8000 Deny unsafe ops in unsafe fns in libcore by LeSeulArtichaut · Pull Request #73622 · rust-lang/rust · GitHub
[go: up one dir, main page]

Skip to content

Deny unsafe ops in unsafe fns in libcore #73622

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 7 commits into from
Jul 2, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Deny unsafe ops in unsafe fns, part 4
  • Loading branch information
LeSeulArtichaut committed Jun 30, 2020
commit c68f478131a94f5a69d91db1af35cb506f673ec2
48 changes: 30 additions & 18 deletions src/libcore/slice/rotate.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
// ignore-tidy-undocumented-unsafe

#![deny(unsafe_op_in_unsafe_fn)]

use crate::cmp;
use crate::mem::{self, MaybeUninit};
use crate::ptr;
Expand Down Expand Up @@ -77,9 +81,9 @@ pub unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize)
// the way until about `left + right == 32`, but the worst case performance breaks even
// around 16. 24 was chosen as middle ground. If the size of `T` is larger than 4
// `usize`s, this algorithm also outperforms other algorithms.
let x = mid.sub(left);
let x = unsafe { mid.sub(left) };
// beginning of first round
let mut tmp: T = x.read();
let mut tmp: T = unsafe { x.read() };
let mut i = right;
// `gcd` can be found before hand by calculating `gcd(left + right, right)`,
// but it is faster to do one loop which calculates the gcd as a side effect, then
Expand All @@ -90,15 +94,15 @@ pub unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize)
// the very end. This is possibly due to the fact that swapping or replacing temporaries
// uses only one memory address in the loop instead of needing to manage two.
loop {
tmp = x.add(i).replace(tmp);
tmp = unsafe { x.add(i).replace(tmp) };
// instead of incrementing `i` and then checking if it is outside the bounds, we
// check if `i` will go outside the bounds on the next increment. This prevents
// any wrapping of pointers or `usize`.
if i >= left {
i -= left;
if i == 0 {
// end of first round
x.write(tmp);
unsafe { x.write(tmp) };
break;
}
// this conditional must be here if `left + right >= 15`
Expand All @@ -111,14 +115,14 @@ pub unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize)
}
// finish the chunk with more rounds
for start in 1..gcd {
tmp = x.add(start).read();
tmp = unsafe { x.add(start).read() };
i = start + right;
loop {
tmp = x.add(i).replace(tmp);
tmp = unsafe { x.add(i).replace(tmp) };
if i >= left {
i -= left;
if i == start {
x.add(start).write(tmp);
unsafe { x.add(start).write(tmp) };
break;
}
} else {
Expand All @@ -133,15 +137,19 @@ pub unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize)
// The `[T; 0]` here is to ensure this is appropriately aligned for T
let mut rawarray = MaybeUninit::<(BufType, [T; 0])>::uninit();
let buf = rawarray.as_mut_ptr() as *mut T;
let dim = mid.sub(left).add(right);
let dim = unsafe { mid.sub(left).add(right) };
if left <= right {
ptr::copy_nonoverlapping(mid.sub(left), buf, left);
ptr::copy(mid, mid.sub(left), right);
ptr::copy_nonoverlapping(buf, dim, left);
unsafe {
ptr::copy_nonoverlapping(mid.sub(left), buf, left);
ptr::copy(mid, mid.sub(left), right);
ptr::copy_nonoverlapping(buf, dim, left);
}
} else {
ptr::copy_nonoverlapping(mid, buf, right);
ptr::copy(mid.sub(left), dim, left);
ptr::copy_nonoverlapping(buf, mid.sub(left), right);
unsafe {
ptr::copy_nonoverlapping(mid, buf, right);
ptr::copy(mid.sub(left), dim, left);
ptr::copy_nonoverlapping(buf, mid.sub(left), right);
}
}
return;
} else if left >= right {
Expand All @@ -150,8 +158,10 @@ pub unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize)
// of this algorithm would be, and swapping using that last chunk instead of swapping
// adjacent chunks like this algorithm is doing, but this way is still faster.
loop {
ptr::swap_nonoverlapping(mid.sub(right), mid, right);
mid = mid.sub(right);
unsafe {
ptr::swap_nonoverlapping(mid.sub(right), mid, right);
mid = mid.sub(right);
}
left -= right;
if left < right {
break;
Expand All @@ -160,8 +170,10 @@ pub unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize)
} else {
// Algorithm 3, `left < right`
loop {
ptr::swap_nonoverlapping(mid.sub(left), mid, left);
mid = mid.add(left);
unsafe {
ptr::swap_nonoverlapping(mid.sub(left), mid, left);
mid = mid.add(left);
} 10000
right -= left;
if right < left {
break;
Expand Down
100 changes: 78 additions & 22 deletions src/libcore/str/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//! [`std::str`]: ../../std/str/index.html

#![stable(feature = "rust1", since = "1.0.0")]
#![deny(unsafe_op_in_unsafe_fn)]

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

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

#[stable(feature = "rust1", since = "1.0.0")]
Expand Down Expand Up @@ -867,7 +876,9 @@ unsafe impl TrustedLen for Bytes<'_> {}
#[doc(hidden)]
unsafe impl TrustedRandomAccess for Bytes<'_> {
unsafe fn get_unchecked(&mut self, i: usize) -> u8 {
self.0.get_unchecked(i)
// SAFETY: the caller must uphold the safety contract
// for `TrustedRandomAccess::get_unchecked`.
unsafe { self.0.get_unchecked(i) }
}
fn may_have_side_effect() -> bool {
false
Expand Down Expand Up @@ -1904,15 +1915,27 @@ mod traits {
}
#[inline]
unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
let ptr = slice.as_ptr().add(self.start);
// SAFETY: the caller guarantees that `self` is in bounds of `slice`
// which satisfies all the conditions for `add`.
let ptr = unsafe { slice.as_ptr().add(self.start) };
let len = self.end - self.start;
super::from_utf8_unchecked(slice::from_raw_parts(ptr, len))
// SAFETY: as the caller guarantees that `self` is in bounds of `slice`,
// we can safely construct a subslice with `from_raw_parts` and use it
// since we return a shared thus immutable reference.
// The call to `from_utf8_unchecked` is safe since the data comes from
// a `str` which is guaranteed to be valid utf8, since the caller
// must guarantee that `self.start` and `self.end` are char boundaries.
unsafe { super::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) }
}
#[inline]
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
let ptr = slice.as_mut_ptr().add(self.start);
// SAFETY: see comments for `get_unchecked`.
let ptr = unsafe { slice.as_mut_ptr().add(self.start) };
let len = self.end - self.start;
super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, len))
// SAFETY: mostly identical to the comments for `get_unchecked`, except that we
// can return a mutable reference since the caller passed a mutable reference
// and is thus guaranteed to have exclusive write access to `slice`.
unsafe { super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, len)) }
}
#[inline]
fn index(self, slice: &str) -> &Self::Output {
Expand Down Expand Up @@ -1974,12 +1997,21 @@ mod traits {
#[inline]
unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
let ptr = slice.as_ptr();
super::from_utf8_unchecked(slice::from_raw_parts(ptr, self.end))
// SAFETY: as the caller guarantees that `self` is in bounds of `slice`,
// we can safely construct a subslice with `from_raw_parts` and use it
// since we return a shared thus immutable reference.
// The call to `from_utf8_unchecked` is safe since the data comes from
// a `str` which is guaranteed to be valid utf8, since the caller
// must guarantee that `self.end` is a char boundary.
unsafe { super::from_utf8_unchecked(slice::from_raw_parts(ptr, self.end)) }
}
#[inline]
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
let ptr = slice.as_mut_ptr();
super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, self.end))
// SAFETY: mostly identical to `get_unchecked`, except that we can safely
// return a mutable reference since the caller passed a mutable reference
// and is thus guaranteed to have exclusive write access to `slice`.
unsafe { super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, self.end)) }
}
#[inline]
fn index(self, slice: &str) -> &Self::Output {
Expand Down Expand Up @@ -2036,15 +2068,27 @@ mod traits {
}
#[inline]
unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
let ptr = slice.as_ptr().add(self.start);
// SAFETY: the caller guarantees that `self` is in bounds of `slice`
// which satisfies all the conditions for `add`.
let ptr = unsafe { slice.as_ptr().add(self.start) };
let len = slice.len() - self.start;
super::from_utf8_unchecked(slice::from_raw_parts(ptr, len))
// SAFETY: as the caller guarantees that `self` is in bounds of `slice`,
// we can safely construct a subslice with `from_raw_parts` and use it
// since we return a shared thus immutable reference.
// The call to `from_utf8_unchecked` is safe since the data comes from
// a `str` which is guaranteed to be valid utf8, since the caller
// must guarantee that `self.start` is a char boundary.
unsafe { super::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) }
}
#[inline]
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
let ptr = slice.as_mut_ptr().add(self.start);
// SAFETY: identical to `get_unchecked`.
let ptr = unsafe { slice.as_mut_ptr().add(self.start) };
let len = slice.len() - self.start;
super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, len))
// SAFETY: mostly identical to `get_unchecked`, except that we can safely
// return a mutable reference since the caller passed a mutable reference
// and is thus guaranteed to have exclusive write access to `slice`.
unsafe { super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, len)) }
}
#[inline]
fn index(self, slice: &str) -> &Self::Output {
Expand Down Expand Up @@ -2099,11 +2143,13 @@ mod traits {
}
#[inline]
unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
(*self.start()..self.end() + 1).get_unchecked(slice)
// SAFETY: the caller must uphold the safety contract for `get_unchecked`.
unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) }
}
#[inline]
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
(*self.start()..self.end() + 1).get_unchecked_mut(slice)
// SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`.
unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) }
}
#[inline]
fn index(self, slice: &str) -> &Self::Output {
Expand Down Expand Up @@ -2148,11 +2194,13 @@ mod traits {
}
#[inline]
unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
(..self.end + 1).get_unchecked(slice)
// SAFETY: the caller must uphold the safety contract for `get_unchecked`.
unsafe { (..self.end + 1).get_unchecked(slice) }
}
#[inline]
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
(..self.end + 1).get_unchecked_mut(slice)
// SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`.
unsafe { (..self.end + 1).get_unchecked_mut(slice) }
}
#[inline]
fn index(self, slice: &str) -> &Self::Output {
Expand Down Expand Up @@ -2373,7 +2421,11 @@ impl str {
#[stable(feature = "str_mut_extras", since = "1.20.0")]
#[inline(always)]
pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
&mut *(self as *mut str as *mut [u8])
// SAFETY: the cast from `&str` to `&[u8]` is safe since `str`
// has the same layout as `&[u8]` (only libstd can make this guarantee).
// The pointer dereference is safe since it comes from a mutable reference which
// is guaranteed to be valid for writes.
unsafe { &mut *(self as *mut str as *mut [u8]) }
}

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

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

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

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

/// Divide one string slice into two at an index.
Expand Down
0