|
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,25 @@ 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 | + let layout = unsafe { Layout::from_size_align_unchecked(size, align) }; |
| 72 | + Ok(layout) |
| 73 | + } else { |
| 74 | + Err(LayoutError) |
71 | 75 | }
|
| 76 | + } |
72 | 77 |
|
73 |
| - // SAFETY: just checked that align is a power of two. |
74 |
| - Layout::from_size_alignment(size, unsafe { Alignment::new_unchecked(align) }) |
| 78 | + const fn is_size_align_valid(size: usize, align: usize) -> bool { |
| 79 | + if !align.is_power_of_two() { |
| 80 | + return false; |
| 81 | + } |
| 82 | + // SAFETY: Precondition checked directly above. |
| 83 | + let align = unsafe { Alignment::new_unchecked(align) }; |
| 84 | + if size > Self::max_size_for_align(align) { |
| 85 | + return false; |
| 86 | + } |
| 87 | + true |
75 | 88 | }
|
76 | 89 |
|
77 | 90 | #[inline(always)]
|
@@ -116,6 +129,15 @@ impl Layout {
|
116 | 129 | #[inline]
|
117 | 130 | #[rustc_allow_const_fn_unstable(ptr_alignment_type)]
|
118 | 131 | pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
|
| 132 | + assert_unsafe_precondition!( |
| 133 | + check_library_ub, |
| 134 | + "Layout::from_size_align_unchecked requires that align is a power of 2 \ |
| 135 | + and the rounded-up allocation size does not exceed isize::MAX", |
| 136 | + ( |
| 137 | + size: usize = size, |
| 138 | + align: usize = align, |
| 139 | + ) => Layout::is_size_align_valid(size, align) |
| 140 | + ); |
119 | 141 | // SAFETY: the caller is required to uphold the preconditions.
|
120 | 142 | unsafe { Layout { size, align: Alignment::new_unchecked(align) } }
|
121 | 143 | }
|
|
0 commit comments