From 2e0cf69562e8d37dd18cb5401fa0820ab339d835 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Thu, 7 May 2026 22:17:10 -0700 Subject: [PATCH] Avoid a UB check in `Layout::for_value` --- library/core/src/alloc/layout.rs | 16 ++++++----- ...rop_bytes.PreCodegen.after.panic-abort.mir | 28 +++++++++---------- ...op_bytes.PreCodegen.after.panic-unwind.mir | 28 +++++++++---------- ...p_generic.PreCodegen.after.panic-abort.mir | 28 +++++++++---------- ..._generic.PreCodegen.after.panic-unwind.mir | 28 +++++++++---------- ...ace.PreCodegen.after.32bit.panic-abort.mir | 28 +++++++++---------- ...ce.PreCodegen.after.32bit.panic-unwind.mir | 28 +++++++++---------- ...ace.PreCodegen.after.64bit.panic-abort.mir | 28 +++++++++---------- ...ce.PreCodegen.after.64bit.panic-unwind.mir | 28 +++++++++---------- 9 files changed, 113 insertions(+), 127 deletions(-) diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index 66f5310db8310..ba189fa1b577c 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -215,9 +215,8 @@ impl Layout { #[must_use] #[inline] pub const fn for_value(t: &T) -> Self { - let (size, alignment) = (size_of_val(t), Alignment::of_val(t)); - // SAFETY: see rationale in `new` for why this is using the unsafe variant - unsafe { Layout::from_size_alignment_unchecked(size, alignment) } + // SAFETY: Because `t` is a reference, its metadata is valid for this. + unsafe { Layout::for_value_raw(t) } } /// Produces layout describing a record that could be used to @@ -250,11 +249,14 @@ impl Layout { #[unstable(feature = "layout_for_ptr", issue = "69835")] #[must_use] #[inline] - pub const unsafe fn for_value_raw(t: *const T) -> Self { + pub const unsafe fn for_value_raw(ptr: *const T) -> Self { // SAFETY: we pass along the prerequisites of these functions to the caller - let (size, alignment) = unsafe { (mem::size_of_val_raw(t), Alignment::of_val_raw(t)) }; - // SAFETY: see rationale in `new` for why this is using the unsafe variant - unsafe { Layout::from_size_alignment_unchecked(size, alignment) } + let (size, align) = unsafe { (mem::size_of_val_raw(ptr), Alignment::of_val_raw(ptr)) }; + // SAFETY: the dynamic size is that of a valid rust type, and those always + // meet the rules of `Layout` (just like in `Layout::new`). + // NB: We use a struct literal, instead of the unsafe constructor, + // to avoid the unnecessary UB check that has compile-time impact. + Layout { size, align } } /// Creates a `NonNull` that is dangling, but well-aligned for this Layout. diff --git a/tests/mir-opt/pre-codegen/drop_box_of_sized.drop_bytes.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/drop_box_of_sized.drop_bytes.PreCodegen.after.panic-abort.mir index 9275643001501..aefc002158966 100644 --- a/tests/mir-opt/pre-codegen/drop_box_of_sized.drop_bytes.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/drop_box_of_sized.drop_bytes.PreCodegen.after.panic-abort.mir @@ -10,28 +10,28 @@ fn drop_bytes(_1: *mut Box<[u8; 1024]>) -> () { let _4: (); scope 4 { scope 5 { - scope 18 (inlined Layout::size) { + scope 17 (inlined Layout::size) { } - scope 19 (inlined std::ptr::Unique::<[u8; 1024]>::cast::) { + scope 18 (inlined std::ptr::Unique::<[u8; 1024]>::cast::) { let mut _3: std::ptr::NonNull; - scope 20 (inlined NonNull::<[u8; 1024]>::cast::) { - scope 21 (inlined NonNull::<[u8; 1024]>::as_ptr) { + scope 19 (inlined NonNull::<[u8; 1024]>::cast::) { + scope 20 (inlined NonNull::<[u8; 1024]>::as_ptr) { } } } - scope 22 (inlined as From>>::from) { - scope 23 (inlined std::ptr::Unique::::as_non_null_ptr) { + scope 21 (inlined as From>>::from) { + scope 22 (inlined std::ptr::Unique::::as_non_null_ptr) { } } - scope 24 (inlined ::deallocate) { - scope 25 (inlined std::alloc::Global::deallocate_impl) { - scope 26 (inlined std::alloc::Global::deallocate_impl_runtime) { - scope 27 (inlined Layout::size) { + scope 23 (inlined ::deallocate) { + scope 24 (inlined std::alloc::Global::deallocate_impl) { + scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) { + scope 26 (inlined Layout::size) { } - scope 28 (inlined alloc::alloc::dealloc_nonnull) { - scope 29 (inlined Layout::size) { + scope 27 (inlined alloc::alloc::dealloc_nonnull) { + scope 28 (inlined Layout::size) { } - scope 30 (inlined Layout::alignment) { + scope 29 (inlined Layout::alignment) { } } } @@ -44,8 +44,6 @@ fn drop_bytes(_1: *mut Box<[u8; 1024]>) -> () { } scope 8 (inlined Layout::for_value_raw::<[u8; 1024]>) { scope 9 { - scope 17 (inlined #[track_caller] Layout::from_size_alignment_unchecked) { - } } scope 10 (inlined size_of_val_raw::<[u8; 1024]>) { } diff --git a/tests/mir-opt/pre-codegen/drop_box_of_sized.drop_bytes.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/drop_box_of_sized.drop_bytes.PreCodegen.after.panic-unwind.mir index 9275643001501..aefc002158966 100644 --- a/tests/mir-opt/pre-codegen/drop_box_of_sized.drop_bytes.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/drop_box_of_sized.drop_bytes.PreCodegen.after.panic-unwind.mir @@ -10,28 +10,28 @@ fn drop_bytes(_1: *mut Box<[u8; 1024]>) -> () { let _4: (); scope 4 { scope 5 { - scope 18 (inlined Layout::size) { + scope 17 (inlined Layout::size) { } - scope 19 (inlined std::ptr::Unique::<[u8; 1024]>::cast::) { + scope 18 (inlined std::ptr::Unique::<[u8; 1024]>::cast::) { let mut _3: std::ptr::NonNull; - scope 20 (inlined NonNull::<[u8; 1024]>::cast::) { - scope 21 (inlined NonNull::<[u8; 1024]>::as_ptr) { + scope 19 (inlined NonNull::<[u8; 1024]>::cast::) { + scope 20 (inlined NonNull::<[u8; 1024]>::as_ptr) { } } } - scope 22 (inlined as From>>::from) { - scope 23 (inlined std::ptr::Unique::::as_non_null_ptr) { + scope 21 (inlined as From>>::from) { + scope 22 (inlined std::ptr::Unique::::as_non_null_ptr) { } } - scope 24 (inlined ::deallocate) { - scope 25 (inlined std::alloc::Global::deallocate_impl) { - scope 26 (inlined std::alloc::Global::deallocate_impl_runtime) { - scope 27 (inlined Layout::size) { + scope 23 (inlined ::deallocate) { + scope 24 (inlined std::alloc::Global::deallocate_impl) { + scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) { + scope 26 (inlined Layout::size) { } - scope 28 (inlined alloc::alloc::dealloc_nonnull) { - scope 29 (inlined Layout::size) { + scope 27 (inlined alloc::alloc::dealloc_nonnull) { + scope 28 (inlined Layout::size) { } - scope 30 (inlined Layout::alignment) { + scope 29 (inlined Layout::alignment) { } } } @@ -44,8 +44,6 @@ fn drop_bytes(_1: *mut Box<[u8; 1024]>) -> () { } scope 8 (inlined Layout::for_value_raw::<[u8; 1024]>) { scope 9 { - scope 17 (inlined #[track_caller] Layout::from_size_alignment_unchecked) { - } } scope 10 (inlined size_of_val_raw::<[u8; 1024]>) { } diff --git a/tests/mir-opt/pre-codegen/drop_box_of_sized.drop_generic.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/drop_box_of_sized.drop_generic.PreCodegen.after.panic-abort.mir index 27f6d77305ca6..bd391cd7184cc 100644 --- a/tests/mir-opt/pre-codegen/drop_box_of_sized.drop_generic.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/drop_box_of_sized.drop_generic.PreCodegen.after.panic-abort.mir @@ -10,28 +10,28 @@ fn drop_generic(_1: *mut Box) -> () { let _5: (); scope 4 { scope 5 { - scope 18 (inlined Layout::size) { + scope 17 (inlined Layout::size) { } - scope 19 (inlined std::ptr::Unique::::cast::) { + scope 18 (inlined std::ptr::Unique::::cast::) { let mut _4: std::ptr::NonNull; - scope 20 (inlined NonNull::::cast::) { - scope 21 (inlined NonNull::::as_ptr) { + scope 19 (inlined NonNull::::cast::) { + scope 20 (inlined NonNull::::as_ptr) { } } } - scope 22 (inlined as From>>::from) { - scope 23 (inlined std::ptr::Unique::::as_non_null_ptr) { + scope 21 (inlined as From>>::from) { + scope 22 (inlined std::ptr::Unique::::as_non_null_ptr) { } } - scope 24 (inlined ::deallocate) { - scope 25 (inlined std::alloc::Global::deallocate_impl) { - scope 26 (inlined std::alloc::Global::deallocate_impl_runtime) { - scope 27 (inlined Layout::size) { + scope 23 (inlined ::deallocate) { + scope 24 (inlined std::alloc::Global::deallocate_impl) { + scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) { + scope 26 (inlined Layout::size) { } - scope 28 (inlined alloc::alloc::dealloc_nonnull) { - scope 29 (inlined Layout::size) { + scope 27 (inlined alloc::alloc::dealloc_nonnull) { + scope 28 (inlined Layout::size) { } - scope 30 (inlined Layout::alignment) { + scope 29 (inlined Layout::alignment) { } } } @@ -45,8 +45,6 @@ fn drop_generic(_1: *mut Box) -> () { scope 8 (inlined Layout::for_value_raw::) { let mut _3: std::mem::Alignment; scope 9 { - scope 17 (inlined #[track_caller] Layout::from_size_alignment_unchecked) { - } } scope 10 (inlined size_of_val_raw::) { } diff --git a/tests/mir-opt/pre-codegen/drop_box_of_sized.drop_generic.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/drop_box_of_sized.drop_generic.PreCodegen.after.panic-unwind.mir index 27f6d77305ca6..bd391cd7184cc 100644 --- a/tests/mir-opt/pre-codegen/drop_box_of_sized.drop_generic.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/drop_box_of_sized.drop_generic.PreCodegen.after.panic-unwind.mir @@ -10,28 +10,28 @@ fn drop_generic(_1: *mut Box) -> () { let _5: (); scope 4 { scope 5 { - scope 18 (inlined Layout::size) { + scope 17 (inlined Layout::size) { } - scope 19 (inlined std::ptr::Unique::::cast::) { + scope 18 (inlined std::ptr::Unique::::cast::) { let mut _4: std::ptr::NonNull; - scope 20 (inlined NonNull::::cast::) { - scope 21 (inlined NonNull::::as_ptr) { + scope 19 (inlined NonNull::::cast::) { + scope 20 (inlined NonNull::::as_ptr) { } } } - scope 22 (inlined as From>>::from) { - scope 23 (inlined std::ptr::Unique::::as_non_null_ptr) { + scope 21 (inlined as From>>::from) { + scope 22 (inlined std::ptr::Unique::::as_non_null_ptr) { } } - scope 24 (inlined ::deallocate) { - scope 25 (inlined std::alloc::Global::deallocate_impl) { - scope 26 (inlined std::alloc::Global::deallocate_impl_runtime) { - scope 27 (inlined Layout::size) { + scope 23 (inlined ::deallocate) { + scope 24 (inlined std::alloc::Global::deallocate_impl) { + scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) { + scope 26 (inlined Layout::size) { } - scope 28 (inlined alloc::alloc::dealloc_nonnull) { - scope 29 (inlined Layout::size) { + scope 27 (inlined alloc::alloc::dealloc_nonnull) { + scope 28 (inlined Layout::size) { } - scope 30 (inlined Layout::alignment) { + scope 29 (inlined Layout::alignment) { } } } @@ -45,8 +45,6 @@ fn drop_generic(_1: *mut Box) -> () { scope 8 (inlined Layout::for_value_raw::) { let mut _3: std::mem::Alignment; scope 9 { - scope 17 (inlined #[track_caller] Layout::from_size_alignment_unchecked) { - } } scope 10 (inlined size_of_val_raw::) { } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir index 004fd74da1442..47694779a2d9c 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-abort.mir @@ -12,29 +12,29 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { let _9: (); scope 4 { scope 5 { - scope 18 (inlined Layout::size) { + scope 17 (inlined Layout::size) { } - scope 19 (inlined std::ptr::Unique::<[T]>::cast::) { + scope 18 (inlined std::ptr::Unique::<[T]>::cast::) { let mut _8: std::ptr::NonNull; - scope 20 (inlined NonNull::<[T]>::cast::) { + scope 19 (inlined NonNull::<[T]>::cast::) { let mut _7: *mut u8; - scope 21 (inlined NonNull::<[T]>::as_ptr) { + scope 20 (inlined NonNull::<[T]>::as_ptr) { } } } - scope 22 (inlined as From>>::from) { - scope 23 (inlined std::ptr::Unique::::as_non_null_ptr) { + scope 21 (inlined as From>>::from) { + scope 22 (inlined std::ptr::Unique::::as_non_null_ptr) { } } - scope 24 (inlined ::deallocate) { - scope 25 (inlined std::alloc::Global::deallocate_impl) { - scope 26 (inlined std::alloc::Global::deallocate_impl_runtime) { - scope 27 (inlined Layout::size) { + scope 23 (inlined ::deallocate) { + scope 24 (inlined std::alloc::Global::deallocate_impl) { + scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) { + scope 26 (inlined Layout::size) { } - scope 28 (inlined alloc::alloc::dealloc_nonnull) { - scope 29 (inlined Layout::size) { + scope 27 (inlined alloc::alloc::dealloc_nonnull) { + scope 28 (inlined Layout::size) { } - scope 30 (inlined Layout::alignment) { + scope 29 (inlined Layout::alignment) { } } } @@ -49,8 +49,6 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { let mut _5: usize; let mut _6: std::mem::Alignment; scope 9 { - scope 17 (inlined #[track_caller] Layout::from_size_alignment_unchecked) { - } } scope 10 (inlined size_of_val_raw::<[T]>) { } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir index 004fd74da1442..47694779a2d9c 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.32bit.panic-unwind.mir @@ -12,29 +12,29 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { let _9: (); scope 4 { scope 5 { - scope 18 (inlined Layout::size) { + scope 17 (inlined Layout::size) { } - scope 19 (inlined std::ptr::Unique::<[T]>::cast::) { + scope 18 (inlined std::ptr::Unique::<[T]>::cast::) { let mut _8: std::ptr::NonNull; - scope 20 (inlined NonNull::<[T]>::cast::) { + scope 19 (inlined NonNull::<[T]>::cast::) { let mut _7: *mut u8; - scope 21 (inlined NonNull::<[T]>::as_ptr) { + scope 20 (inlined NonNull::<[T]>::as_ptr) { } } } - scope 22 (inlined as From>>::from) { - scope 23 (inlined std::ptr::Unique::::as_non_null_ptr) { + scope 21 (inlined as From>>::from) { + scope 22 (inlined std::ptr::Unique::::as_non_null_ptr) { } } - scope 24 (inlined ::deallocate) { - scope 25 (inlined std::alloc::Global::deallocate_impl) { - scope 26 (inlined std::alloc::Global::deallocate_impl_runtime) { - scope 27 (inlined Layout::size) { + scope 23 (inlined ::deallocate) { + scope 24 (inlined std::alloc::Global::deallocate_impl) { + scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) { + scope 26 (inlined Layout::size) { } - scope 28 (inlined alloc::alloc::dealloc_nonnull) { - scope 29 (inlined Layout::size) { + scope 27 (inlined alloc::alloc::dealloc_nonnull) { + scope 28 (inlined Layout::size) { } - scope 30 (inlined Layout::alignment) { + scope 29 (inlined Layout::alignment) { } } } @@ -49,8 +49,6 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { let mut _5: usize; let mut _6: std::mem::Alignment; scope 9 { - scope 17 (inlined #[track_caller] Layout::from_size_alignment_unchecked) { - } } scope 10 (inlined size_of_val_raw::<[T]>) { } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir index 004fd74da1442..47694779a2d9c 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-abort.mir @@ -12,29 +12,29 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { let _9: (); scope 4 { scope 5 { - scope 18 (inlined Layout::size) { + scope 17 (inlined Layout::size) { } - scope 19 (inlined std::ptr::Unique::<[T]>::cast::) { + scope 18 (inlined std::ptr::Unique::<[T]>::cast::) { let mut _8: std::ptr::NonNull; - scope 20 (inlined NonNull::<[T]>::cast::) { + scope 19 (inlined NonNull::<[T]>::cast::) { let mut _7: *mut u8; - scope 21 (inlined NonNull::<[T]>::as_ptr) { + scope 20 (inlined NonNull::<[T]>::as_ptr) { } } } - scope 22 (inlined as From>>::from) { - scope 23 (inlined std::ptr::Unique::::as_non_null_ptr) { + scope 21 (inlined as From>>::from) { + scope 22 (inlined std::ptr::Unique::::as_non_null_ptr) { } } - scope 24 (inlined ::deallocate) { - scope 25 (inlined std::alloc::Global::deallocate_impl) { - scope 26 (inlined std::alloc::Global::deallocate_impl_runtime) { - scope 27 (inlined Layout::size) { + scope 23 (inlined ::deallocate) { + scope 24 (inlined std::alloc::Global::deallocate_impl) { + scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) { + scope 26 (inlined Layout::size) { } - scope 28 (inlined alloc::alloc::dealloc_nonnull) { - scope 29 (inlined Layout::size) { + scope 27 (inlined alloc::alloc::dealloc_nonnull) { + scope 28 (inlined Layout::size) { } - scope 30 (inlined Layout::alignment) { + scope 29 (inlined Layout::alignment) { } } } @@ -49,8 +49,6 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { let mut _5: usize; let mut _6: std::mem::Alignment; scope 9 { - scope 17 (inlined #[track_caller] Layout::from_size_alignment_unchecked) { - } } scope 10 (inlined size_of_val_raw::<[T]>) { } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir index 004fd74da1442..47694779a2d9c 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.64bit.panic-unwind.mir @@ -12,29 +12,29 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { let _9: (); scope 4 { scope 5 { - scope 18 (inlined Layout::size) { + scope 17 (inlined Layout::size) { } - scope 19 (inlined std::ptr::Unique::<[T]>::cast::) { + scope 18 (inlined std::ptr::Unique::<[T]>::cast::) { let mut _8: std::ptr::NonNull; - scope 20 (inlined NonNull::<[T]>::cast::) { + scope 19 (inlined NonNull::<[T]>::cast::) { let mut _7: *mut u8; - scope 21 (inlined NonNull::<[T]>::as_ptr) { + scope 20 (inlined NonNull::<[T]>::as_ptr) { } } } - scope 22 (inlined as From>>::from) { - scope 23 (inlined std::ptr::Unique::::as_non_null_ptr) { + scope 21 (inlined as From>>::from) { + scope 22 (inlined std::ptr::Unique::::as_non_null_ptr) { } } - scope 24 (inlined ::deallocate) { - scope 25 (inlined std::alloc::Global::deallocate_impl) { - scope 26 (inlined std::alloc::Global::deallocate_impl_runtime) { - scope 27 (inlined Layout::size) { + scope 23 (inlined ::deallocate) { + scope 24 (inlined std::alloc::Global::deallocate_impl) { + scope 25 (inlined std::alloc::Global::deallocate_impl_runtime) { + scope 26 (inlined Layout::size) { } - scope 28 (inlined alloc::alloc::dealloc_nonnull) { - scope 29 (inlined Layout::size) { + scope 27 (inlined alloc::alloc::dealloc_nonnull) { + scope 28 (inlined Layout::size) { } - scope 30 (inlined Layout::alignment) { + scope 29 (inlined Layout::alignment) { } } } @@ -49,8 +49,6 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { let mut _5: usize; let mut _6: std::mem::Alignment; scope 9 { - scope 17 (inlined #[track_caller] Layout::from_size_alignment_unchecked) { - } } scope 10 (inlined size_of_val_raw::<[T]>) { }