Skip to content

Commit 1f73d52

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

File tree

5 files changed

+51
-8
lines changed

5 files changed

+51
-8
lines changed

library/alloc/src/boxed.rs

+34-5
Original file line numberDiff line numberDiff line change
@@ -1017,7 +1017,7 @@ impl<T: ?Sized> Box<T> {
10171017
/// resulting `Box`. Specifically, the `Box` destructor will call
10181018
/// the destructor of `T` and free the allocated memory. For this
10191019
/// to be safe, the memory must have been allocated in accordance
1020-
/// with the [memory layout] used by `Box` .
1020+
/// with the [memory layout] used by `Box`.
10211021
///
10221022
/// # Safety
10231023
///
@@ -1056,8 +1056,25 @@ impl<T: ?Sized> Box<T> {
10561056
#[stable(feature = "box_raw", since = "1.4.0")]
10571057
#[inline]
10581058
#[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) }
1059+
pub unsafe fn from_raw(ptr: *mut T) -> Self {
1060+
core::assert_unsafe_precondition!(
1061+
check_language_ub,
1062+
"Box::from_raw requires that its pointer argument is properly aligned and not null",
1063+
(
1064+
ptr: *const () = ptr as *const (),
1065+
align: usize = align_of::<T>(),
1066+
) => const_eval_select!(
1067+
@capture { ptr: *const (), align: usize } -> bool:
1068+
if const {
1069+
!ptr.is_null()
1070+
} else {
1071+
ptr.is_aligned_to(align) && !ptr.is_null()
1072+
}
1073+
)
1074+
);
1075+
1076+
//assert_pointer_is_aligned_and_not_null!("Box::from_raw", ptr, align_of::<T>(), T::IS_ZST);
1077+
unsafe { Self::from_raw_in(ptr, Global) }
10611078
}
10621079

10631080
/// Constructs a box from a `NonNull` pointer.
@@ -1111,6 +1128,12 @@ impl<T: ?Sized> Box<T> {
11111128
#[inline]
11121129
#[must_use = "call `drop(Box::from_non_null(ptr))` if you intend to drop the `Box`"]
11131130
pub unsafe fn from_non_null(ptr: NonNull<T>) -> Self {
1131+
/*assert_pointer_is_aligned_and_not_null!(
1132+
"Box::from_non_null",
1133+
ptr,
1134+
align_of::<T>(),
1135+
T::IS_ZST
1136+
);*/
11141137
unsafe { Self::from_raw(ptr.as_ptr()) }
11151138
}
11161139
}
@@ -1166,8 +1189,14 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
11661189
#[unstable(feature = "allocator_api", issue = "32838")]
11671190
#[rustc_const_unstable(feature = "const_box", issue = "92521")]
11681191
#[inline]
1169-
pub const unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self {
1170-
Box(unsafe { Unique::new_unchecked(raw) }, alloc)
1192+
pub const unsafe fn from_raw_in(ptr: *mut T, alloc: A) -> Self {
1193+
/*assert_pointer_is_aligned_and_not_null!(
1194+
"Box::from_raw_in",
1195+
ptr,
1196+
align_of::<T>(),
1197+
T::IS_ZST
1198+
);*/
1199+
Box(unsafe { Unique::new_unchecked(ptr) }, alloc)
11711200
}
11721201

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

library/alloc/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@
154154
#![feature(try_trait_v2)]
155155
#![feature(try_with_capacity)]
156156
#![feature(tuple_trait)]
157+
#![feature(ub_checks)]
157158
#![feature(unicode_internals)]
158159
#![feature(unsize)]
159160
#![feature(unwrap_infallible)]

library/core/src/intrinsics/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4169,7 +4169,7 @@ pub const fn size_of<T>() -> usize {
41694169
#[rustc_intrinsic_const_stable_indirect]
41704170
#[rustc_intrinsic]
41714171
#[rustc_intrinsic_must_be_overridden]
4172-
pub const fn min_align_of<T>() -> usize {
4172+
pub const fn min_align_of<T: ?Sized>() -> usize {
41734173
unreachable!()
41744174
}
41754175

library/core/src/mem/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
463463
#[stable(feature = "rust1", since = "1.0.0")]
464464
#[rustc_promotable]
465465
#[rustc_const_stable(feature = "const_align_of", since = "1.24.0")]
466-
pub const fn align_of<T>() -> usize {
466+
pub const fn align_of<T: ?Sized>() -> usize {
467467
intrinsics::min_align_of::<T>()
468468
}
469469

library/core/src/ub_checks.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ pub use intrinsics::ub_checks as check_library_ub;
9090
/// language UB checks which generally produce better errors.
9191
#[inline]
9292
#[rustc_allow_const_fn_unstable(const_eval_select)]
93-
pub(crate) const fn check_language_ub() -> bool {
93+
pub const fn check_language_ub() -> bool {
9494
// Only used for UB checks so we may const_eval_select.
9595
intrinsics::ub_checks()
9696
&& const_eval_select!(
@@ -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+
::core::assert_unsafe_precondition!(
138+
check_language_ub,
139+
concat!($function_name, " requires that its pointer argument is properly aligned and not null"),
140+
() => ::core::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)