From 1b77f8e6ead5f717e9f7889885c6e84e05f4cef2 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sat, 26 Dec 2020 02:22:29 +0100 Subject: [PATCH 1/6] Constify intrinsics::copy[_nonoverlapping] --- .../rustc_mir/src/interpret/intrinsics.rs | 23 +++++++++++++++++++ library/core/src/intrinsics.rs | 17 +++++++++----- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index 474e1f8e577f8..c182fa35ee24a 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -322,6 +322,29 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let result = Scalar::from_uint(truncated_bits, layout.size); self.write_scalar(result, dest)?; } + sym::copy | sym::copy_nonoverlapping => { + let elem_ty = instance.substs.type_at(0); + let elem_layout = self.layout_of(elem_ty)?; + let count = self.read_scalar(args[2])?.to_machine_usize(self)?; + let elem_align = elem_layout.align.abi; + + let size = elem_layout.size.checked_mul(count, self).ok_or_else(|| { + err_ub_format!("overflow computing total size of `{}`", intrinsic_name) + })?; + let src = self.read_scalar(args[0])?.check_init()?; + let src = self.memory.check_ptr_access(src, size, elem_align)?; + let dest = self.read_scalar(args[1])?.check_init()?; + let dest = self.memory.check_ptr_access(dest, size, elem_align)?; + + if let (Some(src), Some(dest)) = (src, dest) { + self.memory.copy( + src, + dest, + size, + intrinsic_name == sym::copy_nonoverlapping, + )?; + } + } sym::offset => { let ptr = self.read_scalar(args[0])?.check_init()?; let offset_count = self.read_scalar(args[1])?.to_machine_isize(self)?; diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 5292182269385..87863ab5c68f4 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1846,20 +1846,22 @@ pub(crate) fn is_nonoverlapping(src: *const T, dst: *const T, count: usize) - /// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append #[doc(alias = "memcpy")] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "none")] #[inline] -pub unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { +pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { extern "rust-intrinsic" { fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); } - if cfg!(debug_assertions) + // 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. @@ -1928,16 +1930,19 @@ pub unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { /// ``` #[doc(alias = "memmove")] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "none")] #[inline] -pub unsafe fn copy(src: *const T, dst: *mut T, count: usize) { +pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { extern "rust-intrinsic" { + #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "none")] fn copy(src: *const T, dst: *mut T, count: usize); } - if cfg!(debug_assertions) && !(is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)) { + // FIXME: Perform these checks only at run time + /*if cfg!(debug_assertions) && !(is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)) { // Not panicking to keep codegen impact smaller. abort(); - } + }*/ // SAFETY: the safety contract for `copy` must be upheld by the caller. unsafe { copy(src, dst, count) } From 7594d2a0843e2354d3046951b333604969fec2bc Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sat, 26 Dec 2020 02:25:08 +0100 Subject: [PATCH 2/6] Constify ptr::read and ptr::read_unaligned --- library/core/src/lib.rs | 1 + library/core/src/ptr/mod.rs | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 5b19bf6b80f38..acf4936ee081e 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -73,6 +73,7 @@ #![feature(const_assert_type)] #![feature(const_discriminant)] #![feature(const_cell_into_inner)] +#![feature(const_intrinsic_copy)] #![feature(const_checked_int_methods)] #![feature(const_euclidean_int_methods)] #![feature(const_float_classify)] diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 27d49529a5ec2..14d6695a0f37e 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -685,7 +685,8 @@ pub unsafe fn replace(dst: *mut T, mut src: T) -> T { /// [valid]: self#safety #[inline] #[stable(feature = "rust1", since = "1.0.0")] -pub unsafe fn read(src: *const T) -> T { +#[rustc_const_unstable(feature = "const_ptr_read", issue = "none")] +pub const unsafe fn read(src: *const T) -> T { // `copy_nonoverlapping` takes care of debug_assert. let mut tmp = MaybeUninit::::uninit(); // SAFETY: the caller must guarantee that `src` is valid for reads. @@ -784,7 +785,8 @@ pub unsafe fn read(src: *const T) -> T { /// ``` #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] -pub unsafe fn read_unaligned(src: *const T) -> T { +#[rustc_const_unstable(feature = "const_ptr_read", issue = "none")] +pub const unsafe fn read_unaligned(src: *const T) -> T { // `copy_nonoverlapping` takes care of debug_assert. let mut tmp = MaybeUninit::::uninit(); // SAFETY: the caller must guarantee that `src` is valid for reads. From d4fd7987b559363e8af54cd69a4cb8bac0ae3230 Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sat, 26 Dec 2020 01:25:33 +0100 Subject: [PATCH 3/6] Constify *const T::read[_unaligned] and *mut T::read[_unaligned] --- library/core/src/ptr/const_ptr.rs | 6 ++++-- library/core/src/ptr/mut_ptr.rs | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 8fd9ff768c4f4..d6d0df2d6b93d 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -725,8 +725,9 @@ impl *const T { /// /// [`ptr::read`]: crate::ptr::read() #[stable(feature = "pointer_methods", since = "1.26.0")] + #[rustc_const_unstable(feature = "const_ptr_read", issue = "none")] #[inline] - pub unsafe fn read(self) -> T + pub const unsafe fn read(self) -> T where T: Sized, { @@ -763,8 +764,9 @@ impl *const T { /// /// [`ptr::read_unaligned`]: crate::ptr::read_unaligned() #[stable(feature = "pointer_methods", since = "1.26.0")] + #[rustc_const_unstable(feature = "const_ptr_read", issue = "none")] #[inline] - pub unsafe fn read_unaligned(self) -> T + pub const unsafe fn read_unaligned(self) -> T where T: Sized, { diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 5f94c2393aef3..bab747b50befc 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -832,8 +832,9 @@ impl *mut T { /// /// [`ptr::read`]: crate::ptr::read() #[stable(feature = "pointer_methods", since = "1.26.0")] + #[rustc_const_unstable(feature = "const_ptr_read", issue = "none")] #[inline] - pub unsafe fn read(self) -> T + pub const unsafe fn read(self) -> T where T: Sized, { @@ -870,8 +871,9 @@ impl *mut T { /// /// [`ptr::read_unaligned`]: crate::ptr::read_unaligned() #[stable(feature = "pointer_methods", since = "1.26.0")] + #[rustc_const_unstable(feature = "const_ptr_read", issue = "none")] #[inline] - pub unsafe fn read_unaligned(self) -> T + pub const unsafe fn read_unaligned(self) -> T where T: Sized, { From 1975a6e710d6fbb583a415edc3efed1e8970296a Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sat, 26 Dec 2020 01:27:13 +0100 Subject: [PATCH 4/6] Constify MaybeUninit::assume_init_read --- library/core/src/lib.rs | 1 + library/core/src/mem/maybe_uninit.rs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index acf4936ee081e..4a3020d6b99e1 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -94,6 +94,7 @@ #![feature(const_precise_live_drops)] #![feature(const_ptr_offset)] #![feature(const_ptr_offset_from)] +#![feature(const_ptr_read)] #![feature(const_raw_ptr_comparison)] #![feature(const_raw_ptr_deref)] #![feature(const_slice_from_raw_parts)] diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 57e0bb1499bde..b2a4d897eeded 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -575,8 +575,9 @@ impl MaybeUninit { /// // they both get dropped! /// ``` #[unstable(feature = "maybe_uninit_extra", issue = "63567")] + #[rustc_const_unstable(feature = "maybe_uninit_extra", issue = "63567")] #[inline(always)] - pub unsafe fn assume_init_read(&self) -> T { + pub const unsafe fn assume_init_read(&self) -> T { // SAFETY: the caller must guarantee that `self` is initialized. // Reading from `self.as_ptr()` is safe since `self` should be initialized. unsafe { From 5e27765ddfbeb524629ecb78c430fbe9c765232b Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sat, 26 Dec 2020 01:59:08 +0100 Subject: [PATCH 5/6] Add tests --- library/core/tests/const_ptr.rs | 51 ++++++++++++++++++ library/core/tests/lib.rs | 7 +++ library/core/tests/mem.rs | 7 +++ src/test/ui/const-ptr/out_of_bounds_read.rs | 16 ++++++ .../ui/const-ptr/out_of_bounds_read.stderr | 54 +++++++++++++++++++ 5 files changed, 135 insertions(+) create mode 100644 library/core/tests/const_ptr.rs create mode 100644 src/test/ui/const-ptr/out_of_bounds_read.rs create mode 100644 src/test/ui/const-ptr/out_of_bounds_read.stderr diff --git a/library/core/tests/const_ptr.rs b/library/core/tests/const_ptr.rs new file mode 100644 index 0000000000000..4acd059ab03df --- /dev/null +++ b/library/core/tests/const_ptr.rs @@ -0,0 +1,51 @@ +// Aligned to two bytes +const DATA: [u16; 2] = [u16::from_ne_bytes([0x01, 0x23]), u16::from_ne_bytes([0x45, 0x67])]; + +const fn unaligned_ptr() -> *const u16 { + // Since DATA.as_ptr() is aligned to two bytes, adding 1 byte to that produces an unaligned *const u16 + unsafe { (DATA.as_ptr() as *const u8).add(1) as *const u16 } +} + +#[test] +fn read() { + use core::ptr; + + const FOO: i32 = unsafe { ptr::read(&42 as *const i32) }; + assert_eq!(FOO, 42); + + const ALIGNED: i32 = unsafe { ptr::read_unaligned(&42 as *const i32) }; + assert_eq!(ALIGNED, 42); + + const UNALIGNED_PTR: *const u16 = unaligned_ptr(); + + const UNALIGNED: u16 = unsafe { ptr::read_unaligned(UNALIGNED_PTR) }; + assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45])); +} + +#[test] +fn const_ptr_read() { + const FOO: i32 = unsafe { (&42 as *const i32).read() }; + assert_eq!(FOO, 42); + + const ALIGNED: i32 = unsafe { (&42 as *const i32).read_unaligned() }; + assert_eq!(ALIGNED, 42); + + const UNALIGNED_PTR: *const u16 = unaligned_ptr(); + + const UNALIGNED: u16 = unsafe { UNALIGNED_PTR.read_unaligned() }; + assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45])); +} + +#[test] +fn mut_ptr_read() { + const FOO: i32 = unsafe { (&42 as *const i32 as *mut i32).read() }; + assert_eq!(FOO, 42); + + const ALIGNED: i32 = unsafe { (&42 as *const i32 as *mut i32).read_unaligned() }; + assert_eq!(ALIGNED, 42); + + const UNALIGNED_PTR: *mut u16 = unaligned_ptr() as *mut u16; + + const UNALIGNED: u16 = unsafe { UNALIGNED_PTR.read_unaligned() }; + assert_eq!(UNALIGNED, u16::from_ne_bytes([0x23, 0x45])); +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 2828235c3e38d..9e8ec7060216b 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -13,6 +13,8 @@ #![feature(const_assume)] #![feature(const_cell_into_inner)] #![feature(const_maybe_uninit_assume_init)] +#![feature(const_ptr_read)] +#![feature(const_ptr_offset)] #![feature(core_intrinsics)] #![feature(core_private_bignum)] #![feature(core_private_diy_float)] @@ -34,6 +36,7 @@ #![feature(raw)] #![feature(sort_internals)] #![feature(slice_partition_at_index)] +#![feature(maybe_uninit_extra)] #![feature(maybe_uninit_write_slice)] #![feature(min_specialization)] #![feature(step_trait)] @@ -82,6 +85,10 @@ mod cell; mod char; mod clone; mod cmp; + +#[cfg(not(bootstrap))] +mod const_ptr; + mod fmt; mod hash; mod intrinsics; diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index 5d0fedd4d9ccc..a09a2e91804b1 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -267,3 +267,10 @@ fn uninit_write_slice_cloned_no_drop() { forget(src); } + +#[test] +#[cfg(not(bootstrap))] +fn uninit_const_assume_init_read() { + const FOO: u32 = unsafe { MaybeUninit::new(42).assume_init_read() }; + assert_eq!(FOO, 42); +} diff --git a/src/test/ui/const-ptr/out_of_bounds_read.rs b/src/test/ui/const-ptr/out_of_bounds_read.rs new file mode 100644 index 0000000000000..183aa9e51228c --- /dev/null +++ b/src/test/ui/const-ptr/out_of_bounds_read.rs @@ -0,0 +1,16 @@ +// error-pattern: any use of this value will cause an error + +#![feature(const_ptr_read)] +#![feature(const_ptr_offset)] + +fn main() { + use std::ptr; + + const DATA: [u32; 1] = [42]; + + const PAST_END_PTR: *const u32 = unsafe { DATA.as_ptr().add(1) }; + + const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) }; + const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() }; + const _MUT_READ: u32 = unsafe { (PAST_END_PTR as *mut u32).read() }; +} diff --git a/src/test/ui/const-ptr/out_of_bounds_read.stderr b/src/test/ui/const-ptr/out_of_bounds_read.stderr new file mode 100644 index 0000000000000..ca65a079947e0 --- /dev/null +++ b/src/test/ui/const-ptr/out_of_bounds_read.stderr @@ -0,0 +1,54 @@ +error: any use of this value will cause an error + --> $SRC_DIR/core/src/intrinsics.rs:LL:COL + | +LL | unsafe { copy_nonoverlapping(src, dst, count) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4 + | inside `copy_nonoverlapping::` at $SRC_DIR/core/src/intrinsics.rs:LL:COL + | inside `std::ptr::read::` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | inside `_READ` at $DIR/out_of_bounds_read.rs:13:33 + | + ::: $DIR/out_of_bounds_read.rs:13:5 + | +LL | const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) }; + | ------------------------------------------------------ + | + = note: `#[deny(const_err)]` on by default + +error: any use of this value will cause an error + --> $SRC_DIR/core/src/intrinsics.rs:LL:COL + | +LL | unsafe { copy_nonoverlapping(src, dst, count) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4 + | inside `copy_nonoverlapping::` at $SRC_DIR/core/src/intrinsics.rs:LL:COL + | inside `std::ptr::read::` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | inside `ptr::const_ptr::::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `_CONST_READ` at $DIR/out_of_bounds_read.rs:14:39 + | + ::: $DIR/out_of_bounds_read.rs:14:5 + | +LL | const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() }; + | -------------------------------------------------------- + +error: any use of this value will cause an error + --> $SRC_DIR/core/src/intrinsics.rs:LL:COL + | +LL | unsafe { copy_nonoverlapping(src, dst, count) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | memory access failed: pointer must be in-bounds at offset 8, but is outside bounds of alloc6 which has size 4 + | inside `copy_nonoverlapping::` at $SRC_DIR/core/src/intrinsics.rs:LL:COL + | inside `std::ptr::read::` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | inside `ptr::mut_ptr::::read` at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + | inside `_MUT_READ` at $DIR/out_of_bounds_read.rs:15:37 + | + ::: $DIR/out_of_bounds_read.rs:15:5 + | +LL | const _MUT_READ: u32 = unsafe { (PAST_END_PTR as *mut u32).read() }; + | -------------------------------------------------------------------- + +error: aborting due to 3 previous errors + From 0cea1c9206388edccf9132543df1ab2da00daaaa Mon Sep 17 00:00:00 2001 From: Albin Hedman Date: Sat, 26 Dec 2020 14:03:28 +0100 Subject: [PATCH 6/6] Added reference to tracking issue #80377 --- library/core/src/ptr/const_ptr.rs | 4 ++-- library/core/src/ptr/mod.rs | 4 ++-- library/core/src/ptr/mut_ptr.rs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index d6d0df2d6b93d..e721d1243e88b 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -725,7 +725,7 @@ impl *const T { /// /// [`ptr::read`]: crate::ptr::read() #[stable(feature = "pointer_methods", since = "1.26.0")] - #[rustc_const_unstable(feature = "const_ptr_read", issue = "none")] + #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")] #[inline] pub const unsafe fn read(self) -> T where @@ -764,7 +764,7 @@ impl *const T { /// /// [`ptr::read_unaligned`]: crate::ptr::read_unaligned() #[stable(feature = "pointer_methods", since = "1.26.0")] - #[rustc_const_unstable(feature = "const_ptr_read", issue = "none")] + #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")] #[inline] pub const unsafe fn read_unaligned(self) -> T where diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 14d6695a0f37e..807f114ea466c 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -685,7 +685,7 @@ pub unsafe fn replace(dst: *mut T, mut src: T) -> T { /// [valid]: self#safety #[inline] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_ptr_read", issue = "none")] +#[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")] pub const unsafe fn read(src: *const T) -> T { // `copy_nonoverlapping` takes care of debug_assert. let mut tmp = MaybeUninit::::uninit(); @@ -785,7 +785,7 @@ pub const unsafe fn read(src: *const T) -> T { /// ``` #[inline] #[stable(feature = "ptr_unaligned", since = "1.17.0")] -#[rustc_const_unstable(feature = "const_ptr_read", issue = "none")] +#[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")] pub const unsafe fn read_unaligned(src: *const T) -> T { // `copy_nonoverlapping` takes care of debug_assert. let mut tmp = MaybeUninit::::uninit(); diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index bab747b50befc..1788956894393 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -832,7 +832,7 @@ impl *mut T { /// /// [`ptr::read`]: crate::ptr::read() #[stable(feature = "pointer_methods", since = "1.26.0")] - #[rustc_const_unstable(feature = "const_ptr_read", issue = "none")] + #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")] #[inline] pub const unsafe fn read(self) -> T where @@ -871,7 +871,7 @@ impl *mut T { /// /// [`ptr::read_unaligned`]: crate::ptr::read_unaligned() #[stable(feature = "pointer_methods", since = "1.26.0")] - #[rustc_const_unstable(feature = "const_ptr_read", issue = "none")] + #[rustc_const_unstable(feature = "const_ptr_read", issue = "80377")] #[inline] pub const unsafe fn read_unaligned(self) -> T where