Skip to content

Use nuw when calculating slice lengths from Ranges #108763

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions library/core/src/slice/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use crate::intrinsics::assert_unsafe_precondition;
use crate::intrinsics::const_eval_select;
use crate::intrinsics::unchecked_sub;
use crate::ops;
use crate::ptr;

Expand Down Expand Up @@ -375,14 +376,15 @@ unsafe impl<T> const SliceIndex<[T]> for ops::Range<usize> {
// SAFETY: the caller guarantees that `slice` is not dangling, so it
// 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.
// so the call to `add` is safe and the length calculation cannot overflow.
unsafe {
assert_unsafe_precondition!(
"slice::get_unchecked requires that the range is within the slice",
[T](this: ops::Range<usize>, slice: *const [T]) =>
this.end >= this.start && this.end <= slice.len()
);
ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start)
let new_len = unchecked_sub(self.end, self.start);
ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), new_len)
}
}

Expand All @@ -396,7 +398,8 @@ unsafe impl<T> const SliceIndex<[T]> for ops::Range<usize> {
[T](this: ops::Range<usize>, slice: *mut [T]) =>
this.end >= this.start && this.end <= slice.len()
);
ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start)
let new_len = unchecked_sub(self.end, self.start);
ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), new_len)
}
}

Expand Down
35 changes: 35 additions & 0 deletions tests/codegen/slice-indexing.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// compile-flags: -O
// only-64bit (because the LLVM type of i64 for usize shows up)
// ignore-debug: the debug assertions get in the way

#![crate_type = "lib"]

use std::ops::Range;

// CHECK-LABEL: @index_by_range(
#[no_mangle]
pub fn index_by_range(x: &[u16], r: Range<usize>) -> &[u16] {
// CHECK: sub nuw i64
&x[r]
}

// CHECK-LABEL: @get_unchecked_by_range(
#[no_mangle]
pub unsafe fn get_unchecked_by_range(x: &[u16], r: Range<usize>) -> &[u16] {
// CHECK: sub nuw i64
x.get_unchecked(r)
}

// CHECK-LABEL: @index_mut_by_range(
#[no_mangle]
pub fn index_mut_by_range(x: &mut [i32], r: Range<usize>) -> &mut [i32] {
// CHECK: sub nuw i64
&mut x[r]
}

// CHECK-LABEL: @get_unchecked_mut_by_range(
#[no_mangle]
pub unsafe fn get_unchecked_mut_by_range(x: &mut [i32], r: Range<usize>) -> &mut [i32] {
// CHECK: sub nuw i64
x.get_unchecked_mut(r)
}
9 changes: 9 additions & 0 deletions tests/ui/consts/const-eval/ub-slice-get-unchecked.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#![feature(const_slice_index)]

const A: [(); 5] = [(), (), (), (), ()];

// Since the indexing is on a ZST, the addresses are all fine,
// but we should still catch the bad range.
const B: &[()] = unsafe { A.get_unchecked(3..1) };

fn main() {}
18 changes: 18 additions & 0 deletions tests/ui/consts/const-eval/ub-slice-get-unchecked.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/slice/index.rs:LL:COL
|
= note: overflow executing `unchecked_sub`
|
note: inside `<std::ops::Range<usize> as SliceIndex<[()]>>::get_unchecked`
--> $SRC_DIR/core/src/slice/index.rs:LL:COL
note: inside `core::slice::<impl [()]>::get_unchecked::<std::ops::Range<usize>>`
--> $SRC_DIR/core/src/slice/mod.rs:LL:COL
note: inside `B`
--> $DIR/ub-slice-get-unchecked.rs:7:27
|
LL | const B: &[()] = unsafe { A.get_unchecked(3..1) };
| ^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0080`.