From 3cd517a13fe9cfd7b787a3cf2ff70feeb2d3a035 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Wed, 7 Feb 2024 19:26:26 -0500 Subject: [PATCH] Expand assumes to the other unchecked slice ops --- library/core/src/slice/index.rs | 17 +++++-- tests/codegen-llvm/issues/issue-116878.rs | 24 +++++++++ ...mut_range.PreCodegen.after.panic-abort.mir | 49 ++++++++++++------- ...ut_range.PreCodegen.after.panic-unwind.mir | 49 ++++++++++++------- ...ked_range.PreCodegen.after.panic-abort.mir | 41 ++++++++++------ ...ed_range.PreCodegen.after.panic-unwind.mir | 41 ++++++++++------ 6 files changed, 154 insertions(+), 67 deletions(-) diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index de220e7e38a4b..a062f752eee99 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -258,7 +258,10 @@ unsafe impl const SliceIndex<[T]> for usize { (this: usize = self, len: usize = slice.len()) => this < len ); // SAFETY: see comments for `get_unchecked` above. - unsafe { slice_get_unchecked(slice, self) } + unsafe { + crate::intrinsics::assume(self < slice.len()); + slice_get_unchecked(slice, self) + } } #[inline] @@ -312,7 +315,10 @@ unsafe impl const SliceIndex<[T]> for ops::IndexRange { // cannot be longer than `isize::MAX`. They also guarantee that // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, // so the call to `add` is safe. - unsafe { get_offset_len_noubcheck(slice, self.start(), self.len()) } + unsafe { + crate::intrinsics::assume(self.end() <= slice.len()); + get_offset_len_noubcheck(slice, self.start(), self.len()) + } } #[inline] @@ -325,7 +331,10 @@ unsafe impl const SliceIndex<[T]> for ops::IndexRange { ); // SAFETY: see comments for `get_unchecked` above. - unsafe { get_offset_len_mut_noubcheck(slice, self.start(), self.len()) } + unsafe { + crate::intrinsics::assume(self.end() <= slice.len()); + get_offset_len_mut_noubcheck(slice, self.start(), self.len()) + } } #[inline] @@ -402,6 +411,7 @@ unsafe impl const SliceIndex<[T]> for ops::Range { unsafe { // Using the intrinsic avoids a superfluous UB check, // since the one on this method already checked `end >= start`. + crate::intrinsics::assume(self.end <= slice.len()); let new_len = crate::intrinsics::unchecked_sub(self.end, self.start); get_offset_len_noubcheck(slice, self.start, new_len) } @@ -421,6 +431,7 @@ unsafe impl const SliceIndex<[T]> for ops::Range { ); // SAFETY: see comments for `get_unchecked` above. unsafe { + crate::intrinsics::assume(self.end <= slice.len()); let new_len = crate::intrinsics::unchecked_sub(self.end, self.start); get_offset_len_mut_noubcheck(slice, self.start, new_len) } diff --git a/tests/codegen-llvm/issues/issue-116878.rs b/tests/codegen-llvm/issues/issue-116878.rs index daf46c8bb554a..764903c879822 100644 --- a/tests/codegen-llvm/issues/issue-116878.rs +++ b/tests/codegen-llvm/issues/issue-116878.rs @@ -9,3 +9,27 @@ pub unsafe fn unchecked_slice_no_bounds_check(s: &[u8]) -> u8 { // CHECK-NOT: panic_bounds_check a + s[0] } + +// CHECK-LABEL: @unchecked_slice_no_bounds_check_mut +#[no_mangle] +pub unsafe fn unchecked_slice_no_bounds_check_mut(s: &mut [u8]) -> u8 { + let a = *s.get_unchecked_mut(2); + // CHECK-NOT: panic_bounds_check + a + s[1] +} + +// CHECK-LABEL: @unchecked_slice_no_bounds_check_range +#[no_mangle] +pub unsafe fn unchecked_slice_no_bounds_check_range(s: &[u8]) -> u8 { + let _a = &s.get_unchecked(..1); + // CHECK-NOT: panic_bounds_check + s[0] +} + +// CHECK-LABEL: @unchecked_slice_no_bounds_check_range_mut +#[no_mangle] +pub unsafe fn unchecked_slice_no_bounds_check_range_mut(s: &mut [u8]) -> u8 { + let _a = &mut s.get_unchecked_mut(..2); + // CHECK-NOT: panic_bounds_check + s[1] +} diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir index 6fb1637a6e02f..8c9a36169beb6 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir @@ -8,17 +8,19 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> let mut _4: usize; scope 1 (inlined #[track_caller] core::slice::::get_unchecked_mut::>) { let mut _5: *mut [u32]; - let mut _11: *mut [u32]; + let mut _13: *mut [u32]; scope 2 (inlined #[track_caller] as SliceIndex<[u32]>>::get_unchecked_mut) { let mut _6: usize; let _7: (); - let _8: usize; + let mut _8: usize; + let mut _9: bool; + let _10: usize; scope 3 { - scope 6 (inlined core::slice::index::get_offset_len_mut_noubcheck::) { - let _9: *mut u32; - scope 7 { - let _10: *mut u32; - scope 8 { + scope 8 (inlined core::slice::index::get_offset_len_mut_noubcheck::) { + let _11: *mut u32; + scope 9 { + let _12: *mut u32; + scope 10 { } } } @@ -27,16 +29,20 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> scope 5 (inlined std::ptr::metadata::<[u32]>) { } } + scope 6 (inlined std::ptr::mut_ptr::::len) { + scope 7 (inlined std::ptr::metadata::<[u32]>) { + } + } } } bb0: { _3 = move (_2.0: usize); _4 = move (_2.1: usize); - StorageLive(_11); + StorageLive(_13); StorageLive(_5); _5 = &raw mut (*_1); - StorageLive(_8); + StorageLive(_10); StorageLive(_6); _6 = PtrMetadata(copy _1); _7 = as SliceIndex<[T]>>::get_unchecked_mut::precondition_check(copy _3, copy _4, move _6) -> [return: bb1, unwind unreachable]; @@ -44,18 +50,25 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> bb1: { StorageDead(_6); - _8 = SubUnchecked(copy _4, copy _3); StorageLive(_9); - StorageLive(_10); - _9 = copy _5 as *mut u32 (PtrToPtr); - _10 = Offset(copy _9, copy _3); - _11 = *mut [u32] from (copy _10, copy _8); - StorageDead(_10); - StorageDead(_9); + StorageLive(_8); + _8 = PtrMetadata(copy _1); + _9 = Le(copy _4, move _8); StorageDead(_8); - StorageDead(_5); - _0 = &mut (*_11); + assume(move _9); + StorageDead(_9); + _10 = SubUnchecked(copy _4, copy _3); + StorageLive(_11); + StorageLive(_12); + _11 = copy _5 as *mut u32 (PtrToPtr); + _12 = Offset(copy _11, copy _3); + _13 = *mut [u32] from (copy _12, copy _10); + StorageDead(_12); StorageDead(_11); + StorageDead(_10); + StorageDead(_5); + _0 = &mut (*_13); + StorageDead(_13); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir index 6fb1637a6e02f..8c9a36169beb6 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir @@ -8,17 +8,19 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> let mut _4: usize; scope 1 (inlined #[track_caller] core::slice::::get_unchecked_mut::>) { let mut _5: *mut [u32]; - let mut _11: *mut [u32]; + let mut _13: *mut [u32]; scope 2 (inlined #[track_caller] as SliceIndex<[u32]>>::get_unchecked_mut) { let mut _6: usize; let _7: (); - let _8: usize; + let mut _8: usize; + let mut _9: bool; + let _10: usize; scope 3 { - scope 6 (inlined core::slice::index::get_offset_len_mut_noubcheck::) { - let _9: *mut u32; - scope 7 { - let _10: *mut u32; - scope 8 { + scope 8 (inlined core::slice::index::get_offset_len_mut_noubcheck::) { + let _11: *mut u32; + scope 9 { + let _12: *mut u32; + scope 10 { } } } @@ -27,16 +29,20 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> scope 5 (inlined std::ptr::metadata::<[u32]>) { } } + scope 6 (inlined std::ptr::mut_ptr::::len) { + scope 7 (inlined std::ptr::metadata::<[u32]>) { + } + } } } bb0: { _3 = move (_2.0: usize); _4 = move (_2.1: usize); - StorageLive(_11); + StorageLive(_13); StorageLive(_5); _5 = &raw mut (*_1); - StorageLive(_8); + StorageLive(_10); StorageLive(_6); _6 = PtrMetadata(copy _1); _7 = as SliceIndex<[T]>>::get_unchecked_mut::precondition_check(copy _3, copy _4, move _6) -> [return: bb1, unwind unreachable]; @@ -44,18 +50,25 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> bb1: { StorageDead(_6); - _8 = SubUnchecked(copy _4, copy _3); StorageLive(_9); - StorageLive(_10); - _9 = copy _5 as *mut u32 (PtrToPtr); - _10 = Offset(copy _9, copy _3); - _11 = *mut [u32] from (copy _10, copy _8); - StorageDead(_10); - StorageDead(_9); + StorageLive(_8); + _8 = PtrMetadata(copy _1); + _9 = Le(copy _4, move _8); StorageDead(_8); - StorageDead(_5); - _0 = &mut (*_11); + assume(move _9); + StorageDead(_9); + _10 = SubUnchecked(copy _4, copy _3); + StorageLive(_11); + StorageLive(_12); + _11 = copy _5 as *mut u32 (PtrToPtr); + _12 = Offset(copy _11, copy _3); + _13 = *mut [u32] from (copy _12, copy _10); + StorageDead(_12); StorageDead(_11); + StorageDead(_10); + StorageDead(_5); + _0 = &mut (*_13); + StorageDead(_13); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir index ad1ca5dff43a9..a6af079f3ff11 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir @@ -10,13 +10,15 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range) - scope 2 (inlined #[track_caller] as SliceIndex<[u32]>>::get_unchecked) { let mut _5: usize; let _6: (); - let _7: usize; + let mut _7: usize; + let mut _8: bool; + let _9: usize; scope 3 { - scope 6 (inlined core::slice::index::get_offset_len_noubcheck::) { - let _8: *const u32; - scope 7 { - let _9: *const u32; - scope 8 { + scope 8 (inlined core::slice::index::get_offset_len_noubcheck::) { + let _10: *const u32; + scope 9 { + let _11: *const u32; + scope 10 { } } } @@ -25,13 +27,17 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range) - scope 5 (inlined std::ptr::metadata::<[u32]>) { } } + scope 6 (inlined std::ptr::const_ptr::::len) { + scope 7 (inlined std::ptr::metadata::<[u32]>) { + } + } } } bb0: { _3 = move (_2.0: usize); _4 = move (_2.1: usize); - StorageLive(_7); + StorageLive(_9); StorageLive(_5); _5 = PtrMetadata(copy _1); _6 = as SliceIndex<[T]>>::get_unchecked::precondition_check(copy _3, copy _4, move _5) -> [return: bb1, unwind unreachable]; @@ -39,15 +45,22 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range) - bb1: { StorageDead(_5); - _7 = SubUnchecked(copy _4, copy _3); StorageLive(_8); - StorageLive(_9); - _8 = copy _1 as *const u32 (PtrToPtr); - _9 = Offset(copy _8, copy _3); - _0 = *const [u32] from (copy _9, copy _7); - StorageDead(_9); - StorageDead(_8); + StorageLive(_7); + _7 = PtrMetadata(copy _1); + _8 = Le(copy _4, move _7); StorageDead(_7); + assume(move _8); + StorageDead(_8); + _9 = SubUnchecked(copy _4, copy _3); + StorageLive(_10); + StorageLive(_11); + _10 = copy _1 as *const u32 (PtrToPtr); + _11 = Offset(copy _10, copy _3); + _0 = *const [u32] from (copy _11, copy _9); + StorageDead(_11); + StorageDead(_10); + StorageDead(_9); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir index ad1ca5dff43a9..a6af079f3ff11 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir @@ -10,13 +10,15 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range) - scope 2 (inlined #[track_caller] as SliceIndex<[u32]>>::get_unchecked) { let mut _5: usize; let _6: (); - let _7: usize; + let mut _7: usize; + let mut _8: bool; + let _9: usize; scope 3 { - scope 6 (inlined core::slice::index::get_offset_len_noubcheck::) { - let _8: *const u32; - scope 7 { - let _9: *const u32; - scope 8 { + scope 8 (inlined core::slice::index::get_offset_len_noubcheck::) { + let _10: *const u32; + scope 9 { + let _11: *const u32; + scope 10 { } } } @@ -25,13 +27,17 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range) - scope 5 (inlined std::ptr::metadata::<[u32]>) { } } + scope 6 (inlined std::ptr::const_ptr::::len) { + scope 7 (inlined std::ptr::metadata::<[u32]>) { + } + } } } bb0: { _3 = move (_2.0: usize); _4 = move (_2.1: usize); - StorageLive(_7); + StorageLive(_9); StorageLive(_5); _5 = PtrMetadata(copy _1); _6 = as SliceIndex<[T]>>::get_unchecked::precondition_check(copy _3, copy _4, move _5) -> [return: bb1, unwind unreachable]; @@ -39,15 +45,22 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range) - bb1: { StorageDead(_5); - _7 = SubUnchecked(copy _4, copy _3); StorageLive(_8); - StorageLive(_9); - _8 = copy _1 as *const u32 (PtrToPtr); - _9 = Offset(copy _8, copy _3); - _0 = *const [u32] from (copy _9, copy _7); - StorageDead(_9); - StorageDead(_8); + StorageLive(_7); + _7 = PtrMetadata(copy _1); + _8 = Le(copy _4, move _7); StorageDead(_7); + assume(move _8); + StorageDead(_8); + _9 = SubUnchecked(copy _4, copy _3); + StorageLive(_10); + StorageLive(_11); + _10 = copy _1 as *const u32 (PtrToPtr); + _11 = Offset(copy _10, copy _3); + _0 = *const [u32] from (copy _11, copy _9); + StorageDead(_11); + StorageDead(_10); + StorageDead(_9); return; } }