From a9b600eb30b857c27f86abffe2599acb7f306c78 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 a4ae36bf85..e36862e9a6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1499,7 +1499,27 @@ pub unsafe trait FromZeroes { // 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`.