Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes to pass Miri test with the stacked borrows model #46
Changes to pass Miri test with the stacked borrows model #46
Changes from 2 commits
f0f3ed1
254c1ec
15e6659
a1ce91b
80c7823
File filter
Filter by extension
Conversations
Jump to
There are no files selected for viewing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is correct, as it does not initialize elements beyond
self.data.len()
, right? But this is required. Seerealloc
that initializes all those elements toNone
. And the docs on thedata
field say so as well. I supposehas_element_at
was one of the methods relying on this behavior.But I think this implementation relying that elements beyond
vec.len()
can be initialized and stay that way is... dubious? The easy way to do this properly is to actually initialize all elements and have theVec
'slen == cap
at all times. But that wastes ausize
of course and would require us to store a separatelen
field. So I think this implementation should use a pointer and do everything manually likebitvec
. I don't thinkVec
can give us the guarantees that we need. Or, alternatively, we could find all the methods that rely on the current "initialized beyond len" behavior and rewrite them. Hopefully without making them slower.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oof I think many methods rely on the "initialized beyond len". Lots call
self.data.get_unchecked_mut(idx)
whereidx
is only guaranteed to be<= cap
.Vec::get_unchecked_mut
specifically says that calling it with an out of bounds index is immediately UB. So I think this whole implementation is super broken... sighThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, the key point here is this line in the std docs for
Slice::get_unchecked
andSlice::get_uncheckec_mut
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think with the
has_element_at
change that we committed though, we aren't hitting that anymore.because those
get_unchecked_mut
calls seem to be predicated onhas_element_at
, it is very much a can of worms though.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So yes, that means it has to be completely rewritten to either waste a
usize
and keep the vec'slen == cap
or not useVec
at all, but raw pointers. Ouch.I assume you are not volunteering? :D
I don't know when I'll have the time but of course I'd try it asap. I wonder if I should release your other patch already. Or release a new major version where the
OptionCore
is removed until I get time to re-add it. And then of course yank the old ones.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is a bit involved and a diversion for me, I mostly wanted to compare the performance of
Lox
vs a naive doubly linked list approach for cases where we are adding/removing lots of elements like decimation and subdivision.And I was pondering whether modified RRB-vectors could be used in any way that improves the deletion/insertion with the vector stability guarantees but without having to keep the entire vector gaps.
(Not that I have any actual ideas yet that would work, but it is part of the thinking that lead to me playing with these crates)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking through github at least I don't see anywhere that OptionCore/InlineStableVec gets used outside of
this benchmark1, so removing it until it can be re-added does seem like a viable option.
I don't have any particular preferences between that and releasing with my patch, so both seem like viable options to me.
Footnotes
https://github.com/mooman219/generational_arena_bench ↩
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose one other thing we could consider doing rather than abandoning the approach the crate currently takes is to override
clear
tofor item in self.data.iter_mut() { item.take() }
, then replace the uses ofget_unchecked*
with theirvec.ast_ptr().offset(idx)
which has the weaker precondition the current implementation assumes.This would probably require quite a bit of auditing of anything in the implementation that removes elements though so they
take()
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding your initial comment in this thread I did push a fix that initializes the extra capacity with None values, but in a way that doesn't read the extra capacity of the other vector.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So i've gone ahead and come to the conclusion that there were 2 problems,
the failure to maintain the invariant, in
clear
, and theget_unchecked
usage inhas_element_at
.Subsequently, I've changed the
clear
implementation and avoidedget_unchecked
,and now because calls to
get_unchecked*
are predicated on the return value ofhas_element_at
all the current usage I believe should be correct.This should allow keeping the current implementation intact, while removing that bounds check from my previous patch