about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-08-21 12:50:05 +0000
committerbors <bors@rust-lang.org>2024-08-21 12:50:05 +0000
commit982c6f8721416431ec62bb0b9105c0578a9fc603 (patch)
treeef4a6b042b49bc1730b0639fe32ab76ba3f5338a
parent59a74db37df8628f778faf75faa41958bb07a42a (diff)
parente6b0f27e00c0a6e0bb137bab837fbd5e9d2b7629 (diff)
downloadrust-982c6f8721416431ec62bb0b9105c0578a9fc603.tar.gz
rust-982c6f8721416431ec62bb0b9105c0578a9fc603.zip
Auto merge of #126556 - saethlin:layout-precondition, r=joboet
Add a precondition check for Layout::from_size_align_unchecked

Ran into this while looking into https://github.com/rust-lang/miri/issues/3679. This is of course not the cause of the ICE, but the reproducer doesn't encounter a precondition check and it ought to.
-rw-r--r--library/core/src/alloc/layout.rs29
-rw-r--r--library/core/src/result.rs2
2 files changed, 23 insertions, 8 deletions
diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs
index 549a4bc6727..ad3f9d80878 100644
--- a/library/core/src/alloc/layout.rs
+++ b/library/core/src/alloc/layout.rs
@@ -6,7 +6,7 @@
 
 use crate::error::Error;
 use crate::ptr::{Alignment, NonNull};
-use crate::{cmp, fmt, mem};
+use crate::{assert_unsafe_precondition, cmp, fmt, mem};
 
 // While this function is used in one place and its implementation
 // could be inlined, the previous attempts to do so made rustc
@@ -66,12 +66,20 @@ impl Layout {
     #[inline]
     #[rustc_allow_const_fn_unstable(ptr_alignment_type)]
     pub const fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutError> {
-        if !align.is_power_of_two() {
-            return Err(LayoutError);
+        if Layout::is_size_align_valid(size, align) {
+            // SAFETY: Layout::is_size_align_valid checks the preconditions for this call.
+            unsafe { Ok(Layout { size, align: mem::transmute(align) }) }
+        } else {
+            Err(LayoutError)
         }
+    }
 
-        // SAFETY: just checked that align is a power of two.
-        Layout::from_size_alignment(size, unsafe { Alignment::new_unchecked(align) })
+    const fn is_size_align_valid(size: usize, align: usize) -> bool {
+        let Some(align) = Alignment::new(align) else { return false };
+        if size > Self::max_size_for_align(align) {
+            return false;
+        }
+        true
     }
 
     #[inline(always)]
@@ -116,8 +124,17 @@ impl Layout {
     #[inline]
     #[rustc_allow_const_fn_unstable(ptr_alignment_type)]
     pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
+        assert_unsafe_precondition!(
+            check_library_ub,
+            "Layout::from_size_align_unchecked requires that align is a power of 2 \
+            and the rounded-up allocation size does not exceed isize::MAX",
+            (
+                size: usize = size,
+                align: usize = align,
+            ) => Layout::is_size_align_valid(size, align)
+        );
         // SAFETY: the caller is required to uphold the preconditions.
-        unsafe { Layout { size, align: Alignment::new_unchecked(align) } }
+        unsafe { Layout { size, align: mem::transmute(align) } }
     }
 
     /// The minimum size in bytes for a memory block of this layout.
diff --git a/library/core/src/result.rs b/library/core/src/result.rs
index 7f278296b7b..73b11f803d9 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -1481,7 +1481,6 @@ impl<T, E> Result<T, E> {
     #[track_caller]
     #[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")]
     pub unsafe fn unwrap_unchecked(self) -> T {
-        debug_assert!(self.is_ok());
         match self {
             Ok(t) => t,
             // SAFETY: the safety contract must be upheld by the caller.
@@ -1513,7 +1512,6 @@ impl<T, E> Result<T, E> {
     #[track_caller]
     #[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")]
     pub unsafe fn unwrap_err_unchecked(self) -> E {
-        debug_assert!(self.is_err());
         match self {
             // SAFETY: the safety contract must be upheld by the caller.
             Ok(_) => unsafe { hint::unreachable_unchecked() },