From c6ec1dd717d73d21921b473b2422796041a20064 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Wed, 11 Sep 2024 18:04:40 -0400 Subject: [PATCH 1/2] Add precondition checks to ptr::offset, ptr::add, ptr::sub --- library/core/src/ptr/const_ptr.rs | 88 ++++++++++++++++++- library/core/src/ptr/mut_ptr.rs | 88 ++++++++++++++++++- tests/codegen/option-as-slice.rs | 8 +- ...e_add_fat.PreCodegen.after.panic-abort.mir | 12 ++- ..._add_fat.PreCodegen.after.panic-unwind.mir | 12 ++- ..._add_thin.PreCodegen.after.panic-abort.mir | 12 ++- ...add_thin.PreCodegen.after.panic-unwind.mir | 12 ++- ...ated_loop.PreCodegen.after.panic-abort.mir | 32 ++++--- ...ted_loop.PreCodegen.after.panic-unwind.mir | 12 ++- ...ward_loop.PreCodegen.after.panic-abort.mir | 8 +- ...ard_loop.PreCodegen.after.panic-unwind.mir | 8 +- ...erse_loop.PreCodegen.after.panic-abort.mir | 14 ++- ...rse_loop.PreCodegen.after.panic-unwind.mir | 14 ++- 13 files changed, 277 insertions(+), 43 deletions(-) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 3b45d46b31d5e..418ca96a2a525 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -394,6 +394,36 @@ impl *const T { where T: Sized, { + #[inline] + const fn runtime_offset_nowrap(this: *const (), count: isize, size: usize) -> bool { + #[inline] + fn runtime(this: *const (), count: isize, size: usize) -> bool { + // We know `size <= isize::MAX` so the `as` cast here is not lossy. + let Some(byte_offset) = count.checked_mul(size as isize) else { + return false; + }; + let (_, overflow) = this.addr().overflowing_add_signed(byte_offset); + !overflow + } + + const fn comptime(_: *const (), _: isize, _: usize) -> bool { + true + } + + // We can use const_eval_select here because this is only for UB checks. + intrinsics::const_eval_select((this, count, size), comptime, runtime) + } + + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "ptr::offset requires the address calculation to not overflow", + ( + this: *const () = self as *const (), + count: isize = count, + size: usize = size_of::(), + ) => runtime_offset_nowrap(this, count, size) + ); + // SAFETY: the caller must uphold the safety contract for `offset`. unsafe { intrinsics::offset(self, count) } } @@ -728,7 +758,6 @@ impl *const T { true } - #[allow(unused_unsafe)] intrinsics::const_eval_select((this, origin), comptime, runtime) } @@ -855,6 +884,34 @@ impl *const T { where T: Sized, { + #[inline] + const fn runtime_add_nowrap(this: *const (), count: usize, size: usize) -> bool { + #[inline] + fn runtime(this: *const (), count: usize, size: usize) -> bool { + let Some(byte_offset) = count.checked_mul(size) else { + return false; + }; + let (_, overflow) = this.addr().overflowing_add(byte_offset); + byte_offset <= (isize::MAX as usize) && !overflow + } + + const fn comptime(_: *const (), _: usize, _: usize) -> bool { + true + } + + intrinsics::const_eval_select((this, count, size), comptime, runtime) + } + + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "ptr::add requires that the address calculation does not overflow", + ( + this: *const () = self as *const (), + count: usize = count, + size: usize = size_of::(), + ) => runtime_add_nowrap(this, count, size) + ); + // SAFETY: the caller must uphold the safety contract for `offset`. unsafe { intrinsics::offset(self, count) } } @@ -930,6 +987,33 @@ impl *const T { where T: Sized, { + #[inline] + const fn runtime_sub_nowrap(this: *const (), count: usize, size: usize) -> bool { + #[inline] + fn runtime(this: *const (), count: usize, size: usize) -> bool { + let Some(byte_offset) = count.checked_mul(size) else { + return false; + }; + byte_offset <= (isize::MAX as usize) && this.addr() >= byte_offset + } + + const fn comptime(_: *const (), _: usize, _: usize) -> bool { + true + } + + intrinsics::const_eval_select((this, count, size), comptime, runtime) + } + + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "ptr::sub requires that the address calculation does not overflow", + ( + this: *const () = self as *const (), + count: usize = count, + size: usize = size_of::(), + ) => runtime_sub_nowrap(this, count, size) + ); + if T::IS_ZST { // Pointer arithmetic does nothing when the pointee is a ZST. self @@ -937,7 +1021,7 @@ impl *const T { // SAFETY: the caller must uphold the safety contract for `offset`. // Because the pointee is *not* a ZST, that means that `count` is // at most `isize::MAX`, and thus the negation cannot overflow. - unsafe { self.offset((count as isize).unchecked_neg()) } + unsafe { intrinsics::offset(self, intrinsics::unchecked_sub(0, count as isize)) } } } diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 5fa3b9bf61f7f..8487ba05629fa 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -392,6 +392,37 @@ impl *mut T { where T: Sized, { + #[inline] + const fn runtime_offset_nowrap(this: *const (), count: isize, size: usize) -> bool { + #[inline] + fn runtime(this: *const (), count: isize, size: usize) -> bool { + // `size` is the size of a Rust type, so we know that + // `size <= isize::MAX` and thus `as` cast here is not lossy. + let Some(byte_offset) = count.checked_mul(size as isize) else { + return false; + }; + let (_, overflow) = this.addr().overflowing_add_signed(byte_offset); + !overflow + } + + const fn comptime(_: *const (), _: isize, _: usize) -> bool { + true + } + + // We can use const_eval_select here because this is only for UB checks. + intrinsics::const_eval_select((this, count, size), comptime, runtime) + } + + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "ptr::offset requires the address calculation to not overflow", + ( + this: *const () = self as *const (), + count: isize = count, + size: usize = size_of::(), + ) => runtime_offset_nowrap(this, count, size) + ); + // SAFETY: the caller must uphold the safety contract for `offset`. // The obtained pointer is valid for writes since the caller must // guarantee that it points to the same allocated object as `self`. @@ -936,6 +967,34 @@ impl *mut T { where T: Sized, { + #[inline] + const fn runtime_add_nowrap(this: *const (), count: usize, size: usize) -> bool { + #[inline] + fn runtime(this: *const (), count: usize, size: usize) -> bool { + let Some(byte_offset) = count.checked_mul(size) else { + return false; + }; + let (_, overflow) = this.addr().overflowing_add(byte_offset); + byte_offset <= (isize::MAX as usize) && !overflow + } + + const fn comptime(_: *const (), _: usize, _: usize) -> bool { + true + } + + intrinsics::const_eval_select((this, count, size), comptime, runtime) + } + + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "ptr::add requires that the address calculation does not overflow", + ( + this: *const () = self as *const (), + count: usize = count, + size: usize = size_of::(), + ) => runtime_add_nowrap(this, count, size) + ); + // SAFETY: the caller must uphold the safety contract for `offset`. unsafe { intrinsics::offset(self, count) } } @@ -1011,6 +1070,33 @@ impl *mut T { where T: Sized, { + #[inline] + const fn runtime_sub_nowrap(this: *const (), count: usize, size: usize) -> bool { + #[inline] + fn runtime(this: *const (), count: usize, size: usize) -> bool { + let Some(byte_offset) = count.checked_mul(size) else { + return false; + }; + byte_offset <= (isize::MAX as usize) && this.addr() >= byte_offset + } + + const fn comptime(_: *const (), _: usize, _: usize) -> bool { + true + } + + intrinsics::const_eval_select((this, count, size), comptime, runtime) + } + + ub_checks::assert_unsafe_precondition!( + check_language_ub, + "ptr::sub requires that the address calculation does not overflow", + ( + this: *const () = self as *const (), + count: usize = count, + size: usize = size_of::(), + ) => runtime_sub_nowrap(this, count, size) + ); + if T::IS_ZST { // Pointer arithmetic does nothing when the pointee is a ZST. self @@ -1018,7 +1104,7 @@ impl *mut T { // SAFETY: the caller must uphold the safety contract for `offset`. // Because the pointee is *not* a ZST, that means that `count` is // at most `isize::MAX`, and thus the negation cannot overflow. - unsafe { self.offset((count as isize).unchecked_neg()) } + unsafe { intrinsics::offset(self, intrinsics::unchecked_sub(0, count as isize)) } } } diff --git a/tests/codegen/option-as-slice.rs b/tests/codegen/option-as-slice.rs index cfa479aa4b2f2..0edbbac11762d 100644 --- a/tests/codegen/option-as-slice.rs +++ b/tests/codegen/option-as-slice.rs @@ -14,7 +14,9 @@ pub fn u64_opt_as_slice(o: &Option) -> &[u64] { // CHECK-NOT: br // CHECK-NOT: switch // CHECK-NOT: icmp - // CHECK: %[[LEN:.+]] = load i64,{{.+}} !range ![[META_U64:.+]], !noundef + // CHECK: %[[LEN:.+]] = load i64 + // CHECK-SAME: !range ![[META_U64:[0-9]+]], + // CHECK-SAME: !noundef // CHECK-NOT: select // CHECK-NOT: br // CHECK-NOT: switch @@ -51,7 +53,9 @@ pub fn u8_opt_as_slice(o: &Option) -> &[u8] { // CHECK-NOT: br // CHECK-NOT: switch // CHECK-NOT: icmp - // CHECK: %[[TAG:.+]] = load i8,{{.+}} !range ![[META_U8:.+]], !noundef + // CHECK: %[[TAG:.+]] = load i8 + // CHECK-SAME: !range ![[META_U8:[0-9]+]], + // CHECK-SAME: !noundef // CHECK: %[[LEN:.+]] = zext{{.*}} i8 %[[TAG]] to i64 // CHECK-NOT: select // CHECK-NOT: br diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir index 5faa1e210cf4f..c99c6f7de88c6 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir @@ -10,12 +10,18 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] { scope 2 (inlined std::ptr::const_ptr::::cast::) { } scope 3 (inlined std::ptr::const_ptr::::add) { + scope 4 (inlined core::ub_checks::check_language_ub) { + scope 5 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + scope 6 (inlined std::mem::size_of::) { + } } - scope 4 (inlined std::ptr::const_ptr::::with_metadata_of::<[u32]>) { + scope 7 (inlined std::ptr::const_ptr::::with_metadata_of::<[u32]>) { let mut _5: usize; - scope 5 (inlined std::ptr::metadata::<[u32]>) { + scope 8 (inlined std::ptr::metadata::<[u32]>) { } - scope 6 (inlined std::ptr::from_raw_parts::<[u32], ()>) { + scope 9 (inlined std::ptr::from_raw_parts::<[u32], ()>) { } } } diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir index 5faa1e210cf4f..c99c6f7de88c6 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir @@ -10,12 +10,18 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] { scope 2 (inlined std::ptr::const_ptr::::cast::) { } scope 3 (inlined std::ptr::const_ptr::::add) { + scope 4 (inlined core::ub_checks::check_language_ub) { + scope 5 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + scope 6 (inlined std::mem::size_of::) { + } } - scope 4 (inlined std::ptr::const_ptr::::with_metadata_of::<[u32]>) { + scope 7 (inlined std::ptr::const_ptr::::with_metadata_of::<[u32]>) { let mut _5: usize; - scope 5 (inlined std::ptr::metadata::<[u32]>) { + scope 8 (inlined std::ptr::metadata::<[u32]>) { } - scope 6 (inlined std::ptr::from_raw_parts::<[u32], ()>) { + scope 9 (inlined std::ptr::from_raw_parts::<[u32], ()>) { } } } diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir index 9429785045a29..07665b2adc81a 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir @@ -10,11 +10,17 @@ fn demo_byte_add_thin(_1: *const u32, _2: usize) -> *const u32 { scope 2 (inlined std::ptr::const_ptr::::cast::) { } scope 3 (inlined std::ptr::const_ptr::::add) { + scope 4 (inlined core::ub_checks::check_language_ub) { + scope 5 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + scope 6 (inlined std::mem::size_of::) { + } } - scope 4 (inlined std::ptr::const_ptr::::with_metadata_of::) { - scope 5 (inlined std::ptr::metadata::) { + scope 7 (inlined std::ptr::const_ptr::::with_metadata_of::) { + scope 8 (inlined std::ptr::metadata::) { } - scope 6 (inlined std::ptr::from_raw_parts::) { + scope 9 (inlined std::ptr::from_raw_parts::) { } } } diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir index 9429785045a29..07665b2adc81a 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir @@ -10,11 +10,17 @@ fn demo_byte_add_thin(_1: *const u32, _2: usize) -> *const u32 { scope 2 (inlined std::ptr::const_ptr::::cast::) { } scope 3 (inlined std::ptr::const_ptr::::add) { + scope 4 (inlined core::ub_checks::check_language_ub) { + scope 5 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + scope 6 (inlined std::mem::size_of::) { + } } - scope 4 (inlined std::ptr::const_ptr::::with_metadata_of::) { - scope 5 (inlined std::ptr::metadata::) { + scope 7 (inlined std::ptr::const_ptr::::with_metadata_of::) { + scope 8 (inlined std::ptr::metadata::) { } - scope 6 (inlined std::ptr::from_raw_parts::) { + scope 9 (inlined std::ptr::from_raw_parts::) { } } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir index 3aa483ed1aefa..da3295bf8c979 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir @@ -19,30 +19,30 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { debug i => _22; debug x => _23; } - scope 17 (inlined > as Iterator>::next) { + scope 20 (inlined > as Iterator>::next) { let mut _14: &mut std::slice::Iter<'_, T>; let mut _15: std::option::Option<&T>; let mut _19: (usize, bool); let mut _20: (usize, &T); - scope 18 { + scope 21 { let _18: usize; - scope 23 { + scope 26 { } } - scope 19 { - scope 20 { - scope 26 (inlined as FromResidual>>::from_residual) { + scope 22 { + scope 23 { + scope 29 (inlined as FromResidual>>::from_residual) { } } } - scope 21 { - scope 22 { + scope 24 { + scope 25 { } } - scope 24 (inlined as Try>::branch) { + scope 27 (inlined as Try>::branch) { let mut _16: isize; let _17: &T; - scope 25 { + scope 28 { } } } @@ -64,6 +64,12 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { scope 12 (inlined NonNull::::as_ptr) { } scope 13 (inlined std::ptr::mut_ptr::::add) { + scope 14 (inlined core::ub_checks::check_language_ub) { + scope 15 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + scope 16 (inlined std::mem::size_of::) { + } } } scope 8 (inlined as From<&[T]>>::from) { @@ -77,11 +83,11 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } } } - scope 14 (inlined as Iterator>::enumerate) { - scope 15 (inlined Enumerate::>::new) { + scope 17 (inlined as Iterator>::enumerate) { + scope 18 (inlined Enumerate::>::new) { } } - scope 16 (inlined > as IntoIterator>::into_iter) { + scope 19 (inlined > as IntoIterator>::into_iter) { } bb0: { diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir index 4cc0aa0ed788d..46c868ba8a16d 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir @@ -39,6 +39,12 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { scope 12 (inlined NonNull::::as_ptr) { } scope 13 (inlined std::ptr::mut_ptr::::add) { + scope 14 (inlined core::ub_checks::check_language_ub) { + scope 15 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + scope 16 (inlined std::mem::size_of::) { + } } } scope 8 (inlined as From<&[T]>>::from) { @@ -52,11 +58,11 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } } } - scope 14 (inlined as Iterator>::enumerate) { - scope 15 (inlined Enumerate::>::new) { + scope 17 (inlined as Iterator>::enumerate) { + scope 18 (inlined Enumerate::>::new) { } } - scope 16 (inlined > as IntoIterator>::into_iter) { + scope 19 (inlined > as IntoIterator>::into_iter) { } bb0: { diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir index 507afa63c6884..cedda097c3890 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir @@ -36,6 +36,12 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 12 (inlined NonNull::::as_ptr) { } scope 13 (inlined std::ptr::mut_ptr::::add) { + scope 14 (inlined core::ub_checks::check_language_ub) { + scope 15 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + scope 16 (inlined std::mem::size_of::) { + } } } scope 8 (inlined as From<&[T]>>::from) { @@ -49,7 +55,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } } } - scope 14 (inlined as IntoIterator>::into_iter) { + scope 17 (inlined as IntoIterator>::into_iter) { } bb0: { diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir index a25f12edc28e9..e299760d9825a 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir @@ -36,6 +36,12 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 12 (inlined NonNull::::as_ptr) { } scope 13 (inlined std::ptr::mut_ptr::::add) { + scope 14 (inlined core::ub_checks::check_language_ub) { + scope 15 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + scope 16 (inlined std::mem::size_of::) { + } } } scope 8 (inlined as From<&[T]>>::from) { @@ -49,7 +55,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } } } - scope 14 (inlined as IntoIterator>::into_iter) { + scope 17 (inlined as IntoIterator>::into_iter) { } bb0: { diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir index 1b397a4e4cdde..d01bd4a9a4a5f 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir @@ -18,7 +18,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 2 { debug x => _17; } - scope 17 (inlined > as Iterator>::next) { + scope 20 (inlined > as Iterator>::next) { let mut _14: &mut std::slice::Iter<'_, T>; } } @@ -39,6 +39,12 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 12 (inlined NonNull::::as_ptr) { } scope 13 (inlined std::ptr::mut_ptr::::add) { + scope 14 (inlined core::ub_checks::check_language_ub) { + scope 15 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + scope 16 (inlined std::mem::size_of::) { + } } } scope 8 (inlined as From<&[T]>>::from) { @@ -52,11 +58,11 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } } } - scope 14 (inlined as Iterator>::rev) { - scope 15 (inlined Rev::>::new) { + scope 17 (inlined as Iterator>::rev) { + scope 18 (inlined Rev::>::new) { } } - scope 16 (inlined > as IntoIterator>::into_iter) { + scope 19 (inlined > as IntoIterator>::into_iter) { } bb0: { diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir index 77689dd9b513e..d2d0492add466 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir @@ -18,7 +18,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 2 { debug x => _17; } - scope 17 (inlined > as Iterator>::next) { + scope 20 (inlined > as Iterator>::next) { let mut _14: &mut std::slice::Iter<'_, T>; } } @@ -39,6 +39,12 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 12 (inlined NonNull::::as_ptr) { } scope 13 (inlined std::ptr::mut_ptr::::add) { + scope 14 (inlined core::ub_checks::check_language_ub) { + scope 15 (inlined core::ub_checks::check_language_ub::runtime) { + } + } + scope 16 (inlined std::mem::size_of::) { + } } } scope 8 (inlined as From<&[T]>>::from) { @@ -52,11 +58,11 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } } } - scope 14 (inlined as Iterator>::rev) { - scope 15 (inlined Rev::>::new) { + scope 17 (inlined as Iterator>::rev) { + scope 18 (inlined Rev::>::new) { } } - scope 16 (inlined > as IntoIterator>::into_iter) { + scope 19 (inlined > as IntoIterator>::into_iter) { } bb0: { From ee9b0574c41c7d32a9e8115a0936ce3d8de21259 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 6 Oct 2024 23:36:22 -0400 Subject: [PATCH 2/2] cfg out checks in add and sub but not offset ...because the checks in offset found bugs in a crater run. --- library/core/src/ptr/const_ptr.rs | 4 ++++ library/core/src/ptr/mut_ptr.rs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 418ca96a2a525..fb8a72ed772b5 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -884,6 +884,7 @@ impl *const T { where T: Sized, { + #[cfg(debug_assertions)] #[inline] const fn runtime_add_nowrap(this: *const (), count: usize, size: usize) -> bool { #[inline] @@ -902,6 +903,7 @@ impl *const T { intrinsics::const_eval_select((this, count, size), comptime, runtime) } + #[cfg(debug_assertions)] // Expensive, and doesn't catch much in the wild. ub_checks::assert_unsafe_precondition!( check_language_ub, "ptr::add requires that the address calculation does not overflow", @@ -987,6 +989,7 @@ impl *const T { where T: Sized, { + #[cfg(debug_assertions)] #[inline] const fn runtime_sub_nowrap(this: *const (), count: usize, size: usize) -> bool { #[inline] @@ -1004,6 +1007,7 @@ impl *const T { intrinsics::const_eval_select((this, count, size), comptime, runtime) } + #[cfg(debug_assertions)] // Expensive, and doesn't catch much in the wild. ub_checks::assert_unsafe_precondition!( check_language_ub, "ptr::sub requires that the address calculation does not overflow", diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 8487ba05629fa..7a999410d2534 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -967,6 +967,7 @@ impl *mut T { where T: Sized, { + #[cfg(debug_assertions)] #[inline] const fn runtime_add_nowrap(this: *const (), count: usize, size: usize) -> bool { #[inline] @@ -985,6 +986,7 @@ impl *mut T { intrinsics::const_eval_select((this, count, size), comptime, runtime) } + #[cfg(debug_assertions)] // Expensive, and doesn't catch much in the wild. ub_checks::assert_unsafe_precondition!( check_language_ub, "ptr::add requires that the address calculation does not overflow", @@ -1070,6 +1072,7 @@ impl *mut T { where T: Sized, { + #[cfg(debug_assertions)] #[inline] const fn runtime_sub_nowrap(this: *const (), count: usize, size: usize) -> bool { #[inline] @@ -1087,6 +1090,7 @@ impl *mut T { intrinsics::const_eval_select((this, count, size), comptime, runtime) } + #[cfg(debug_assertions)] // Expensive, and doesn't catch much in the wild. ub_checks::assert_unsafe_precondition!( check_language_ub, "ptr::sub requires that the address calculation does not overflow",