-
Notifications
You must be signed in to change notification settings - Fork 59
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
Aliasing rules for Vec<T>
and other standard containers
#262
Comments
Well... quoting from the docs:
So, only the order is unstable.
Is the slice length here Regarding your higher-level point, I don't have an answer, but I can try to tease this apart into two questions:
One data point: for |
I'd argue that isn't a stable guarantee, especially since an interpretation that it is wouldn't necessarily be compatible with the efforts in https://github.com/rust-lang/wg-allocators. This information has to be stored somewhere, and, at least for
Either one is reasonable. I actually originally had the question be As for how the aliasing rules work, I'm not worried about the concreate rules for the implementation. lccc defines
These are notably derivative pointers of the interior, by definition. The definition I use notably permits as many derivative pointers as it wants (provided either only 1 exists, or none have the
This was a sort-of catch all question, and can certainly be analyzed individually, for each such container. In particular, this is desirable from the implementation-side for |
I wouldn't say it's incompatible; the quoted stability guarantee is only for the |
Things like that, stated in the doc, as as close to a stable guarantee as we have for libraries. If this isn't a stable guarantee, I don't know what is. |
My question is be, what is that stable guarantee. What does the fact that a type consists of only one pointer and two usizes, but is |
I've seen old unsafe code that relied on Vec being "3x usize", on the grounds that the docs say it's a stable part of the type. |
I did say that the guarantee is that decomposing into the raw parts and assembling it back again will always give exactly the original value back. It doesn't have any private fields that would get lost in the translation. Nor does it have any extra validity invariants, only extra safety invariants. |
That's what I thought, and originally mentioned in my comment on that ("this information has to be stored somewhere, and, at least for |
I largely agree with your post, but I'm not certain about this one. It already has a non-null validity invariant in the current implementation, which is tighter validity than the To me, this statement in the documentation is about saying "no, it's not reference counted" and "no, it's not a |
Historically, we treat these kinds of comments in documentation as guarantees, and I've taken pains to get the libs team to sign off on them. |
FWIW
Never says that length/capacity have to be usize and have to be valid for all values, so I do think it should be allowed in the future to constrain them for |
I'd like to bring this up again and ask a further question (one that also applies to
|
The type system has to ensure this restriction for soundness reasons. However, Stacked Borrows doesn't do anything like that. It work strictly per-pointer / per-allocation, and in particular "the pointer used to load X" has no effect on the 'content' of X even if X is itself a pointer.
To make sure I understand the question -- that would rule out code like this, right? Currently, it is my interpretation of the documentation of I think this has to necessarily imply "no" to both of your questions, or am I misunderstanding something? |
added a strings.rs regression test case for potential future UB This PR adds a regression test for the aliasing rules of a `Unique<T>` pointer. At the time of writing this test case, Miri does not treat `Unique<T>` pointers as a special case, these are treated like any other raw pointer. However, there are existing Github issues which may lead to `Unique<T>` becoming a special case through asserting unique ownership over the pointee: - rust-lang/unsafe-code-guidelines#258 - rust-lang/unsafe-code-guidelines#262 In the new test case, the calls to `String::remove` and `String::insert[_str]` follow code paths that would trigger undefined behavior in case `Unique<T>` would ever assert semantic ownership over the pointee. Internally, these methods call `self.vec.as_ptr()` and `self.vec.as_mut_ptr()` on the vector of bytes that are backing the `String`. That `Vec<u8>` holds a `Unique<u8>` internally. The second call to `Vec::as_mut_ptr(&mut self)` would then invalidate the pointers derived from `Vec::as_ptr(&self)`. Note that as long as `Unique<T>` is treated like any other raw pointer, this test case should pass. It is merely here as a canary test for potential future undefined behavior.
Closing in favor of #326. |
This was brought up briefly in #258, but I was wondering about the aliasing rules for Standard Containers, partricularily
Vec<T,A>
.Right now, a safety invariant for
Vec
is that the inner pointer is not aliased (this is necessary, becauseVec
can modify it, and implementsDerefMut
). However, as was noted, making this an aliasing invariant may be non-trivial. However, notably,Vec<T,A>
has an unstable layout, so an implementation could be(Unique<[T]>,usize,A)
. My question is, would this be a valid implementation? Would an implementation be permitted to treatVec<T>
specially w.r.t. the stacked borrows aliasing model?(Note: all of the above explicitly references
Vec<T,A>
but the question also stands without loss of generality, to all standard library containers. IE. can an implementation assume exclusive ownership of the pointers managed by standard containers, however that may extend, even if the container is unused andmem::forgotten
.)The text was updated successfully, but these errors were encountered: