-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Initialization from zeroed bytes is potentially unsound. #1451
Comments
I think this is incorrect: the value of padding bytes is currently unspecified.
I think this is also incorrect: Rust assumes that any value is a valid value for a padding byte. It does not matter whether you write zero or some other value to them, or whether you write to them at all (e.g. leaving them uninitialized is also ok).
Since padding bytes can take any value, writing zero to them is ok, and the claim that doing so is instant UB is also incorrect.
Since padding bytes can take any value, and zero is a value, the claim that initializing these padding bytes with In fact, the current documentation for
While you are correct here in that initializing these via |
The argument in rust-lang/unsafe-code-guidelines#174 is that there is actually nothing stating that these bytes can take any value. All we got is current rustc behavior, but that's clearly not enough. |
Which is why the first sentence in my comment says that the current behavior is unspecified.
This is not all we got. We do have official documentation everywhere explaining that the following is guaranteed to work on stable Rust: let value: repr_c_type_with_padding = c_ffi_fn(); Since C is allowed to write anything to padding bytes, the padding bytes of |
So your argument is rust-lang/unsafe-code-guidelines#174 does not need an RFC? I totally agree with you that zero-initialization of padding must be allowed, and initializing padding with any bytes (including uninitialized) should be allowed. But is this just an edit to the reference or the nomicon, or is it a new RFC? |
I'd say for at least repr(C) there shouldn't be a need for an RFC, as the guarantees are not for Rust to decide. |
I think this would just be an edit. We do guarantee that: let mut value: repr_c_type_with_padding = c_ffi_fn();
c_ffi_fn2(&mut value); works, we do guarantee that one can pass the reference to C via The UCGs should, at some point, define what this "anything" is. There is a PR open saying that valid values for a byte are all bit-patterns in range 0..256 and a 0xUU bit-pattern, but is this everything that C can write to a byte? On first look, for all platforms that Rust support that don't have trap representations, I think that's enough, but because of FFI we are a bit tied to C here, so we need to make sure that whatever we define that "anything" to be, that it does not break the FFI use cases. |
I'm closing this as mostly invalid and non-actionable. This issue claims that initialization from zeroed bytes is unsound for integers - which is what we use for padding byte fields - but this claim is false. This issue also claims that initialization from zeroed bytes is unsound for padding bytes, but that claims is false, and the claim that This issue claims that Initialization from zeroed bytes is potentially unsound. That claim is true, it is potentially unsound for some types, like |
I've opened #1453 to track that explicit padding fields might invoke undefined behavior when these are returned from C. That issue is barely actionable. |
MaybeUninit::zeroed
andmem::zeroed
are the recommended way to initialize many of the datatypes inlibc
(see: #41 (comment), #55 (comment), #58 (comment), #475 (comment), #1135 (comment), #1395 (comment)).Per rust-lang/unsafe-code-guidelines#174, initialization from zeroed bytes is potentially unsound for structures with padding. The value of padding bytes is expressly undefined. Rust is therefore free to assume that padding bytes have a particular value. If Rust assumes that the padding bytes of a type
T
have, for instance, the particular value of42
,mem::zeroed()
will not produce a valid instance ofT
. This is instant UB.Many (but not all) struct definitions in
libc
encode padding bytes explicitly as private fields. For such types, initialization viamem::zeroed()
is not UB. For the types defined using#[repr(align(N))]
to introduce padding bytes, initialization viamem::zeroed()
flirts with UB. This issue is relevant to #1324, for expanding the use ofalign(N)
.The text was updated successfully, but these errors were encountered: