From e81289445c39f4e6981c89379c03b426de389a57 Mon Sep 17 00:00:00 2001 From: Tom Dohrmann Date: Tue, 3 Sep 2024 04:02:17 -0700 Subject: [PATCH] never construct value on stack in new_box_zeroed (#1601) 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 --- src/lib.rs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 7e38f882eb..d346667348 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2128,7 +2128,27 @@ pub unsafe trait FromZeros: TryFromBytes { // no allocation, but `Box` does require a correct dangling pointer. let layout = Layout::new::(); 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`'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`.