Skip to content

Commit

Permalink
Auto merge of rust-lang#126556 - saethlin:layout-precondition, r=joboet
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bors committed Aug 21, 2024
2 parents 9e9141f + b507a8b commit 7f8bdd5
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 8 deletions.
29 changes: 23 additions & 6 deletions core/src/alloc/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)]
Expand Down Expand Up @@ -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.
Expand Down
2 changes: 0 additions & 2 deletions core/src/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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() },
Expand Down

0 comments on commit 7f8bdd5

Please sign in to comment.