Skip to content

Commit 9adc058

Browse files
committed
Consolidate panicking functions in slice/index.rs
Consolidate all the panicking functions in `slice/index.rs` to use a single `slice_index_fail` function, similar to how it is done in `str/traits.rs`.
1 parent ffb9d94 commit 9adc058

File tree

10 files changed

+180
-128
lines changed

10 files changed

+180
-128
lines changed

library/core/src/slice/index.rs

Lines changed: 87 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -34,53 +34,44 @@ where
3434
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
3535
#[cfg_attr(feature = "panic_immediate_abort", inline)]
3636
#[track_caller]
37-
const fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
38-
const_panic!(
39-
"slice start index is out of range for slice",
40-
"range start index {index} out of range for slice of length {len}",
41-
index: usize,
42-
len: usize,
43-
)
44-
}
37+
const fn slice_index_fail(start: usize, end: usize, len: usize) -> ! {
38+
if start > len {
39+
const_panic!(
40+
"slice start index is out of range for slice",
41+
"range start index {start} out of range for slice of length {len}",
42+
start: usize,
43+
len: usize,
44+
)
45+
}
4546

46-
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
47-
#[cfg_attr(feature = "panic_immediate_abort", inline)]
48-
#[track_caller]
49-
const fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
50-
const_panic!(
51-
"slice end index is out of range for slice",
52-
"range end index {index} out of range for slice of length {len}",
53-
index: usize,
54-
len: usize,
55-
)
56-
}
47+
if end > len {
48+
const_panic!(
49+
"slice end index is out of range for slice",
50+
"range end index {end} out of range for slice of length {len}",
51+
end: usize,
52+
len: usize,
53+
)
54+
}
5755

58-
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
59-
#[cfg_attr(feature = "panic_immediate_abort", inline)]
60-
#[track_caller]
61-
const fn slice_index_order_fail(index: usize, end: usize) -> ! {
56+
if start > end {
57+
const_panic!(
58+
"slice index start is larger than end",
59+
"slice index starts at {start} but ends at {end}",
60+
start: usize,
61+
end: usize,
62+
)
63+
}
64+
65+
// Only reachable if the range was a `RangeInclusive` or a
66+
// `RangeToInclusive`, with `end == len`.
6267
const_panic!(
63-
"slice index start is larger than end",
64-
"slice index starts at {index} but ends at {end}",
65-
index: usize,
68+
"slice end index is out of range for slice",
69+
"range end index {end} out of range for slice of length {len}",
6670
end: usize,
71+
len: usize,
6772
)
6873
}
6974

70-
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
71-
#[cfg_attr(feature = "panic_immediate_abort", inline)]
72-
#[track_caller]
73-
const fn slice_start_index_overflow_fail() -> ! {
74-
panic!("attempted to index slice from after maximum usize");
75-
}
76-
77-
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
78-
#[cfg_attr(feature = "panic_immediate_abort", inline)]
79-
#[track_caller]
80-
const fn slice_end_index_overflow_fail() -> ! {
81-
panic!("attempted to index slice up to maximum usize");
82-
}
83-
8475
// The UbChecks are great for catching bugs in the unsafe methods, but including
8576
// them in safe indexing is unnecessary and hurts inlining and debug runtime perf.
8677
// Both the safe and unsafe public methods share these helpers,
@@ -341,7 +332,7 @@ unsafe impl<T> const SliceIndex<[T]> for ops::IndexRange {
341332
// SAFETY: `self` is checked to be valid and in bounds above.
342333
unsafe { &*get_offset_len_noubcheck(slice, self.start(), self.len()) }
343334
} else {
344-
slice_end_index_len_fail(self.end(), slice.len())
335+
slice_index_fail(self.start(), self.end(), slice.len())
345336
}
346337
}
347338

