about summary refs log tree commit diff
path: root/library/core/src/alloc/layout.rs
diff options
context:
space:
mode:
authorBen Kimock <kimockb@gmail.com>2024-06-16 12:58:08 -0400
committerBen Kimock <kimockb@gmail.com>2024-08-19 17:18:17 -0400
commit7f5d282185674cac26f9f916f0f1ae8ec04e3482 (patch)
treec5159f479afccf65e15fcd3f62a3a147bb182d51 /library/core/src/alloc/layout.rs
parent27b93da8de2477b3a41811b0ee486cffa99fa00e (diff)
downloadrust-7f5d282185674cac26f9f916f0f1ae8ec04e3482.tar.gz
rust-7f5d282185674cac26f9f916f0f1ae8ec04e3482.zip
Add a precondition check for Layout::from_size_align_unchecked
Diffstat (limited to 'library/core/src/alloc/layout.rs')
-rw-r--r--library/core/src/alloc/layout.rs32
1 files changed, 27 insertions, 5 deletions
diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs
index 549a4bc6727..c2521ffe9cc 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,25 @@ 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.
+            let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
+            Ok(layout)
+        } 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 {
+        if !align.is_power_of_two() {
+            return false;
+        }
+        // SAFETY: Precondition checked directly above.
+        let align = unsafe { Alignment::new_unchecked(align) };
+        if size > Self::max_size_for_align(align) {
+            return false;
+        }
+        true
     }
 
     #[inline(always)]
@@ -116,6 +129,15 @@ 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) } }
     }