about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-02-29 00:20:44 +0000
committerbors <bors@rust-lang.org>2020-02-29 00:20:44 +0000
commit5703b7aafb70e77547e8f03876a5911a2e89a2a5 (patch)
tree993eae2b8ff1b373ec43f4b482425f0d056f83fa
parent0eb878d2aa6e3a1cb315f3f328681b26bb4bffdb (diff)
parent8d3b3063f6a91eb4d421998aea3c7dbcefa34f11 (diff)
downloadrust-5703b7aafb70e77547e8f03876a5911a2e89a2a5.tar.gz
rust-5703b7aafb70e77547e8f03876a5911a2e89a2a5.zip
Auto merge of #69208 - RalfJung:debug-assert, r=Mark-Simulacrum
debug_assert a few more raw pointer methods

Makes progress for https://github.com/rust-lang/rust/issues/53871
-rw-r--r--src/libcore/intrinsics.rs10
-rw-r--r--src/libcore/ptr/mod.rs14
2 files changed, 19 insertions, 5 deletions
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index 43f8cfc0c47..94928211a97 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -1423,13 +1423,15 @@ pub(crate) fn is_aligned_and_not_null<T>(ptr: *const T) -> bool {
 }
 
 /// Checks whether the regions of memory starting at `src` and `dst` of size
-/// `count * size_of::<T>()` overlap.
-fn overlaps<T>(src: *const T, dst: *const T, count: usize) -> bool {
+/// `count * size_of::<T>()` do *not* overlap.
+pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -> bool {
     let src_usize = src as usize;
     let dst_usize = dst as usize;
     let size = mem::size_of::<T>().checked_mul(count).unwrap();
     let diff = if src_usize > dst_usize { src_usize - dst_usize } else { dst_usize - src_usize };
-    size > diff
+    // If the absolute distance between the ptrs is at least as big as the size of the buffer,
+    // they do not overlap.
+    diff >= size
 }
 
 /// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
@@ -1525,7 +1527,7 @@ pub unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
 
     debug_assert!(is_aligned_and_not_null(src), "attempt to copy from unaligned or null pointer");
     debug_assert!(is_aligned_and_not_null(dst), "attempt to copy to unaligned or null pointer");
-    debug_assert!(!overlaps(src, dst, count), "attempt to copy to overlapping memory");
+    debug_assert!(is_nonoverlapping(src, dst, count), "attempt to copy to overlapping memory");
     copy_nonoverlapping(src, dst, count)
 }
 
diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs
index 88b490a25d5..fcfa98d8507 100644
--- a/src/libcore/ptr/mod.rs
+++ b/src/libcore/ptr/mod.rs
@@ -72,7 +72,7 @@
 use crate::cmp::Ordering;
 use crate::fmt;
 use crate::hash;
-use crate::intrinsics;
+use crate::intrinsics::{self, is_aligned_and_not_null, is_nonoverlapping};
 use crate::mem::{self, MaybeUninit};
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -392,6 +392,10 @@ pub unsafe fn swap<T>(x: *mut T, y: *mut T) {
 #[inline]
 #[stable(feature = "swap_nonoverlapping", since = "1.27.0")]
 pub unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
+    debug_assert!(is_aligned_and_not_null(x), "attempt to swap unaligned or null pointer");
+    debug_assert!(is_aligned_and_not_null(y), "attempt to swap unaligned or null pointer");
+    debug_assert!(is_nonoverlapping(x, y, count), "attempt to swap overlapping memory");
+
     let x = x as *mut u8;
     let y = y as *mut u8;
     let len = mem::size_of::<T>() * count;
@@ -619,6 +623,7 @@ pub unsafe fn replace<T>(dst: *mut T, mut src: T) -> T {
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub unsafe fn read<T>(src: *const T) -> T {
+    // `copy_nonoverlapping` takes care of debug_assert.
     let mut tmp = MaybeUninit::<T>::uninit();
     copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
     tmp.assume_init()
@@ -712,6 +717,7 @@ pub unsafe fn read<T>(src: *const T) -> T {
 #[inline]
 #[stable(feature = "ptr_unaligned", since = "1.17.0")]
 pub unsafe fn read_unaligned<T>(src: *const T) -> T {
+    // `copy_nonoverlapping` takes care of debug_assert.
     let mut tmp = MaybeUninit::<T>::uninit();
     copy_nonoverlapping(src as *const u8, tmp.as_mut_ptr() as *mut u8, mem::size_of::<T>());
     tmp.assume_init()
@@ -804,6 +810,9 @@ pub unsafe fn read_unaligned<T>(src: *const T) -> T {
 #[inline]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub unsafe fn write<T>(dst: *mut T, src: T) {
+    // FIXME: the debug assertion here causes codegen test failures on some architectures.
+    // See <https://github.com/rust-lang/rust/pull/69208#issuecomment-591326757>.
+    // debug_assert!(is_aligned_and_not_null(dst), "attempt to write to unaligned or null pointer");
     intrinsics::move_val_init(&mut *dst, src)
 }
 
@@ -896,6 +905,7 @@ pub unsafe fn write<T>(dst: *mut T, src: T) {
 #[inline]
 #[stable(feature = "ptr_unaligned", since = "1.17.0")]
 pub unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
+    // `copy_nonoverlapping` takes care of debug_assert.
     copy_nonoverlapping(&src as *const T as *const u8, dst as *mut u8, mem::size_of::<T>());
     mem::forget(src);
 }
@@ -967,6 +977,7 @@ pub unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
 #[inline]
 #[stable(feature = "volatile", since = "1.9.0")]
 pub unsafe fn read_volatile<T>(src: *const T) -> T {
+    debug_assert!(is_aligned_and_not_null(src), "attempt to read from unaligned or null pointer");
     intrinsics::volatile_load(src)
 }
 
@@ -1035,6 +1046,7 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
 #[inline]
 #[stable(feature = "volatile", since = "1.9.0")]
 pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
+    debug_assert!(is_aligned_and_not_null(dst), "attempt to write to unaligned or null pointer");
     intrinsics::volatile_store(dst, src);
 }