| 
6 | 6 | 
 
  | 
7 | 7 | use crate::error::Error;  | 
8 | 8 | use crate::ptr::{Alignment, NonNull};  | 
9 |  | -use crate::{cmp, fmt, mem};  | 
 | 9 | +use crate::{assert_unsafe_precondition, cmp, fmt, mem};  | 
10 | 10 | 
 
  | 
11 | 11 | // While this function is used in one place and its implementation  | 
12 | 12 | // could be inlined, the previous attempts to do so made rustc  | 
@@ -66,12 +66,20 @@ impl Layout {  | 
66 | 66 |     #[inline]  | 
67 | 67 |     #[rustc_allow_const_fn_unstable(ptr_alignment_type)]  | 
68 | 68 |     pub const fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutError> {  | 
69 |  | -        if !align.is_power_of_two() {  | 
70 |  | -            return Err(LayoutError);  | 
 | 69 | +        if Layout::is_size_align_valid(size, align) {  | 
 | 70 | +            // SAFETY: Layout::is_size_align_valid checks the preconditions for this call.  | 
 | 71 | +            unsafe { Ok(Layout { size, align: mem::transmute(align) }) }  | 
 | 72 | +        } else {  | 
 | 73 | +            Err(LayoutError)  | 
71 | 74 |         }  | 
 | 75 | +    }  | 
72 | 76 | 
 
  | 
73 |  | -        // SAFETY: just checked that align is a power of two.  | 
74 |  | -        Layout::from_size_alignment(size, unsafe { Alignment::new_unchecked(align) })  | 
 | 77 | +    const fn is_size_align_valid(size: usize, align: usize) -> bool {  | 
 | 78 | +        let Some(align) = Alignment::new(align) else { return false };  | 
 | 79 | +        if size > Self::max_size_for_align(align) {  | 
 | 80 | +            return false;  | 
 | 81 | +        }  | 
 | 82 | +        true  | 
75 | 83 |     }  | 
76 | 84 | 
 
  | 
77 | 85 |     #[inline(always)]  | 
@@ -116,8 +124,17 @@ impl Layout {  | 
116 | 124 |     #[inline]  | 
117 | 125 |     #[rustc_allow_const_fn_unstable(ptr_alignment_type)]  | 
118 | 126 |     pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {  | 
 | 127 | +        assert_unsafe_precondition!(  | 
 | 128 | +            check_library_ub,  | 
 | 129 | +            "Layout::from_size_align_unchecked requires that align is a power of 2 \  | 
 | 130 | +            and the rounded-up allocation size does not exceed isize::MAX",  | 
 | 131 | +            (  | 
 | 132 | +                size: usize = size,  | 
 | 133 | +                align: usize = align,  | 
 | 134 | +            ) => Layout::is_size_align_valid(size, align)  | 
 | 135 | +        );  | 
119 | 136 |         // SAFETY: the caller is required to uphold the preconditions.  | 
120 |  | -        unsafe { Layout { size, align: Alignment::new_unchecked(align) } }  | 
 | 137 | +        unsafe { Layout { size, align: mem::transmute(align) } }  | 
121 | 138 |     }  | 
122 | 139 | 
 
  | 
123 | 140 |     /// The minimum size in bytes for a memory block of this layout.  | 
 | 
0 commit comments