@@ -351,7 +342,7 @@ unsafe impl<T> const SliceIndex<[T]> for ops::IndexRange {
351342
// SAFETY: `self` is checked to be valid and in bounds above.
352343
unsafe { &mut *get_offset_len_mut_noubcheck(slice, self.start(), self.len()) }
353344
} else {
354-
slice_end_index_len_fail(self.end(), slice.len())
345+
slice_index_fail(self.start(), self.end(), slice.len())
355346
}
356347
}
357348
}
@@ -436,26 +427,27 @@ unsafe impl<T> const SliceIndex<[T]> for ops::Range<usize> {
436427
#[inline(always)]
437428
fn index(self, slice: &[T]) -> &[T] {
438429
// Using checked_sub is a safe way to get `SubUnchecked` in MIR
439-
let Some(new_len) = usize::checked_sub(self.end, self.start) else {
440-
slice_index_order_fail(self.start, self.end)
441-
};
442-
if self.end > slice.len() {
443-
slice_end_index_len_fail(self.end, slice.len());
430+
if let Some(new_len) = usize::checked_sub(self.end, self.start)
431+
&& self.end <= slice.len()
432+
{
433+
// SAFETY: `self` is checked to be valid and in bounds above.
434+
unsafe { &*get_offset_len_noubcheck(slice, self.start, new_len) }
435+
} else {
436+
slice_index_fail(self.start, self.end, slice.len())
444437
}
445-
// SAFETY: `self` is checked to be valid and in bounds above.
446-
unsafe { &*get_offset_len_noubcheck(slice, self.start, new_len) }
447438
}
448439

449440
#[inline]
450441
fn index_mut(self, slice: &mut [T]) -> &mut [T] {
451-
let Some(new_len) = usize::checked_sub(self.end, self.start) else {
452-
slice_index_order_fail(self.start, self.end)
453-
};
454-
if self.end > slice.len() {
455-
slice_end_index_len_fail(self.end, slice.len());
442+
// Using checked_sub is a safe way to get `SubUnchecked` in MIR
443+
if let Some(new_len) = usize::checked_sub(self.end, self.start)
444+
&& self.end <= slice.len()
445+
{
446+
// SAFETY: `self` is checked to be valid and in bounds above.
447+
unsafe { &mut *get_offset_len_mut_noubcheck(slice, self.start, new_len) }
448+
} else {
449+
slice_index_fail(self.start, self.end, slice.len())
456450
}
457-
// SAFETY: `self` is checked to be valid and in bounds above.
458-
unsafe { &mut *get_offset_len_mut_noubcheck(slice, self.start, new_len) }
459451
}
460452
}
461453

@@ -567,7 +559,7 @@ unsafe impl<T> const SliceIndex<[T]> for ops::RangeFrom<usize> {
567559
#[inline]
568560
fn index(self, slice: &[T]) -> &[T] {
569561
if self.start > slice.len() {
570-
slice_start_index_len_fail(self.start, slice.len());
562+
slice_index_fail(self.start, slice.len(), slice.len())
571563
}
572564
// SAFETY: `self` is checked to be valid and in bounds above.
573565
unsafe { &*self.get_unchecked(slice) }
@@ -576,7 +568,7 @@ unsafe impl<T> const SliceIndex<[T]> for ops::RangeFrom<usize> {
576568
#[inline]
577569
fn index_mut(self, slice: &mut [T]) -> &mut [T] {
578570
if self.start > slice.len() {
579-
slice_start_index_len_fail(self.start, slice.len());
571+
slice_index_fail(self.start, slice.len(), slice.len())
580572
}
581573
// SAFETY: `self` is checked to be valid and in bounds above.
582574
unsafe { &mut *self.get_unchecked_mut(slice) }
@@ -690,16 +682,16 @@ unsafe impl<T> const SliceIndex<[T]> for ops::RangeInclusive<usize> {
690682

691683
#[inline]
692684
fn index(self, slice: &[T]) -> &[T] {
693-
if *self.end() == usize::MAX {
694-
slice_end_index_overflow_fail();
685+
if *self.end() >= slice.len() {
686+
slice_index_fail(self.start, self.end, slice.len())
695687
}
696688
self.into_slice_range().index(slice)
697689
}
698690

699691
#[inline]
700692
fn index_mut(self, slice: &mut [T]) -> &mut [T] {
701-
if *self.end() == usize::MAX {
702-
slice_end_index_overflow_fail();
693+
if *self.end() >= slice.len() {
694+
slice_index_fail(self.start, self.end, slice.len())
703695
}
704696
self.into_slice_range().index_mut(slice)
705697
}
@@ -852,28 +844,26 @@ where
852844
{
853845
let len = bounds.end;
854846

855-
let start = match range.start_bound() {
856-
ops::Bound::Included(&start) => start,
857-
ops::Bound::Excluded(start) => {
858-
start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail())
859-
}
860-
ops::Bound::Unbounded => 0,
861-
};
862-
863847
let end = match range.end_bound() {
864-
ops::Bound::Included(end) => {
865-
end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail())
866-
}
848+
ops::Bound::Included(&end) if end >= len => slice_index_fail(0, end, len),
849+
// Cannot overflow because `end < len` implies `end < usize::MAX`.
850+
ops::Bound::Included(&end) => end + 1,
851+
852+
ops::Bound::Excluded(&end) if end > len => slice_index_fail(0, end, len),
867853
ops::Bound::Excluded(&end) => end,
868854
ops::Bound::Unbounded => len,
869855
};
870856

871-
if start > end {
872-
slice_index_order_fail(start, end);
873-
}
874-
if end > len {
875-
slice_end_index_len_fail(end, len);
876-
}
857+
let start = match range.start_bound() {
858+
ops::Bound::Excluded(&start) if start >= end => slice_index_fail(start, end, len),
859+
// Cannot overflow because `start < end` implies `start < usize::MAX`.
860+
ops::Bound::Excluded(&start) => start + 1,
861+
862+
ops::Bound::Included(&start) if start > end => slice_index_fail(start, end, len),
863+
ops::Bound::Included(&start) => start,
864+
865+
ops::Bound::Unbounded => 0,
866+
};
877867

878868
ops::Range { start, end }
879869
}
@@ -982,25 +972,27 @@ pub(crate) fn into_slice_range(
982972
len: usize,
983973
(start, end): (ops::Bound<usize>, ops::Bound<usize>),
984974
) -> ops::Range<usize> {
985-
use ops::Bound;
986-
let start = match start {
987-
Bound::Included(start) => start,
988-
Bound::Excluded(start) => {
989-
start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail())
990-
}
991-
Bound::Unbounded => 0,
992-
};
993-
994975
let end = match end {
995-
Bound::Included(end) => {
996-
end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail())
997-
}
998-
Bound::Excluded(end) => end,
999-
Bound::Unbounded => len,
976+
ops::Bound::Included(end) if end >= len => slice_index_fail(0, end, len),
977+
// Cannot overflow because `end < len` implies `end < usize::MAX`.
978+
ops::Bound::Included(end) => end + 1,
979+
980+
ops::Bound::Excluded(end) if end > len => slice_index_fail(0, end, len),
981+
ops::Bound::Excluded(end) => end,
982+
983+
ops::Bound::Unbounded => len,
1000984
};
1001985

1002-
// Don't bother with checking `start < end` and `end <= len`
1003-
// since these checks are handled by `Range` impls
986+
let start = match start {
987+
ops::Bound::Excluded(start) if start >= end => slice_index_fail(start, end, len),
988+
// Cannot overflow because `start < end` implies `start < usize::MAX`.
989+
ops::Bound::Excluded(start) => start + 1,
990+
991+
ops::Bound::Included(start) if start > end => slice_index_fail(start, end, len),
992+
ops::Bound::Included(start) => start,
993+
994+
ops::Bound::Unbounded => 0,
995+
};
1004996

1005997
start..end
1006998
}

library/coretests/tests/slice.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1492,28 +1492,28 @@ mod slice_index {
14921492
// note: using 0 specifically ensures that the result of overflowing is 0..0,
14931493
// so that `get` doesn't simply return None for the wrong reason.
14941494
bad: data[0 ..= usize::MAX];
1495-
message: "maximum usize";
1495+
message: "out of range";
14961496
}
14971497

14981498
in mod rangetoinclusive_overflow {
14991499
data: [0, 1];
15001500

15011501
bad: data[..= usize::MAX];
1502-
message: "maximum usize";
1502+
message: "out of range";
15031503
}
15041504

15051505
in mod boundpair_overflow_end {
15061506
data: [0; 1];
15071507

15081508
bad: data[(Bound::Unbounded, Bound::Included(usize::MAX))];
1509-
message: "maximum usize";
1509+
message: "out of range";
15101510
}
15111511

15121512
in mod boundpair_overflow_start {
15131513
data: [0; 1];
15141514

15151515
bad: data[(Bound::Excluded(usize::MAX), Bound::Unbounded)];
1516-
message: "maximum usize";
1516+
message: "out of range";
15171517
}
15181518
} // panic_cases!
15191519
}
@@ -2008,7 +2008,7 @@ fn test_copy_within_panics_src_inverted() {
20082008
bytes.copy_within(2..1, 0);
20092009
}
20102010
#[test]
2011-
#[should_panic(expected = "attempted to index slice up to maximum usize")]
2011+
#[should_panic(expected = "out of range")]
20122012
fn test_copy_within_panics_src_out_of_bounds() {
20132013
let mut bytes = *b"Hello, World!";
20142014
// an inclusive range ending at usize::MAX would make src_end overflow
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
thread 'main' ($TID) panicked at tests/panic/oob_subslice.rs:LL:CC:
3-
range end index 5 out of range for slice of length 4
2+
thread 'main' panicked at tests/panic/oob_subslice.rs:LL:CC:
3+
range end index 4 out of range for slice of length 4
44
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
55
note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect

tests/codegen-llvm/binary-search-index-no-bound-check.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@
88
#[no_mangle]
99
pub fn binary_search_index_no_bounds_check(s: &[u8]) -> u8 {
1010
// CHECK-NOT: panic
11-
// CHECK-NOT: slice_start_index_len_fail
12-
// CHECK-NOT: slice_end_index_len_fail
11+
// CHECK-NOT: slice_index_fail
1312
// CHECK-NOT: panic_bounds_check
1413
if let Ok(idx) = s.binary_search(&b'\\') { s[idx] } else { 42 }
1514
}

tests/codegen-llvm/integer-overflow.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ pub struct S1<'a> {
1010
// CHECK-LABEL: @slice_no_index_order
1111
#[no_mangle]
1212
pub fn slice_no_index_order<'a>(s: &'a mut S1, n: usize) -> &'a [u8] {
13-
// CHECK-NOT: slice_index_order_fail
13+
// CHECK-TIMES 1: slice_index_fail
1414
let d = &s.data[s.position..s.position + n];
1515
s.position += n;
1616
return d;
@@ -19,6 +19,6 @@ pub fn slice_no_index_order<'a>(s: &'a mut S1, n: usize) -> &'a [u8] {
1919
// CHECK-LABEL: @test_check
2020
#[no_mangle]
2121
pub fn test_check<'a>(s: &'a mut S1, x: usize, y: usize) -> &'a [u8] {
22-
// CHECK: slice_index_order_fail
22+
// CHECK-TIMES 1: slice_index_fail
2323
&s.data[x..y]
2424
}

