Skip to content

Commit

Permalink
never construct value on stack in new_box_zeroed (#1601)
Browse files Browse the repository at this point in the history
On lower opt-levels the compiler might not optimize out the
`layout.size() == 0` branch and emits code for the if-body. This will
cause a stack allocation for `Self`. Avoid calling new_zeroed() and
directly construct the Box from a dangling pointer instead.

Co-authored-by: Joshua Liebow-Feeser <[email protected]>
  • Loading branch information
Freax13 and joshlf authored Sep 3, 2024
1 parent b2615ba commit e812894
Showing 1 changed file with 21 additions and 1 deletion.
22 changes: 21 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2128,7 +2128,27 @@ pub unsafe trait FromZeros: TryFromBytes {
// no allocation, but `Box` does require a correct dangling pointer.
let layout = Layout::new::<Self>();
if layout.size() == 0 {
return Box::new(Self::new_zeroed());
// Construct the `Box` from a dangling pointer to avoid calling
// `Self::new_zeroed`. This ensures that stack space is never
// allocated for `Self` even on lower opt-levels where this branch
// might not get optimized out.

// SAFETY: Per [1], when `T` is a ZST, `Box<T>`'s only validity
// requirements are that the pointer is non-null and sufficiently
// aligned. Per [2], `NonNull::dangling` produces a pointer which
// is sufficiently aligned. Since the produced pointer is a
// `NonNull`, it is non-null.
//
// [1] Per https://doc.rust-lang.org/nightly/std/boxed/index.html#memory-layout:
//
// For zero-sized values, the `Box` pointer has to be non-null and sufficiently aligned.
//
// [2] Per https://doc.rust-lang.org/std/ptr/struct.NonNull.html#method.dangling:
//
// Creates a new `NonNull` that is dangling, but well-aligned.
unsafe {
return Box::from_raw(NonNull::dangling().as_ptr());
}
}

// TODO(#429): Add a "SAFETY" comment and remove this `allow`.
Expand Down

0 comments on commit e812894

Please sign in to comment.