Skip to content

Commit c68f478

Browse files
Deny unsafe ops in unsafe fns, part 4
1 parent ac7539c commit c68f478

File tree

2 files changed

+108
-40
lines changed

2 files changed

+108
-40
lines changed

src/libcore/slice/rotate.rs

+30-18
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
// ignore-tidy-undocumented-unsafe
2+
3+
#![deny(unsafe_op_in_unsafe_fn)]
4+
15
use crate::cmp;
26
use crate::mem::{self, MaybeUninit};
37
use crate::ptr;
@@ -77,9 +81,9 @@ pub unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize)
7781
// the way until about `left + right == 32`, but the worst case performance breaks even
7882
// around 16. 24 was chosen as middle ground. If the size of `T` is larger than 4
7983
// `usize`s, this algorithm also outperforms other algorithms.
80-
let x = mid.sub(left);
84+
let x = unsafe { mid.sub(left) };
8185
// beginning of first round
82-
let mut tmp: T = x.read();
86+
let mut tmp: T = unsafe { x.read() };
8387
let mut i = right;
8488
// `gcd` can be found before hand by calculating `gcd(left + right, right)`,
8589
// but it is faster to do one loop which calculates the gcd as a side effect, then
@@ -90,15 +94,15 @@ pub unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize)
9094
// the very end. This is possibly due to the fact that swapping or replacing temporaries
9195
// uses only one memory address in the loop instead of needing to manage two.
9296
loop {
93-
tmp = x.add(i).replace(tmp);
97+
tmp = unsafe { x.add(i).replace(tmp) };
9498
// instead of incrementing `i` and then checking if it is outside the bounds, we
9599
// check if `i` will go outside the bounds on the next increment. This prevents
96100
// any wrapping of pointers or `usize`.
97101
if i >= left {
98102
i -= left;
99103
if i == 0 {
100104
// end of first round
101-
x.write(tmp);
105+
unsafe { x.write(tmp) };
102106
break;
103107
}
104108
// this conditional must be here if `left + right >= 15`
@@ -111,14 +115,14 @@ pub unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize)
111115
}
112116
// finish the chunk with more rounds
113117
for start in 1..gcd {
114-
tmp = x.add(start).read();
118+
tmp = unsafe { x.add(start).read() };
115119
i = start + right;
116120
loop {
117-
tmp = x.add(i).replace(tmp);
121+
tmp = unsafe { x.add(i).replace(tmp) };
118122
if i >= left {
119123
i -= left;
120124
if i == start {
121-
x.add(start).write(tmp);
125+
unsafe { x.add(start).write(tmp) };
122126
break;
123127
}
124128
} else {
@@ -133,15 +137,19 @@ pub unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize)
133137
// The `[T; 0]` here is to ensure this is appropriately aligned for T
134138
let mut rawarray = MaybeUninit::<(BufType, [T; 0])>::uninit();
135139
let buf = rawarray.as_mut_ptr() as *mut T;
136-
let dim = mid.sub(left).add(right);
140+
let dim = unsafe { mid.sub(left).add(right) };
137141
if left <= right {
138-
ptr::copy_nonoverlapping(mid.sub(left), buf, left);
139-
ptr::copy(mid, mid.sub(left), right);
140-
ptr::copy_nonoverlapping(buf, dim, left);
142+
unsafe {
143+
ptr::copy_nonoverlapping(mid.sub(left), buf, left);
144+
ptr::copy(mid, mid.sub(left), right);
145+
ptr::copy_nonoverlapping(buf, dim, left);
146+
}
141147
} else {
142-
ptr::copy_nonoverlapping(mid, buf, right);
143-
ptr::copy(mid.sub(left), dim, left);
144-
ptr::copy_nonoverlapping(buf, mid.sub(left), right);
148+
unsafe {
149+
ptr::copy_nonoverlapping(mid, buf, right);
150+
ptr::copy(mid.sub(left), dim, left);
151+
ptr::copy_nonoverlapping(buf, mid.sub(left), right);
152+
}
145153
}
146154
return;
147155
} else if left >= right {
@@ -150,8 +158,10 @@ pub unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize)
150158
// of this algorithm would be, and swapping using that last chunk instead of swapping
151159
// adjacent chunks like this algorithm is doing, but this way is still faster.
152160
loop {
153-
ptr::swap_nonoverlapping(mid.sub(right), mid, right);
154-
mid = mid.sub(right);
161+
unsafe {
162+
ptr::swap_nonoverlapping(mid.sub(right), mid, right);
163+
mid = mid.sub(right);
164+
}
155165
left -= right;
156166
if left < right {
157167
break;
@@ -160,8 +170,10 @@ pub unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize)
160170
} else {
161171
// Algorithm 3, `left < right`
162172
loop {
163-
ptr::swap_nonoverlapping(mid.sub(left), mid, left);
164-
mid = mid.add(left);
173+
unsafe {
174+
ptr::swap_nonoverlapping(mid.sub(left), mid, left);
175+
mid = mid.add(left);
176+
}
165177
right -= left;
166178
if right < left {
167179
break;

src/libcore/str/mod.rs

+78-22
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//! [`std::str`]: ../../std/str/index.html
88
99
#![stable(feature = "rust1", since = "1.0.0")]
10+
#![deny(unsafe_op_in_unsafe_fn)]
1011

1112
use self::pattern::Pattern;
1213
use self::pattern::{DoubleEndedSearcher, ReverseSearcher, Searcher};
@@ -419,7 +420,11 @@ pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> {
419420
#[inline]
420421
#[stable(feature = "rust1", since = "1.0.0")]
421422
pub unsafe fn from_utf8_unchecked(v: &[u8]) -> &str {
422-
&*(v as *const [u8] as *const str)
423+
// SAFETY: the caller must guarantee that the bytes `v`
424+
// are valid UTF-8, thus the cast to `*const str` is safe.
425+
// Also, the pointer dereference is safe because that pointer
426+
// comes from a reference which is guaranteed to be valid for reads.
427+
unsafe { &*(v as *const [u8] as *const str) }
423428
}
424429

425430
/// Converts a slice of bytes to a string slice without checking
@@ -444,7 +449,11 @@ pub unsafe fn from_utf8_unchecked(v: &[u8]) -> &str {
444449
#[inline]
445450
#[stable(feature = "str_mut_extras", since = "1.20.0")]
446451
pub unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str {
447-
&mut *(v as *mut [u8] as *mut str)
452+
// SAFETY: the caller must guarantee that the bytes `v`
453+
// are valid UTF-8, thus the cast to `*mut str` is safe.
454+
// Also, the pointer dereference is safe because that pointer
455+
// comes from a reference which is guaranteed to be valid for writes.
456+
unsafe { &mut *(v as *mut [u8] as *mut str) }
448457
}
449458

450459
#[stable(feature = "rust1", since = "1.0.0")]
@@ -867,7 +876,9 @@ unsafe impl TrustedLen for Bytes<'_> {}
867876
#[doc(hidden)]
868877
unsafe impl TrustedRandomAccess for Bytes<'_> {
869878
unsafe fn get_unchecked(&mut self, i: usize) -> u8 {
870-
self.0.get_unchecked(i)
879+
// SAFETY: the caller must uphold the safety contract
880+
// for `TrustedRandomAccess::get_unchecked`.
881+
unsafe { self.0.get_unchecked(i) }
871882
}
872883
fn may_have_side_effect() -> bool {
873884
false
@@ -1904,15 +1915,27 @@ mod traits {
19041915
}
19051916
#[inline]
19061917
unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
1907-
let ptr = slice.as_ptr().add(self.start);
1918+
// SAFETY: the caller guarantees that `self` is in bounds of `slice`
1919+
// which satisfies all the conditions for `add`.
1920+
let ptr = unsafe { slice.as_ptr().add(self.start) };
19081921
let len = self.end - self.start;
1909-
super::from_utf8_unchecked(slice::from_raw_parts(ptr, len))
1922+
// SAFETY: as the caller guarantees that `self` is in bounds of `slice`,
1923+
// we can safely construct a subslice with `from_raw_parts` and use it
1924+
// since we return a shared thus immutable reference.
1925+
// The call to `from_utf8_unchecked` is safe since the data comes from
1926+
// a `str` which is guaranteed to be valid utf8, since the caller
1927+
// must guarantee that `self.start` and `self.end` are char boundaries.
1928+
unsafe { super::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) }
19101929
}
19111930
#[inline]
19121931
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
1913-
let ptr = slice.as_mut_ptr().add(self.start);
1932+
// SAFETY: see comments for `get_unchecked`.
1933+
let ptr = unsafe { slice.as_mut_ptr().add(self.start) };
19141934
let len = self.end - self.start;
1915-
super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, len))
1935+
// SAFETY: mostly identical to the comments for `get_unchecked`, except that we
1936+
// can return a mutable reference since the caller passed a mutable reference
1937+
// and is thus guaranteed to have exclusive write access to `slice`.
1938+
unsafe { super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, len)) }
19161939
}
19171940
#[inline]
19181941
fn index(self, slice: &str) -> &Self::Output {
@@ -1974,12 +1997,21 @@ mod traits {
19741997
#[inline]
19751998
unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
19761999
let ptr = slice.as_ptr();
1977-
super::from_utf8_unchecked(slice::from_raw_parts(ptr, self.end))
2000+
// SAFETY: as the caller guarantees that `self` is in bounds of `slice`,
2001+
// we can safely construct a subslice with `from_raw_parts` and use it
2002+
// since we return a shared thus immutable reference.
2003+
// The call to `from_utf8_unchecked` is safe since the data comes from
2004+
// a `str` which is guaranteed to be valid utf8, since the caller
2005+
// must guarantee that `self.end` is a char boundary.
2006+
unsafe { super::from_utf8_unchecked(slice::from_raw_parts(ptr, self.end)) }
19782007
}
19792008
#[inline]
19802009
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
19812010
let ptr = slice.as_mut_ptr();
1982-
super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, self.end))
2011+
// SAFETY: mostly identical to `get_unchecked`, except that we can safely
2012+
// return a mutable reference since the caller passed a mutable reference
2013+
// and is thus guaranteed to have exclusive write access to `slice`.
2014+
unsafe { super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, self.end)) }
19832015
}
19842016
#[inline]
19852017
fn index(self, slice: &str) -> &Self::Output {
@@ -2036,15 +2068,27 @@ mod traits {
20362068
}
20372069
#[inline]
20382070
unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
2039-
let ptr = slice.as_ptr().add(self.start);
2071+
// SAFETY: the caller guarantees that `self` is in bounds of `slice`
2072+
// which satisfies all the conditions for `add`.
2073+
let ptr = unsafe { slice.as_ptr().add(self.start) };
20402074
let len = slice.len() - self.start;
2041-
super::from_utf8_unchecked(slice::from_raw_parts(ptr, len))
2075+
// SAFETY: as the caller guarantees that `self` is in bounds of `slice`,
2076+
// we can safely construct a subslice with `from_raw_parts` and use it
2077+
// since we return a shared thus immutable reference.
2078+
// The call to `from_utf8_unchecked` is safe since the data comes from
2079+
// a `str` which is guaranteed to be valid utf8, since the caller
2080+
// must guarantee that `self.start` is a char boundary.
2081+
unsafe { super::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) }
20422082
}
20432083
#[inline]
20442084
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
2045-
let ptr = slice.as_mut_ptr().add(self.start);
2085+
// SAFETY: identical to `get_unchecked`.
2086+
let ptr = unsafe { slice.as_mut_ptr().add(self.start) };
20462087
let len = slice.len() - self.start;
2047-
super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, len))
2088+
// SAFETY: mostly identical to `get_unchecked`, except that we can safely
2089+
// return a mutable reference since the caller passed a mutable reference
2090+
// and is thus guaranteed to have exclusive write access to `slice`.
2091+
unsafe { super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, len)) }
20482092
}
20492093
#[inline]
20502094
fn index(self, slice: &str) -> &Self::Output {
@@ -2099,11 +2143,13 @@ mod traits {
20992143
}
21002144
#[inline]
21012145
unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
2102-
(*self.start()..self.end() + 1).get_unchecked(slice)
2146+
// SAFETY: the caller must uphold the safety contract for `get_unchecked`.
2147+
unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) }
21032148
}
21042149
#[inline]
21052150
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
2106-
(*self.start()..self.end() + 1).get_unchecked_mut(slice)
2151+
// SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`.
2152+
unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) }
21072153
}
21082154
#[inline]
21092155
fn index(self, slice: &str) -> &Self::Output {
@@ -2148,11 +2194,13 @@ mod traits {
21482194
}
21492195
#[inline]
21502196
unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
2151-
(..self.end + 1).get_unchecked(slice)
2197+
// SAFETY: the caller must uphold the safety contract for `get_unchecked`.
2198+
unsafe { (..self.end + 1).get_unchecked(slice) }
21522199
}
21532200
#[inline]
21542201
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
2155-
(..self.end + 1).get_unchecked_mut(slice)
2202+
// SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`.
2203+
unsafe { (..self.end + 1).get_unchecked_mut(slice) }
21562204
}
21572205
#[inline]
21582206
fn index(self, slice: &str) -> &Self::Output {
@@ -2373,7 +2421,11 @@ impl str {
23732421
#[stable(feature = "str_mut_extras", since = "1.20.0")]
23742422
#[inline(always)]
23752423
pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
2376-
&mut *(self as *mut str as *mut [u8])
2424+
// SAFETY: the cast from `&str` to `&[u8]` is safe since `str`
2425+
// has the same layout as `&[u8]` (only libstd can make this guarantee).
2426+
// The pointer dereference is safe since it comes from a mutable reference which
2427+
// is guaranteed to be valid for writes.
2428+
unsafe { &mut *(self as *mut str as *mut [u8]) }
23772429
}
23782430

23792431
/// Converts a string slice to a raw pointer.
@@ -2509,7 +2561,8 @@ impl str {
25092561
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
25102562
#[inline]
25112563
pub unsafe fn get_unchecked<I: SliceIndex<str>>(&self, i: I) -> &I::Output {
2512-
i.get_unchecked(self)
2564+
// SAFETY: the caller must uphold the safety contract for `get_unchecked`.
2565+
unsafe { i.get_unchecked(self) }
25132566
}
25142567

25152568
/// Returns a mutable, unchecked subslice of `str`.
@@ -2541,7 +2594,8 @@ impl str {
25412594
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
25422595
#[inline]
25432596
pub unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::Output {
2544-
i.get_unchecked_mut(self)
2597+
// SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`.
2598+
unsafe { i.get_unchecked_mut(self) }
25452599
}
25462600

25472601
/// Creates a string slice from another string slice, bypassing safety
@@ -2591,7 +2645,8 @@ impl str {
25912645
#[rustc_deprecated(since = "1.29.0", reason = "use `get_unchecked(begin..end)` instead")]
25922646
#[inline]
25932647
pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str {
2594-
(begin..end).get_unchecked(self)
2648+
// SAFETY: the caller must uphold the safety contract for `get_unchecked`.
2649+
unsafe { (begin..end).get_unchecked(self) }
25952650
}
25962651

25972652
/// Creates a string slice from another string slice, bypassing safety
@@ -2622,7 +2677,8 @@ impl str {
26222677
#[rustc_deprecated(since = "1.29.0", reason = "use `get_unchecked_mut(begin..end)` instead")]
26232678
#[inline]
26242679
pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str {
2625-
(begin..end).get_unchecked_mut(self)
2680+
// SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`.
2681+
unsafe { (begin..end).get_unchecked_mut(self) }
26262682
}
26272683

26282684
/// Divide one string slice into two at an index.

0 commit comments

Comments
 (0)