Skip to content

Commit 1d78922

Browse files
committed
UB-check for alignment of ptr to Box::from_raw{,_in}
1 parent 28b83ee commit 1d78922

File tree

2 files changed

+33
-5
lines changed

2 files changed

+33
-5
lines changed

library/alloc/src/boxed.rs

+20-5
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@
182182
//! [valid]: ptr#safety
183183
184184
#![stable(feature = "rust1", since = "1.0.0")]
185+
#![feature(ub_checks)]
185186

186187
use core::borrow::{Borrow, BorrowMut};
187188
#[cfg(not(no_global_oom_handling))]
@@ -200,6 +201,7 @@ use core::ops::{
200201
use core::pin::{Pin, PinCoerceUnsized};
201202
use core::ptr::{self, NonNull, Unique};
202203
use core::task::{Context, Poll};
204+
use core::ub_checks::assert_pointer_is_aligned_and_not_null;
203205

204206
#[cfg(not(no_global_oom_handling))]
205207
use crate::alloc::handle_alloc_error;
@@ -1017,7 +1019,7 @@ impl<T: ?Sized> Box<T> {
10171019
/// resulting `Box`. Specifically, the `Box` destructor will call
10181020
/// the destructor of `T` and free the allocated memory. For this
10191021
/// to be safe, the memory must have been allocated in accordance
1020-
/// with the [memory layout] used by `Box` .
1022+
/// with the [memory layout] used by `Box`.
10211023
///
10221024
/// # Safety
10231025
///
@@ -1056,8 +1058,9 @@ impl<T: ?Sized> Box<T> {
10561058
#[stable(feature = "box_raw", since = "1.4.0")]
10571059
#[inline]
10581060
#[must_use = "call `drop(Box::from_raw(ptr))` if you intend to drop the `Box`"]
1059-
pub unsafe fn from_raw(raw: *mut T) -> Self {
1060-
unsafe { Self::from_raw_in(raw, Global) }
1061+
pub unsafe fn from_raw(ptr: *mut T) -> Self {
1062+
assert_pointer_is_aligned_and_not_null!("Box::from_raw", ptr, align_of::<T>(), T::IS_ZST);
1063+
unsafe { Self::from_raw_in(ptr, Global) }
10611064
}
10621065

10631066
/// Constructs a box from a `NonNull` pointer.
@@ -1111,6 +1114,12 @@ impl<T: ?Sized> Box<T> {
11111114
#[inline]
11121115
#[must_use = "call `drop(Box::from_non_null(ptr))` if you intend to drop the `Box`"]
11131116
pub unsafe fn from_non_null(ptr: NonNull<T>) -> Self {
1117+
assert_pointer_is_aligned_and_not_null!(
1118+
"Box::from_non_null",
1119+
ptr,
1120+
align_of::<T>(),
1121+
T::IS_ZST
1122+
);
11141123
unsafe { Self::from_raw(ptr.as_ptr()) }
11151124
}
11161125
}
@@ -1166,8 +1175,14 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
11661175
#[unstable(feature = "allocator_api", issue = "32838")]
11671176
#[rustc_const_unstable(feature = "const_box", issue = "92521")]
11681177
#[inline]
1169-
pub const unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self {
1170-
Box(unsafe { Unique::new_unchecked(raw) }, alloc)
1178+
pub const unsafe fn from_raw_in(ptr: *mut T, alloc: A) -> Self {
1179+
assert_pointer_is_aligned_and_not_null!(
1180+
"Box::from_raw_in",
1181+
ptr,
1182+
align_of::<T>(),
1183+
T::IS_ZST
1184+
);
1185+
Box(unsafe { Unique::new_unchecked(ptr) }, alloc)
11711186
}
11721187

11731188
/// Constructs a box from a `NonNull` pointer in the given allocator.

library/core/src/ub_checks.rs

+13
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,19 @@ pub(crate) const fn maybe_is_aligned_and_not_null(
129129
)
130130
}
131131

132+
/// Specialized version of `assert_unsafe_precondition` for checking that a pointer is properly aligned and not null
133+
#[macro_export]
134+
#[unstable(feature = "ub_checks", issue = "none")]
135+
macro_rules! assert_pointer_is_aligned_and_not_null {
136+
($function_name: literal, $ptr: expr, $align: expr, $is_zst: expr) => {
137+
assert_unsafe_precondition!(
138+
check_language_ub,
139+
concat!($function_name, " requires that its pointer argument is properly aligned and not null"),
140+
() => ub_checks::maybe_is_aligned_and_not_null(ptr as *const (), $align, $is_zst)
141+
);
142+
}
143+
}
144+
132145
#[inline]
133146
pub(crate) const fn is_valid_allocation_size(size: usize, len: usize) -> bool {
134147
let max_len = if size == 0 { usize::MAX } else { isize::MAX as usize / size };

0 commit comments

Comments
 (0)