directly expose copy and copy_nonoverlapping intrinsics
This commit is contained in:
parent
57a71ac0e1
commit
18d12ad171
3 changed files with 175 additions and 218 deletions
|
@ -1730,30 +1730,6 @@ extern "rust-intrinsic" {
|
||||||
/// Allocate at compile time. Should not be called at runtime.
|
/// Allocate at compile time. Should not be called at runtime.
|
||||||
#[rustc_const_unstable(feature = "const_heap", issue = "79597")]
|
#[rustc_const_unstable(feature = "const_heap", issue = "79597")]
|
||||||
pub fn const_allocate(size: usize, align: usize) -> *mut u8;
|
pub fn const_allocate(size: usize, align: usize) -> *mut u8;
|
||||||
}
|
|
||||||
|
|
||||||
// Some functions are defined here because they accidentally got made
|
|
||||||
// available in this module on stable. See <https://github.com/rust-lang/rust/issues/15702>.
|
|
||||||
// (`transmute` also falls into this category, but it cannot be wrapped due to the
|
|
||||||
// check that `T` and `U` have the same size.)
|
|
||||||
|
|
||||||
/// Checks whether `ptr` is properly aligned with respect to
|
|
||||||
/// `align_of::<T>()`.
|
|
||||||
pub(crate) fn is_aligned_and_not_null<T>(ptr: *const T) -> bool {
|
|
||||||
!ptr.is_null() && ptr as usize % mem::align_of::<T>() == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks whether the regions of memory starting at `src` and `dst` of size
|
|
||||||
/// `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 };
|
|
||||||
// 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
|
/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
|
||||||
/// and destination must *not* overlap.
|
/// and destination must *not* overlap.
|
||||||
|
@ -1839,27 +1815,7 @@ pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -
|
||||||
#[doc(alias = "memcpy")]
|
#[doc(alias = "memcpy")]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
|
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
|
||||||
#[inline]
|
pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
|
||||||
pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) {
|
|
||||||
extern "rust-intrinsic" {
|
|
||||||
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
|
|
||||||
fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: Perform these checks only at run time
|
|
||||||
/*if cfg!(debug_assertions)
|
|
||||||
&& !(is_aligned_and_not_null(src)
|
|
||||||
&& is_aligned_and_not_null(dst)
|
|
||||||
&& is_nonoverlapping(src, dst, count))
|
|
||||||
{
|
|
||||||
// Not panicking to keep codegen impact smaller.
|
|
||||||
abort();
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// SAFETY: the safety contract for `copy_nonoverlapping` must be
|
|
||||||
// upheld by the caller.
|
|
||||||
unsafe { copy_nonoverlapping(src, dst, count) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
|
/// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
|
||||||
/// and destination may overlap.
|
/// and destination may overlap.
|
||||||
|
@ -1924,21 +1880,30 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
|
||||||
#[doc(alias = "memmove")]
|
#[doc(alias = "memmove")]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
|
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
|
||||||
#[inline]
|
pub fn copy<T>(src: *const T, dst: *mut T, count: usize);
|
||||||
pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
|
|
||||||
extern "rust-intrinsic" {
|
|
||||||
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
|
|
||||||
fn copy<T>(src: *const T, dst: *mut T, count: usize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Perform these checks only at run time
|
// Some functions are defined here because they accidentally got made
|
||||||
/*if cfg!(debug_assertions) && !(is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)) {
|
// available in this module on stable. See <https://github.com/rust-lang/rust/issues/15702>.
|
||||||
// Not panicking to keep codegen impact smaller.
|
// (`transmute` also falls into this category, but it cannot be wrapped due to the
|
||||||
abort();
|
// check that `T` and `U` have the same size.)
|
||||||
}*/
|
|
||||||
|
|
||||||
// SAFETY: the safety contract for `copy` must be upheld by the caller.
|
/// Checks whether `ptr` is properly aligned with respect to
|
||||||
unsafe { copy(src, dst, count) }
|
/// `align_of::<T>()`.
|
||||||
|
pub(crate) fn is_aligned_and_not_null<T>(ptr: *const T) -> bool {
|
||||||
|
!ptr.is_null() && ptr as usize % mem::align_of::<T>() == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks whether the regions of memory starting at `src` and `dst` of size
|
||||||
|
/// `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 };
|
||||||
|
// If the absolute distance between the ptrs is at least as big as the size of the buffer,
|
||||||
|
// they do not overlap.
|
||||||
|
diff >= size
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets `count * size_of::<T>()` bytes of memory starting at `dst` to
|
/// Sets `count * size_of::<T>()` bytes of memory starting at `dst` to
|
||||||
|
|
|
@ -881,17 +881,12 @@ pub const unsafe fn read_unaligned<T>(src: *const T) -> T {
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub unsafe fn write<T>(dst: *mut T, src: T) {
|
pub unsafe fn write<T>(dst: *mut T, src: T) {
|
||||||
// We are calling the intrinsics directly to avoid function calls in the generated code
|
|
||||||
// as `intrinsics::copy_nonoverlapping` is a wrapper function.
|
|
||||||
extern "rust-intrinsic" {
|
|
||||||
fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
|
|
||||||
}
|
|
||||||
|
|
||||||
// SAFETY: the caller must guarantee that `dst` is valid for writes.
|
// SAFETY: the caller must guarantee that `dst` is valid for writes.
|
||||||
// `dst` cannot overlap `src` because the caller has mutable access
|
// `dst` cannot overlap `src` because the caller has mutable access
|
||||||
// to `dst` while `src` is owned by this function.
|
// to `dst` while `src` is owned by this function.
|
||||||
unsafe {
|
unsafe {
|
||||||
copy_nonoverlapping(&src as *const T, dst, 1);
|
copy_nonoverlapping(&src as *const T, dst, 1);
|
||||||
|
// We are calling the intrinsic directly to avoid function calls in the generated code.
|
||||||
intrinsics::forget(src);
|
intrinsics::forget(src);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
error: any use of this value will cause an error
|
error: any use of this value will cause an error
|
||||||
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL
|
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
||||||
|
|
|
|
||||||
LL | unsafe { copy_nonoverlapping(src, dst, count) }
|
LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
| |
|
| |
|
||||||
| memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4
|
| memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4
|
||||||
| inside `copy_nonoverlapping::<u32>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
|
|
||||||
| inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
| inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
||||||
| inside `_READ` at $DIR/out_of_bounds_read.rs:13:33
|
| inside `_READ` at $DIR/out_of_bounds_read.rs:13:33
|
||||||
|
|
|
|
||||||
|
@ -17,13 +16,12 @@ LL | const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) };
|
||||||
= note: `#[deny(const_err)]` on by default
|
= note: `#[deny(const_err)]` on by default
|
||||||
|
|
||||||
error: any use of this value will cause an error
|
error: any use of this value will cause an error
|
||||||
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL
|
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
||||||
|
|
|
|
||||||
LL | unsafe { copy_nonoverlapping(src, dst, count) }
|
LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
| |
|
| |
|
||||||
| memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4
|
| memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4
|
||||||
| inside `copy_nonoverlapping::<u32>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
|
|
||||||
| inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
| inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
||||||
| inside `ptr::const_ptr::<impl *const u32>::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
| inside `ptr::const_ptr::<impl *const u32>::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
|
||||||
| inside `_CONST_READ` at $DIR/out_of_bounds_read.rs:14:39
|
| inside `_CONST_READ` at $DIR/out_of_bounds_read.rs:14:39
|
||||||
|
@ -34,13 +32,12 @@ LL | const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() };
|
||||||
| --------------------------------------------------------
|
| --------------------------------------------------------
|
||||||
|
|
||||||
error: any use of this value will cause an error
|
error: any use of this value will cause an error
|
||||||
--> $SRC_DIR/core/src/intrinsics.rs:LL:COL
|
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
||||||
|
|
|
|
||||||
LL | unsafe { copy_nonoverlapping(src, dst, count) }
|
LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
| |
|
| |
|
||||||
| memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4
|
| memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4
|
||||||
| inside `copy_nonoverlapping::<u32>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
|
|
||||||
| inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
| inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
||||||
| inside `ptr::mut_ptr::<impl *mut u32>::read` at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
|
| inside `ptr::mut_ptr::<impl *mut u32>::read` at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
|
||||||
| inside `_MUT_READ` at $DIR/out_of_bounds_read.rs:15:37
|
| inside `_MUT_READ` at $DIR/out_of_bounds_read.rs:15:37
|
||||||
|
|
Loading…
Reference in a new issue