tests/codegen-llvm/issues/issue-27130.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#[no_mangle]
77
pub fn trim_in_place(a: &mut &[u8]) {
88
while a.first() == Some(&42) {
9-
// CHECK-NOT: slice_index_order_fail
9+
// CHECK-TIMES 1: slice_index_fail
1010
*a = &a[1..];
1111
}
1212
}
@@ -15,7 +15,7 @@ pub fn trim_in_place(a: &mut &[u8]) {
1515
#[no_mangle]
1616
pub fn trim_in_place2(a: &mut &[u8]) {
1717
while let Some(&42) = a.first() {
18-
// CHECK-NOT: slice_index_order_fail
18+
// CHECK-TIMES 1: slice_index_fail
1919
*a = &a[2..];
2020
}
2121
}

tests/codegen-llvm/issues/issue-69101-bounds-check.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
// CHECK-LABEL: @already_sliced_no_bounds_check
1111
#[no_mangle]
1212
pub fn already_sliced_no_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) {
13-
// CHECK: slice_end_index_len_fail
13+
// CHECK: slice_index_fail
1414
// CHECK-NOT: panic_bounds_check
1515
let _ = (&a[..2048], &b[..2048], &mut c[..2048]);
1616
for i in 0..1024 {
@@ -21,7 +21,7 @@ pub fn already_sliced_no_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) {
2121
// CHECK-LABEL: @already_sliced_no_bounds_check_exact
2222
#[no_mangle]
2323
pub fn already_sliced_no_bounds_check_exact(a: &[u8], b: &[u8], c: &mut [u8]) {
24-
// CHECK: slice_end_index_len_fail
24+
// CHECK: slice_index_fail
2525
// CHECK-NOT: panic_bounds_check
2626
let _ = (&a[..1024], &b[..1024], &mut c[..1024]);
2727
for i in 0..1024 {
@@ -33,7 +33,7 @@ pub fn already_sliced_no_bounds_check_exact(a: &[u8], b: &[u8], c: &mut [u8]) {
3333
// CHECK-LABEL: @already_sliced_bounds_check
3434
#[no_mangle]
3535
pub fn already_sliced_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) {
36-
// CHECK: slice_end_index_len_fail
36+
// CHECK: slice_index_fail
3737
// CHECK: panic_bounds_check
3838
let _ = (&a[..1023], &b[..2048], &mut c[..2048]);
3939
for i in 0..1024 {

0 commit comments

Comments
 (0)