-
Notifications
You must be signed in to change notification settings - Fork 58
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
When does copying an uninitialized byte poison the destination? #301
Comments
(nit: "poison" has a specific meaning in LLVM, so it'd probably be better to avoid that world unless that's meant specifically.) "uninit" is basically another possible value in addition to the "normal" ones. So yes, copying uninit around absolutely copies the uninit-ness -- even writing the uninit to memory and reading it back keeps the uninit-ness. (This is important for optimization. For example, you can only optimize And MIRI says it's currently UB: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=36f80529ae08fa1ae686d891c125f05d
|
The part about this example that's not clear to me is: In a typed pointer write of a I believe internal padding bytes should probably be copied, in order to allow for a memcpy implementation of the write. Trailing padding bytes can possibly avoid being copied, but copying all padding bytes seems to lead to the simplest specification. If stride != size then you also have to worry about stride padding bytes, but I don't know of any plans to change that. |
In the abstract machine, In implementation, the compiler might not write padding bytes, because it would be UB to depend on their value anyway so it's inobservable whether they were written or not. |
Is that documented / guaranteed anywhere? (I agree that, if true, this will resolve the question.) |
For padding it's actually even more interesting: after writing a So for the original question, this becomes UB when you print the
Not that I know of. This is the most conservative model I can imagine and based on what I think C does. |
Hehehe, I think in LLVM terms too much sometimes.
This is what I expect, but ISTR we didn't want padding to get copied when doing typed pointer writes (or any assignment) because that can step on niches. Mind, the abstract machine might not care about niches and all of this is moot, but it would be nice if typed writes of structs with padding didn't have this problem... |
I don't think that is reasonably possible. We have to allow the compiler to turn a typed write into a byte-wise |
It would be possible if padding was always zero, since then |
I am also not entirely sure which guarantees LLVM makes for padding. |
I think this question has a pretty clear answer: after a typed copy, all padding bytes in the destination are The validity invariant for padding imposes no requirements at all, so we also can't rely on it always being 0 or something like that. In other words, even this is UB: #[repr(C)]
struct HasPadding(u8, u16);
assert_eq!(size_of::<HasPadding>(), 4);
let src = 0u32;
let mut dst = 0u32;
let srcptr = addr_of!(src).cast::<HasPadding>();
let dstptr = addr_of_mut!(dst).cast::<HasPadding>();
*dstptr = *srcptr; // copy at type `HasPadding`
assert!(dst == 0); // UB! `dst` has an uninit byte, validity invariant violated In the hope that we have consensus on this question... |
Team member @RalfJung has proposed to close this. The next step is review by the rest of the tagged team members: No concerns currently listed. Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
The final comment period, with a disposition to close, as per the review above, is now complete. As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed. |
I added this to https://github.com/rust-lang/opsem-team/blob/main/fcps.md, the issue can be closed. |
In other words, is this program UB?
If I have initialized memory somewhere, and I do a type-specific copy (not a generic memcpy) of a type with uninitialized bytes (be it padding bytes or a
MayebeUninit<T>
) does the uninitialized-ness get copied too? (The answer need not be the same for each case.)Given that we seem to believe that assigning a struct does not copy padding bits (can't find the issue # for this atm), I feel like this code should not be UB (by way of making one of
bytes
' bytes uninitialized.The text was updated successfully, but these errors were encountered: