Skip to content

Commit 009c4a7

Browse files
nitnelaveRalfJung
authored andcommitted
Add debug assertions to write_bytes and copy*
1 parent 5480b47 commit 009c4a7

File tree

2 files changed

+35
-4
lines changed

2 files changed

+35
-4
lines changed

src/libcore/intrinsics.rs

+32-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
issue = "0")]
3737
#![allow(missing_docs)]
3838

39+
use crate::mem;
40+
3941
#[stable(feature = "drop_in_place", since = "1.8.0")]
4042
#[rustc_deprecated(reason = "no longer an intrinsic - use `ptr::drop_in_place` directly",
4143
since = "1.18.0")]
@@ -1323,6 +1325,26 @@ extern "rust-intrinsic" {
13231325
// (`transmute` also falls into this category, but it cannot be wrapped due to the
13241326
// check that `T` and `U` have the same size.)
13251327

1328+
/// Checks whether `ptr` is properly aligned with respect to
1329+
/// `align_of::<T>()`.
1330+
pub(crate) fn is_aligned_and_not_null<T>(ptr: *const T) -> bool {
1331+
!ptr.is_null() && ptr as usize % mem::align_of::<T>() == 0
1332+
}
1333+
1334+
/// Checks whether the regions of memory starting at `src` and `dst` of size
1335+
/// `count * size_of::<T>()` overlap.
1336+
fn overlaps<T>(src: *const T, dst: *const T, count: usize) -> bool {
1337+
let src_usize = src as usize;
1338+
let dst_usize = dst as usize;
1339+
let size = mem::size_of::<T>().checked_mul(count).unwrap();
1340+
let diff = if src_usize > dst_usize {
1341+
src_usize - dst_usize
1342+
} else {
1343+
dst_usize - src_usize
1344+
};
1345+
size > diff
1346+
}
1347+
13261348
/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
13271349
/// and destination must *not* overlap.
13281350
///
@@ -1412,7 +1434,11 @@ pub unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
14121434
extern "rust-intrinsic" {
14131435
fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
14141436
}
1415-
copy_nonoverlapping(src, dst, count);
1437+
1438+
debug_assert!(is_aligned_and_not_null(src), "attempt to copy from unaligned or null pointer");
1439+
debug_assert!(is_aligned_and_not_null(dst), "attempt to copy to unaligned or null pointer");
1440+
debug_assert!(!overlaps(src, dst, count), "attempt to copy to overlapping memory");
1441+
copy_nonoverlapping(src, dst, count)
14161442
}
14171443

14181444
/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
@@ -1472,6 +1498,9 @@ pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
14721498
extern "rust-intrinsic" {
14731499
fn copy<T>(src: *const T, dst: *mut T, count: usize);
14741500
}
1501+
1502+
debug_assert!(is_aligned_and_not_null(src), "attempt to copy from unaligned or null pointer");
1503+
debug_assert!(is_aligned_and_not_null(dst), "attempt to copy to unaligned or null pointer");
14751504
copy(src, dst, count)
14761505
}
14771506

@@ -1553,5 +1582,7 @@ pub unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
15531582
extern "rust-intrinsic" {
15541583
fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
15551584
}
1585+
1586+
debug_assert!(is_aligned_and_not_null(dst), "attempt to write to unaligned or null pointer");
15561587
write_bytes(dst, val, count)
15571588
}

src/libcore/slice/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
use crate::cmp::Ordering::{self, Less, Equal, Greater};
2626
use crate::cmp;
2727
use crate::fmt;
28-
use crate::intrinsics::{assume, exact_div, unchecked_sub};
28+
use crate::intrinsics::{assume, exact_div, unchecked_sub, is_aligned_and_not_null};
2929
use crate::isize;
3030
use crate::iter::*;
3131
use crate::ops::{FnMut, Try, self};
@@ -5228,7 +5228,7 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> {
52285228
#[inline]
52295229
#[stable(feature = "rust1", since = "1.0.0")]
52305230
pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
5231-
debug_assert!(data as usize % mem::align_of::<T>() == 0, "attempt to create unaligned slice");
5231+
debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice");
52325232
debug_assert!(mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
52335233
"attempt to create slice covering half the address space");
52345234
&*ptr::slice_from_raw_parts(data, len)
@@ -5249,7 +5249,7 @@ pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
52495249
#[inline]
52505250
#[stable(feature = "rust1", since = "1.0.0")]
52515251
pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
5252-
debug_assert!(data as usize % mem::align_of::<T>() == 0, "attempt to create unaligned slice");
5252+
debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice");
52535253
debug_assert!(mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
52545254
"attempt to create slice covering half the address space");
52555255
&mut *ptr::slice_from_raw_parts_mut(data, len)

0 commit comments

Comments
 (0)