Skip to content

Commit 09f8885

Browse files
committed
debug assertions for slice::split_at_unchecked, str::get_unchecked
1 parent 005fc0f commit 09f8885

File tree

3 files changed

+44
-35
lines changed

3 files changed

+44
-35
lines changed

library/core/src/slice/index.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -371,12 +371,11 @@ unsafe impl<T> const SliceIndex<[T]> for ops::Range<usize> {
371371

372372
#[inline]
373373
unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
374-
let this = ops::Range { start: self.start, end: self.end };
374+
let this = ops::Range { ..self };
375375
// SAFETY: the caller guarantees that `slice` is not dangling, so it
376376
// cannot be longer than `isize::MAX`. They also guarantee that
377377
// `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
378378
// so the call to `add` is safe.
379-
380379
unsafe {
381380
assert_unsafe_precondition!(
382381
"slice::get_unchecked requires that the range is within the slice",
@@ -389,7 +388,7 @@ unsafe impl<T> const SliceIndex<[T]> for ops::Range<usize> {
389388

390389
#[inline]
391390
unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
392-
let this = ops::Range { start: self.start, end: self.end };
391+
let this = ops::Range { ..self };
393392
// SAFETY: see comments for `get_unchecked` above.
394393
unsafe {
395394
assert_unsafe_precondition!(

library/core/src/slice/mod.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -1679,7 +1679,13 @@ impl<T> [T] {
16791679
let ptr = self.as_ptr();
16801680

16811681
// SAFETY: Caller has to check that `0 <= mid <= self.len()`
1682-
unsafe { (from_raw_parts(ptr, mid), from_raw_parts(ptr.add(mid), len - mid)) }
1682+
unsafe {
1683+
assert_unsafe_precondition!(
1684+
"slice::split_at_unchecked requires the index to be within the slice",
1685+
(mid: usize, len: usize) => mid <= len
1686+
);
1687+
(from_raw_parts(ptr, mid), from_raw_parts(ptr.add(mid), len - mid))
1688+
}
16831689
}
16841690

16851691
/// Divides one mutable slice into two at an index, without doing bounds checking.

library/core/src/str/traits.rs

+35-31
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Trait implementations for `str`.
22
33
use crate::cmp::Ordering;
4+
use crate::intrinsics::assert_unsafe_precondition;
45
use crate::ops;
56
use crate::ptr;
67
use crate::slice::SliceIndex;
@@ -198,15 +199,31 @@ unsafe impl const SliceIndex<str> for ops::Range<usize> {
198199
let slice = slice as *const [u8];
199200
// SAFETY: the caller guarantees that `self` is in bounds of `slice`
200201
// which satisfies all the conditions for `add`.
201-
let ptr = unsafe { slice.as_ptr().add(self.start) };
202+
let ptr = unsafe {
203+
let this = ops::Range { ..self };
204+
assert_unsafe_precondition!(
205+
"str::get_unchecked requires that the range is within the string slice",
206+
(this: ops::Range<usize>, slice: *const [u8]) =>
207+
this.end >= this.start && this.end <= slice.len()
208+
);
209+
slice.as_ptr().add(self.start)
210+
};
202211
let len = self.end - self.start;
203212
ptr::slice_from_raw_parts(ptr, len) as *const str
204213
}
205214
#[inline]
206215
unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
207216
let slice = slice as *mut [u8];
208217
// SAFETY: see comments for `get_unchecked`.
209-
let ptr = unsafe { slice.as_mut_ptr().add(self.start) };
218+
let ptr = unsafe {
219+
let this = ops::Range { ..self };
220+
assert_unsafe_precondition!(
221+
"str::get_unchecked_mut requires that the range is within the string slice",
222+
(this: ops::Range<usize>, slice: *mut [u8]) =>
223+
this.end >= this.start && this.end <= slice.len()
224+
);
225+
slice.as_mut_ptr().add(self.start)
226+
};
210227
let len = self.end - self.start;
211228
ptr::slice_from_raw_parts_mut(ptr, len) as *mut str
212229
}
@@ -276,15 +293,13 @@ unsafe impl const SliceIndex<str> for ops::RangeTo<usize> {
276293
}
277294
#[inline]
278295
unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
279-
let slice = slice as *const [u8];
280-
let ptr = slice.as_ptr();
281-
ptr::slice_from_raw_parts(ptr, self.end) as *const str
296+
// SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
297+
unsafe { (0..self.end).get_unchecked(slice) }
282298
}
283299
#[inline]
284300
unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
285-
let slice = slice as *mut [u8];
286-
let ptr = slice.as_mut_ptr();
287-
ptr::slice_from_raw_parts_mut(ptr, self.end) as *mut str
301+
// SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
302+
unsafe { (0..self.end).get_unchecked_mut(slice) }
288303
}
289304
#[inline]
290305
fn index(self, slice: &str) -> &Self::Output {
@@ -347,20 +362,15 @@ unsafe impl const SliceIndex<str> for ops::RangeFrom<usize> {
347362
}
348363
#[inline]
349364
unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
350-
let slice = slice as *const [u8];
351-
// SAFETY: the caller guarantees that `self` is in bounds of `slice`
352-
// which satisfies all the conditions for `add`.
353-
let ptr = unsafe { slice.as_ptr().add(self.start) };
354-
let len = slice.len() - self.start;
355-
ptr::slice_from_raw_parts(ptr, len) as *const str
365+
let len = (slice as *const [u8]).len();
366+
// SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
367+
unsafe { (self.start..len).get_unchecked(slice) }
356368
}
357369
#[inline]
358370
unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
359-
let slice = slice as *mut [u8];
360-
// SAFETY: identical to `get_unchecked`.
361-
let ptr = unsafe { slice.as_mut_ptr().add(self.start) };
362-
let len = slice.len() - self.start;
363-
ptr::slice_from_raw_parts_mut(ptr, len) as *mut str
371+
let len = (slice as *mut [u8]).len();
372+
// SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
373+
unsafe { (self.start..len).get_unchecked_mut(slice) }
364374
}
365375
#[inline]
366376
fn index(self, slice: &str) -> &Self::Output {
@@ -456,35 +466,29 @@ unsafe impl const SliceIndex<str> for ops::RangeToInclusive<usize> {
456466
type Output = str;
457467
#[inline]
458468
fn get(self, slice: &str) -> Option<&Self::Output> {
459-
if self.end == usize::MAX { None } else { (..self.end + 1).get(slice) }
469+
(0..=self.end).get(slice)
460470
}
461471
#[inline]
462472
fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
463-
if self.end == usize::MAX { None } else { (..self.end + 1).get_mut(slice) }
473+
(0..=self.end).get_mut(slice)
464474
}
465475
#[inline]
466476
unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output {
467477
// SAFETY: the caller must uphold the safety contract for `get_unchecked`.
468-
unsafe { (..self.end + 1).get_unchecked(slice) }
478+
unsafe { (0..=self.end).get_unchecked(slice) }
469479
}
470480
#[inline]
471481
unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output {
472482
// SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`.
473-
unsafe { (..self.end + 1).get_unchecked_mut(slice) }
483+
unsafe { (0..=self.end).get_unchecked_mut(slice) }
474484
}
475485
#[inline]
476486
fn index(self, slice: &str) -> &Self::Output {
477-
if self.end == usize::MAX {
478-
str_index_overflow_fail();
479-
}
480-
(..self.end + 1).index(slice)
487+
(0..=self.end).index(slice)
481488
}
482489
#[inline]
483490
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
484-
if self.end == usize::MAX {
485-
str_index_overflow_fail();
486-
}
487-
(..self.end + 1).index_mut(slice)
491+
(0..=self.end).index_mut(slice)
488492
}
489493
}
490494

0 commit comments

Comments
 (0)