Skip to content

Commit 3d3f494

Browse files
committed
Auto merge of #126556 - saethlin:layout-precondition, r=<try>
Add a precondition check for Layout::from_size_align_unchecked Ran into this while looking into rust-lang/miri#3679. This is of course not the cause of the ICE, but the reproducer doesn't encounter a precondition check and it ought to.
2 parents 5aea140 + e6b0f27 commit 3d3f494

File tree

2 files changed

+23
-8
lines changed

2 files changed

+23
-8
lines changed

library/core/src/alloc/layout.rs

+23-6
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
use crate::error::Error;
88
use crate::ptr::{Alignment, NonNull};
9-
use crate::{cmp, fmt, mem};
9+
use crate::{assert_unsafe_precondition, cmp, fmt, mem};
1010

1111
// While this function is used in one place and its implementation
1212
// could be inlined, the previous attempts to do so made rustc
@@ -66,12 +66,20 @@ impl Layout {
6666
#[inline]
6767
#[rustc_allow_const_fn_unstable(ptr_alignment_type)]
6868
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)
7174
}
75+
}
7276

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
7583
}
7684

7785
#[inline(always)]
@@ -116,8 +124,17 @@ impl Layout {
116124
#[inline]
117125
#[rustc_allow_const_fn_unstable(ptr_alignment_type)]
118126
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+
);
119136
// 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) } }
121138
}
122139

123140
/// The minimum size in bytes for a memory block of this layout.

library/core/src/result.rs

-2
Original file line numberDiff line numberDiff line change
@@ -1481,7 +1481,6 @@ impl<T, E> Result<T, E> {
14811481
#[track_caller]
14821482
#[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")]
14831483
pub unsafe fn unwrap_unchecked(self) -> T {
1484-
debug_assert!(self.is_ok());
14851484
match self {
14861485
Ok(t) => t,
14871486
// SAFETY: the safety contract must be upheld by the caller.
@@ -1513,7 +1512,6 @@ impl<T, E> Result<T, E> {
15131512
#[track_caller]
15141513
#[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")]
15151514
pub unsafe fn unwrap_err_unchecked(self) -> E {
1516-
debug_assert!(self.is_err());
15171515
match self {
15181516
// SAFETY: the safety contract must be upheld by the caller.
15191517
Ok(_) => unsafe { hint::unreachable_unchecked() },

0 commit comments

Comments
 (0)