Skip to content

Commit a4095ca

Browse files
Document unsafety in src/libcore/slice/mod.rs
1 parent 1557fb0 commit a4095ca

File tree

1 file changed

+94
-10
lines changed

1 file changed

+94
-10
lines changed

src/libcore/slice/mod.rs

+94-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
// ignore-tidy-filelength
2-
// ignore-tidy-undocumented-unsafe
32

43
//! Slice management and manipulation.
54
//!
@@ -70,6 +69,8 @@ impl<T> [T] {
7069
#[allow(unused_attributes)]
7170
#[allow_internal_unstable(const_fn_union)]
7271
pub const fn len(&self) -> usize {
72+
// SAFETY: this is safe because `&[T]` and `FatPtr<T>` have the same layout.
73+
// Only `std` can make this guarantee.
7374
unsafe { crate::ptr::Repr { rust: self }.raw.len }
7475
}
7576

@@ -437,7 +438,8 @@ impl<T> [T] {
437438
#[unstable(feature = "slice_ptr_range", issue = "65807")]
438439
#[inline]
439440
pub fn as_ptr_range(&self) -> Range<*const T> {
440-
// The `add` here is safe, because:
441+
let start = self.as_ptr();
442+
// SAFETY: The `add` here is safe, because:
441443
//
442444
// - Both pointers are part of the same object, as pointing directly
443445
// past the object also counts.
@@ -454,7 +456,6 @@ impl<T> [T] {
454456
// the end of the address space.
455457
//
456458
// See the documentation of pointer::add.
457-
let start = self.as_ptr();
458459
let end = unsafe { start.add(self.len()) };
459460
start..end
460461
}
@@ -478,8 +479,8 @@ impl<T> [T] {
478479
#[unstable(feature = "slice_ptr_range", issue = "65807")]
479480
#[inline]
480481
pub fn as_mut_ptr_range(&mut self) -> Range<*mut T> {
481-
// See as_ptr_range() above for why `add` here is safe.
482482
let start = self.as_mut_ptr();
483+
// SAFETY: See as_ptr_range() above for why `add` here is safe.
483484
let end = unsafe { start.add(self.len()) };
484485
start..end
485486
}
@@ -505,6 +506,8 @@ impl<T> [T] {
505506
#[stable(feature = "rust1", since = "1.0.0")]
506507
#[inline]
507508
pub fn swap(&mut self, a: usize, b: usize) {
509+
// SAFETY: `pa` and `pb` have been created from safe mutable references and refer
510+
// to elements in the slice and therefore are guaranteed to be valid and aligned.
508511
unsafe {
509512
// Can't take two mutable loans from one vector, so instead just cast
510513
// them to their raw pointers to do the swap
@@ -548,6 +551,10 @@ impl<T> [T] {
548551
// Use the llvm.bswap intrinsic to reverse u8s in a usize
549552
let chunk = mem::size_of::<usize>();
550553
while i + chunk - 1 < ln / 2 {
554+
// SAFETY: the condition of the `while` guarantees that
555+
// `i` and `ln - i - chunk` are inside the slice.
556+
// The resulting pointers `pa` and `pb` are therefore valid,
557+
// and can be read from and written to.
551558
unsafe {
552559
let pa: *mut T = self.get_unchecked_mut(i);
553560
let pb: *mut T = self.get_unchecked_mut(ln - i - chunk);
@@ -564,6 +571,10 @@ impl<T> [T] {
564571
// Use rotate-by-16 to reverse u16s in a u32
565572
let chunk = mem::size_of::<u32>() / 2;
566573
while i + chunk - 1 < ln / 2 {
574+
// SAFETY: the condition of the `while` guarantees that
575+
// `i` and `ln - i - chunk` are inside the slice.
576+
// The resulting pointers `pa` and `pb` are therefore valid,
577+
// and can be read from and written to.
567578
unsafe {
568579
let pa: *mut T = self.get_unchecked_mut(i);
569580
let pb: *mut T = self.get_unchecked_mut(ln - i - chunk);
@@ -577,8 +588,12 @@ impl<T> [T] {
577588
}
578589

579590
while i < ln / 2 {
580-
// Unsafe swap to avoid the bounds check in safe swap.
591+
// SAFETY: the condition of the `while` guarantees that `i` and `ln - i - 1`
592+
// are inside the slice and refer to an element inside the slice.
593+
// The resulting pointers `pa` and `pb` are therefore valid and aligned,
594+
// and can be read from and written to.
581595
unsafe {
596+
// Unsafe swap to avoid the bounds check in safe swap.
582597
let pa: *mut T = self.get_unchecked_mut(i);
583598
let pb: *mut T = self.get_unchecked_mut(ln - i - 1);
584599
ptr::swap(pa, pb);
@@ -603,6 +618,9 @@ impl<T> [T] {
603618
#[stable(feature = "rust1", since = "1.0.0")]
604619
#[inline]
605620
pub fn iter(&self) -> Iter<'_, T> {
621+
// SAFETY: adding `self.len()` to the starting pointer gives a pointer
622+
// at the end of `self`, which fulfills the expectations of `ptr.add()`
623+
// and `NonNull::new_unchecked()`.
606624
unsafe {
607625
let ptr = self.as_ptr();
608626
assume(!ptr.is_null());
@@ -631,6 +649,9 @@ impl<T> [T] {
631649
#[stable(feature = "rust1", since = "1.0.0")]
632650
#[inline]
633651
pub fn iter_mut(&mut self) -> IterMut<'_, T> {
652+
// SAFETY: adding `self.len()` to the starting pointer gives a pointer
653+
// at the end of `self`, which fulfills the expectations of `ptr.add()`
654+
// and `NonNull::new_unchecked()`.
634655
unsafe {
635656
let ptr = self.as_mut_ptr();
636657
assume(!ptr.is_null());
@@ -1062,6 +1083,8 @@ impl<T> [T] {
10621083
let len = self.len();
10631084
let ptr = self.as_mut_ptr();
10641085

1086+
// SAFETY: `[ptr;mid]` and `[mid;len]` are inside `self`, which fulfills the
1087+
// requirements of `from_raw_parts_mut`.
10651088
unsafe {
10661089
assert!(mid <= len);
10671090

@@ -1548,14 +1571,14 @@ impl<T> [T] {
15481571
while size > 1 {
15491572
let half = size / 2;
15501573
let mid = base + half;
1551-
// mid is always in [0, size), that means mid is >= 0 and < size.
1574+
// SAFETY: mid is always in [0, size), that means mid is >= 0 and < size.
15521575
// mid >= 0: by definition
15531576
// mid < size: mid = size / 2 + size / 4 + size / 8 ...
15541577
let cmp = f(unsafe { s.get_unchecked(mid) });
15551578
base = if cmp == Greater { base } else { mid };
15561579
size -= half;
15571580
}
1558-
// base is always in [0, size) because base <= mid.
1581+
// SAFETY: base is always in [0, size) because base <= mid.
15591582
let cmp = f(unsafe { s.get_unchecked(base) });
15601583
if cmp == Equal { Ok(base) } else { Err(base + (cmp == Less) as usize) }
15611584
}
@@ -2013,6 +2036,13 @@ impl<T> [T] {
20132036
let mut next_read: usize = 1;
20142037
let mut next_write: usize = 1;
20152038

2039+
// SAFETY: the `while` condition guarantees `next_read` and `next_write`
2040+
// are less than `len`, thus are inside `self`. `prev_ptr_write` points to
2041+
// one element before `ptr_write`, but `next_write` starts at 1, so
2042+
// `prev_ptr_write` is never less than 0 and is inside the slice.
2043+
// This fulfils the requirements for dereferencing `ptr_read`, `prev_ptr_write`
2044+
// and `ptr_write`, and for using `ptr.add(next_read)`, `ptr.add(next_write - 1)`
2045+
// and `prev_ptr_write.offset(1)`.
20162046
unsafe {
20172047
// Avoid bounds checks by using raw pointers.
20182048
while next_read < len {
@@ -2097,6 +2127,8 @@ impl<T> [T] {
20972127
assert!(mid <= self.len());
20982128
let k = self.len() - mid;
20992129

2130+
// SAFETY: `[mid - mid;mid+k]` corresponds to the entire
2131+
// `self` slice, thus is valid for reads and writes.
21002132
unsafe {
21012133
let p = self.as_mut_ptr();
21022134
rotate::ptr_rotate(mid, p.add(mid), k);
@@ -2138,6 +2170,8 @@ impl<T> [T] {
21382170
assert!(k <= self.len());
21392171
let mid = self.len() - k;
21402172

2173+
// SAFETY: `[mid - mid;mid+k]` corresponds to the entire
2174+
// `self` slice, thus is valid for reads and writes.
21412175
unsafe {
21422176
let p = self.as_mut_ptr();
21432177
rotate::ptr_rotate(mid, p.add(mid), k);
@@ -2300,6 +2334,9 @@ impl<T> [T] {
23002334
T: Copy,
23012335
{
23022336
assert_eq!(self.len(), src.len(), "destination and source slices have different lengths");
2337+
// SAFETY: `self` is valid for `self.len()` bytes by definition, and `src` was
2338+
// checked to have the same length. Both slices cannot be overlapping because
2339+
// Rust's mutable references are exclusive.
23032340
unsafe {
23042341
ptr::copy_nonoverlapping(src.as_ptr(), self.as_mut_ptr(), self.len());
23052342
}
@@ -2353,6 +2390,7 @@ impl<T> [T] {
23532390
assert!(src_end <= self.len(), "src is out of bounds");
23542391
let count = src_end - src_start;
23552392
assert!(dest <= self.len() - count, "dest is out of bounds");
2393+
// SAFETY: the conditions for `ptr::copy` have been checked above.
23562394
unsafe {
23572395
ptr::copy(self.as_ptr().add(src_start), self.as_mut_ptr().add(dest), count);
23582396
}
@@ -2408,6 +2446,9 @@ impl<T> [T] {
24082446
#[stable(feature = "swap_with_slice", since = "1.27.0")]
24092447
pub fn swap_with_slice(&mut self, other: &mut [T]) {
24102448
assert!(self.len() == other.len(), "destination and source slices have different lengths");
2449+
// SAFETY: `self` is valid for `self.len()` bytes by definition, and `src` was
2450+
// checked to have the same length. Both slices cannot be overlapping because
2451+
// Rust's mutable references are exclusive.
24112452
unsafe {
24122453
ptr::swap_nonoverlapping(self.as_mut_ptr(), other.as_mut_ptr(), self.len());
24132454
}
@@ -2439,6 +2480,8 @@ impl<T> [T] {
24392480
// iterative stein’s algorithm
24402481
// We should still make this `const fn` (and revert to recursive algorithm if we do)
24412482
// because relying on llvm to consteval all this is… well, it makes me uncomfortable.
2483+
2484+
// SAFETY: `a` and `b` are checked to be non-zero values.
24422485
let (ctz_a, mut ctz_b) = unsafe {
24432486
if a == 0 {
24442487
return b;
@@ -2458,6 +2501,7 @@ impl<T> [T] {
24582501
mem::swap(&mut a, &mut b);
24592502
}
24602503
b = b - a;
2504+
// SAFETY: `b` is checked to be non-zero.
24612505
unsafe {
24622506
if b == 0 {
24632507
break;
@@ -2848,11 +2892,13 @@ impl<T> SliceIndex<[T]> for usize {
28482892

28492893
#[inline]
28502894
fn get(self, slice: &[T]) -> Option<&T> {
2895+
// SAFETY: `self` is checked to be in bounds.
28512896
if self < slice.len() { unsafe { Some(self.get_unchecked(slice)) } } else { None }
28522897
}
28532898

28542899
#[inline]
28552900
fn get_mut(self, slice: &mut [T]) -> Option<&mut T> {
2901+
// SAFETY: `self` is checked to be in bounds.
28562902
if self < slice.len() { unsafe { Some(self.get_unchecked_mut(slice)) } } else { None }
28572903
}
28582904

@@ -2888,6 +2934,7 @@ impl<T> SliceIndex<[T]> for ops::Range<usize> {
28882934
if self.start > self.end || self.end > slice.len() {
28892935
None
28902936
} else {
2937+
// SAFETY: `self` is checked to be valid and in bounds above.
28912938
unsafe { Some(self.get_unchecked(slice)) }
28922939
}
28932940
}
@@ -2897,6 +2944,7 @@ impl<T> SliceIndex<[T]> for ops::Range<usize> {
28972944
if self.start > self.end || self.end > slice.len() {
28982945
None
28992946
} else {
2947+
// SAFETY: `self` is checked to be valid and in bounds above.
29002948
unsafe { Some(self.get_unchecked_mut(slice)) }
29012949
}
29022950
}
@@ -2918,6 +2966,7 @@ impl<T> SliceIndex<[T]> for ops::Range<usize> {
29182966
} else if self.end > slice.len() {
29192967
slice_index_len_fail(self.end, slice.len());
29202968
}
2969+
// SAFETY: `self` is checked to be valid and in bounds above.
29212970
unsafe { self.get_unchecked(slice) }
29222971
}
29232972

@@ -2928,6 +2977,7 @@ impl<T> SliceIndex<[T]> for ops::Range<usize> {
29282977
} else if self.end > slice.len() {
29292978
slice_index_len_fail(self.end, slice.len());
29302979
}
2980+
// SAFETY: `self` is checked to be valid and in bounds above.
29312981
unsafe { self.get_unchecked_mut(slice) }
29322982
}
29332983
}
@@ -3239,6 +3289,8 @@ macro_rules! iterator {
32393289
// Helper function for creating a slice from the iterator.
32403290
#[inline(always)]
32413291
fn make_slice(&self) -> &'a [T] {
3292+
// SAFETY: the iterator was created from a slice with pointer `self.ptr` and length `len!(self)`.
3293+
// This guarantees that all the prerequisites for `from_raw_parts` are fulfilled.
32423294
unsafe { from_raw_parts(self.ptr.as_ptr(), len!(self)) }
32433295
}
32443296

@@ -3292,6 +3344,10 @@ macro_rules! iterator {
32923344
#[inline]
32933345
fn next(&mut self) -> Option<$elem> {
32943346
// could be implemented with slices, but this avoids bounds checks
3347+
3348+
// SAFETY: `assume` calls are safe since a slice's start pointer must be non-null,
3349+
// and slices over non-ZSTs must also have a non-null end pointer.
3350+
// The call to `next_unchecked!` is safe since we check if the iterator is empty first.
32953351
unsafe {
32963352
assume(!self.ptr.as_ptr().is_null());
32973353
if mem::size_of::<T>() != 0 {
@@ -3325,14 +3381,14 @@ macro_rules! iterator {
33253381
// could be (due to wrapping).
33263382
self.end = self.ptr.as_ptr();
33273383
} else {
3384+
// SAFETY: end can't be 0 if T isn't ZST because ptr isn't 0 and end >= ptr
33283385
unsafe {
3329-
// End can't be 0 if T isn't ZST because ptr isn't 0 and end >= ptr
33303386
self.ptr = NonNull::new_unchecked(self.end as *mut T);
33313387
}
33323388
}
33333389
return None;
33343390
}
3335-
// We are in bounds. `post_inc_start` does the right thing even for ZSTs.
3391+
// SAFETY: we are in bounds. `post_inc_start` does the right thing even for ZSTs.
33363392
unsafe {
33373393
self.post_inc_start(n as isize);
33383394
Some(next_unchecked!(self))
@@ -3439,6 +3495,8 @@ macro_rules! iterator {
34393495
let mut i = 0;
34403496
while let Some(x) = self.next() {
34413497
if predicate(x) {
3498+
// SAFETY: we are guaranteed to be in bounds by the loop invariant:
3499+
// when `i >= n`, `self.next()` returns `None` and the loop breaks.
34423500
unsafe { assume(i < n) };
34433501
return Some(i);
34443502
}
@@ -3460,6 +3518,8 @@ macro_rules! iterator {
34603518
while let Some(x) = self.next_back() {
34613519
i -= 1;
34623520
if predicate(x) {
3521+
// SAFETY: `i` must be lower than `n` since it starts at `n`
3522+
// and is only decreasing.
34633523
unsafe { assume(i < n) };
34643524
return Some(i);
34653525
}
@@ -3475,6 +3535,10 @@ macro_rules! iterator {
34753535
#[inline]
34763536
fn next_back(&mut self) -> Option<$elem> {
34773537
// could be implemented with slices, but this avoids bounds checks
3538+
3539+
// SAFETY: `assume` calls are safe since a slice's start pointer must be non-null,
3540+
// and slices over non-ZSTs must also have a non-null end pointer.
3541+
// The call to `next_back_unchecked!` is safe since we check if the iterator is empty first.
34783542
unsafe {
34793543
assume(!self.ptr.as_ptr().is_null());
34803544
if mem::size_of::<T>() != 0 {
@@ -3495,7 +3559,7 @@ macro_rules! iterator {
34953559
self.end = self.ptr.as_ptr();
34963560
return None;
34973561
}
3498-
// We are in bounds. `pre_dec_end` does the right thing even for ZSTs.
3562+
// SAFETY: we are in bounds. `pre_dec_end` does the right thing even for ZSTs.
34993563
unsafe {
35003564
self.pre_dec_end(n as isize);
35013565
Some(next_back_unchecked!(self))
@@ -3690,6 +3754,8 @@ impl<'a, T> IterMut<'a, T> {
36903754
/// ```
36913755
#[stable(feature = "iter_to_slice", since = "1.4.0")]
36923756
pub fn into_slice(self) -> &'a mut [T] {
3757+
// SAFETY: the iterator was created from a mutable slice with pointer `self.ptr` and length `len!(self)`.
3758+
// This guarantees that all the prerequisites for `from_raw_parts_mut` are fulfilled.
36933759
unsafe { from_raw_parts_mut(self.ptr.as_ptr(), len!(self)) }
36943760
}
36953761

@@ -5855,12 +5921,20 @@ pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T]
58555921
/// Converts a reference to T into a slice of length 1 (without copying).
58565922
#[stable(feature = "from_ref", since = "1.28.0")]
58575923
pub fn from_ref<T>(s: &T) -> &[T] {
5924+
// SAFETY: a reference is guaranteed to be valid for reads. The returned
5925+
// reference cannot be mutated as it is an immutable reference.
5926+
// `mem::size_of::<T>()` cannot be larger than `isize::MAX`.
5927+
// Thus the call to `from_raw_parts` is safe.
58585928
unsafe { from_raw_parts(s, 1) }
58595929
}
58605930

58615931
/// Converts a reference to T into a slice of length 1 (without copying).
58625932
#[stable(feature = "from_ref", since = "1.28.0")]
58635933
pub fn from_mut<T>(s: &mut T) -> &mut [T] {
5934+
// SAFETY: a mutable reference is guaranteed to be valid for writes.
5935+
// The reference cannot be accessed by another pointer as it is an mutable reference.
5936+
// `mem::size_of::<T>()` cannot be larger than `isize::MAX`.
5937+
// Thus the call to `from_raw_parts_mut` is safe.
58645938
unsafe { from_raw_parts_mut(s, 1) }
58655939
}
58665940

@@ -5993,6 +6067,9 @@ where
59936067
if self.as_ptr().guaranteed_eq(other.as_ptr()) {
59946068
return true;
59956069
}
6070+
6071+
// SAFETY: `self` and `other` are references and are thus guaranteed to be valid.
6072+
// The two slices have been checked to have the same size above.
59966073
unsafe {
59976074
let size = mem::size_of_val(self);
59986075
memcmp(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0
@@ -6095,6 +6172,9 @@ impl SliceOrd for u8 {
60956172
#[inline]
60966173
fn compare(left: &[Self], right: &[Self]) -> Ordering {
60976174
let order =
6175+
// SAFETY: `left` and `right` are references and are thus guaranteed to be valid.
6176+
// We use the minimum of both lengths which guarantees that both regions are
6177+
// valid for reads in that interval.
60986178
unsafe { memcmp(left.as_ptr(), right.as_ptr(), cmp::min(left.len(), right.len())) };
60996179
if order == 0 {
61006180
left.len().cmp(&right.len())
@@ -6164,6 +6244,10 @@ impl SliceContains for u8 {
61646244
impl SliceContains for i8 {
61656245
fn slice_contains(&self, x: &[Self]) -> bool {
61666246
let byte = *self as u8;
6247+
// SAFETY: `i8` and `u8` have the same memory layout, thus casting `x.as_ptr()`
6248+
// as `*const u8` is safe. The `x.as_ptr()` comes from a reference and is thus guaranteed
6249+
// to be valid for reads for the length of the slice `x.len()`, which cannot be larger
6250+
// than `isize::MAX`. The returned slice is never mutated.
61676251
let bytes: &[u8] = unsafe { from_raw_parts(x.as_ptr() as *const u8, x.len()) };
61686252
memchr::memchr(byte, bytes).is_some()
61696253
}

0 commit comments

Comments
 (0)