Skip to content
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

Document unsafe in libcore #66506

Closed
wants to merge 12 commits into from
15 changes: 8 additions & 7 deletions src/libcore/alloc.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
//! Memory allocation APIs

// ignore-tidy-undocumented-unsafe

#![stable(feature = "alloc_module", since = "1.28.0")]

use crate::cmp;
Expand Down Expand Up @@ -88,6 +86,7 @@ impl Layout {
return Err(LayoutErr { private: () });
}

// SAFETY: performed checks above
unsafe {
Ok(Layout::from_size_align_unchecked(size, align))
}
Expand Down Expand Up @@ -120,11 +119,11 @@ impl Layout {
#[inline]
pub fn new<T>() -> Self {
let (size, align) = size_align::<T>();
// Note that the align is guaranteed by rustc to be a power of two and
debug_assert!(Layout::from_size_align(size, align).is_ok());
// SAFETY: Note that the align is guaranteed by rustc to be a power of two and
// the size+align combo is guaranteed to fit in our address space. As a
// result use the unchecked constructor here to avoid inserting code
// that panics if it isn't optimized well enough.
debug_assert!(Layout::from_size_align(size, align).is_ok());
unsafe {
Layout::from_size_align_unchecked(size, align)
}
Expand All @@ -137,8 +136,8 @@ impl Layout {
#[inline]
pub fn for_value<T: ?Sized>(t: &T) -> Self {
let (size, align) = (mem::size_of_val(t), mem::align_of_val(t));
// See rationale in `new` for why this us using an unsafe variant below
debug_assert!(Layout::from_size_align(size, align).is_ok());
// SAFETY: See rationale in `new` for why this us using an unsafe variant below
unsafe {
Layout::from_size_align_unchecked(size, align)
}
Expand Down Expand Up @@ -243,9 +242,9 @@ impl Layout {
let alloc_size = padded_size.checked_mul(n)
.ok_or(LayoutErr { private: () })?;

// SAFETY: `self.align` is already known to be valid and `alloc_size` has been
// padded already.
unsafe {
// self.align is already known to be valid and alloc_size has been
// padded already.
Ok((Layout::from_size_align_unchecked(alloc_size, self.align()), padded_size))
}
}
Expand Down Expand Up @@ -1074,6 +1073,7 @@ pub unsafe trait Alloc {
{
let k = Layout::new::<T>();
if k.size() > 0 {
// SAFETY: layout has nonzero size
unsafe { self.alloc(k).map(|p| p.cast()) }
} else {
Err(AllocErr)
Expand Down Expand Up @@ -1143,6 +1143,7 @@ pub unsafe trait Alloc {
{
match Layout::array::<T>(n) {
Ok(ref layout) if layout.size() > 0 => {
// SAFETY: layout has nonzero size
unsafe {
self.alloc(layout.clone()).map(|p| p.cast())
}
Expand Down
12 changes: 10 additions & 2 deletions src/libcore/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,6 @@
//! ```
//!

// ignore-tidy-undocumented-unsafe

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

use crate::cmp::Ordering;
Expand Down Expand Up @@ -369,6 +367,7 @@ impl<T> Cell<T> {
if ptr::eq(self, other) {
return;
}
// SAFETY: not threadsafe, but it's OK since we know `Cell` isn't threadsafe
unsafe {
ptr::swap(self.value.get(), other.value.get());
}
Expand All @@ -388,6 +387,7 @@ impl<T> Cell<T> {
/// ```
#[stable(feature = "move_cell", since = "1.17.0")]
pub fn replace(&self, val: T) -> T {
// SAFETY: not threadsafe, but it's OK since we know `Cell` isn't threadsafe
mem::replace(unsafe { &mut *self.value.get() }, val)
}

Expand Down Expand Up @@ -424,6 +424,7 @@ impl<T:Copy> Cell<T> {
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn get(&self) -> T {
// SAFETY: not threadsafe, but it's OK since we know `Cell` isn't threadsafe
unsafe{ *self.value.get() }
}

Expand Down Expand Up @@ -491,6 +492,7 @@ impl<T: ?Sized> Cell<T> {
#[inline]
#[stable(feature = "cell_get_mut", since = "1.11.0")]
pub fn get_mut(&mut self) -> &mut T {
// SAFETY: not threadsafe, but it's OK since we know `Cell` isn't threadsafe
unsafe {
&mut *self.value.get()
}
Expand All @@ -512,6 +514,7 @@ impl<T: ?Sized> Cell<T> {
#[inline]
#[stable(feature = "as_cell", since = "1.37.0")]
pub fn from_mut(t: &mut T) -> &Cell<T> {
// SAFETY: `&mut` ensures unique access
unsafe {
&*(t as *mut T as *const Cell<T>)
}
Expand Down Expand Up @@ -557,6 +560,7 @@ impl<T> Cell<[T]> {
/// ```
#[stable(feature = "as_cell", since = "1.37.0")]
pub fn as_slice_of_cells(&self) -> &[Cell<T>] {
// SAFETY: `Cell<T>` has the same memory layout as `T`
unsafe {
&*(self as *const Cell<[T]> as *const [Cell<T>])
}
Expand Down Expand Up @@ -825,6 +829,8 @@ impl<T: ?Sized> RefCell<T> {
pub fn try_borrow(&self) -> Result<Ref<'_, T>, BorrowError> {
match BorrowRef::new(&self.borrow) {
Some(b) => Ok(Ref {
// SAFETY: `BorrowRef` ensures that there is only immutable access
// to the value while borrowed
value: unsafe { &*self.value.get() },
borrow: b,
}),
Expand Down Expand Up @@ -903,6 +909,7 @@ impl<T: ?Sized> RefCell<T> {
pub fn try_borrow_mut(&self) -> Result<RefMut<'_, T>, BorrowMutError> {
match BorrowRefMut::new(&self.borrow) {
Some(b) => Ok(RefMut {
// SAFETY: `BorrowRef` gurantees unique access
value: unsafe { &mut *self.value.get() },
borrow: b,
}),
Expand Down Expand Up @@ -954,6 +961,7 @@ impl<T: ?Sized> RefCell<T> {
#[inline]
#[stable(feature = "cell_get_mut", since = "1.11.0")]
pub fn get_mut(&mut self) -> &mut T {
// SAFETY: `&mut` guarantees unique access
unsafe {
&mut *self.value.get()
}
Expand Down
6 changes: 4 additions & 2 deletions src/libcore/fmt/float.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@ use crate::fmt::{Formatter, Result, LowerExp, UpperExp, Display, Debug};
use crate::mem::MaybeUninit;
use crate::num::flt2dec;

// ignore-tidy-undocumented-unsafe

// Don't inline this so callers don't use the stack space this function
// requires unless they have to.
#[inline(never)]
fn float_to_decimal_common_exact<T>(fmt: &mut Formatter<'_>, num: &T,
sign: flt2dec::Sign, precision: usize) -> Result
where T: flt2dec::DecodableFloat
{
// SAFETY: possible undefined behavior, see comment
unsafe {
let mut buf = MaybeUninit::<[u8; 1024]>::uninit(); // enough for f32 and f64
let mut parts = MaybeUninit::<[flt2dec::Part<'_>; 4]>::uninit();
Expand All @@ -33,6 +32,7 @@ fn float_to_decimal_common_shortest<T>(fmt: &mut Formatter<'_>, num: &T,
sign: flt2dec::Sign, precision: usize) -> Result
where T: flt2dec::DecodableFloat
{
// SAFETY: possible undefined behavior, see comment
unsafe {
// enough for f32 and f64
let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninit();
Expand Down Expand Up @@ -73,6 +73,7 @@ fn float_to_exponential_common_exact<T>(fmt: &mut Formatter<'_>, num: &T,
upper: bool) -> Result
where T: flt2dec::DecodableFloat
{
// SAFETY: possible undefined behavior, see comment
unsafe {
let mut buf = MaybeUninit::<[u8; 1024]>::uninit(); // enough for f32 and f64
let mut parts = MaybeUninit::<[flt2dec::Part<'_>; 6]>::uninit();
Expand All @@ -92,6 +93,7 @@ fn float_to_exponential_common_shortest<T>(fmt: &mut Formatter<'_>,
upper: bool) -> Result
where T: flt2dec::DecodableFloat
{
// SAFETY: possible undefined behavior, see comment
unsafe {
// enough for f32 and f64
let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninit();
Expand Down
8 changes: 6 additions & 2 deletions src/libcore/fmt/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
//! Utilities for formatting and printing strings.

// ignore-tidy-undocumented-unsafe

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

use crate::cell::{UnsafeCell, Cell, RefCell, Ref, RefMut};
Expand Down Expand Up @@ -279,6 +277,7 @@ impl<'a> ArgumentV1<'a> {
issue = "0")]
pub fn new<'b, T>(x: &'b T,
f: fn(&T, &mut Formatter<'_>) -> Result) -> ArgumentV1<'b> {
// SAFETY: relies on `T` being sized to avoid undefined behavior
unsafe {
ArgumentV1 {
formatter: mem::transmute(f),
Expand All @@ -296,6 +295,7 @@ impl<'a> ArgumentV1<'a> {

fn as_usize(&self) -> Option<usize> {
if self.formatter as usize == ArgumentV1::show_usize as usize {
// SAFETY: if the formatter is `show_usize`, it means it came in as `&usize`
Some(unsafe { *(self.value as *const _ as *const usize) })
} else {
None
Expand Down Expand Up @@ -1355,6 +1355,8 @@ impl<'a> Formatter<'a> {
let mut align = old_align;
if self.sign_aware_zero_pad() {
// a sign always goes first
// SAFETY: `formatted.sign` is always generated from `determine_sign` which is
// valid UTF-8
let sign = unsafe { str::from_utf8_unchecked(formatted.sign) };
self.buf.write_str(sign)?;

Expand Down Expand Up @@ -1386,6 +1388,8 @@ impl<'a> Formatter<'a> {

fn write_formatted_parts(&mut self, formatted: &flt2dec::Formatted<'_>) -> Result {
fn write_bytes(buf: &mut dyn Write, s: &[u8]) -> Result {
// SAFETY: `formatted.sign` is always generated from `determine_sign` which is
// valid UTF-8
buf.write_str(unsafe { str::from_utf8_unchecked(s) })
}

Expand Down
65 changes: 39 additions & 26 deletions src/libcore/fmt/num.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
//! Integer and floating-point number formatting

// ignore-tidy-undocumented-unsafe


use crate::fmt;
use crate::ops::{Div, Rem, Sub};
use crate::str;
Expand Down Expand Up @@ -83,6 +80,8 @@ trait GenericRadix {
}
}
let buf = &buf[curr..];
// SAFETY: only chars in `buf` are created by `Self::digit` which are assumed to be
// valid UTF-8
let buf = unsafe { str::from_utf8_unchecked(slice::from_raw_parts(
MaybeUninit::first_ptr(buf),
buf.len()
Expand Down Expand Up @@ -191,49 +190,63 @@ static DEC_DIGITS_LUT: &[u8; 200] =
macro_rules! impl_Display {
($($t:ident),* as $u:ident via $conv_fn:ident named $name:ident) => {
fn $name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// 2^128 is about 3*10^38, so 39 gives an extra byte of space
let mut buf = [MaybeUninit::<u8>::uninit(); 39];
let mut curr = buf.len() as isize;
let buf_ptr = MaybeUninit::first_ptr_mut(&mut buf);
let lut_ptr = DEC_DIGITS_LUT.as_ptr();

unsafe {
// need at least 16 bits for the 4-characters-at-a-time to work.
assert!(crate::mem::size_of::<$u>() >= 2);
// need at least 16 bits for the 4-characters-at-a-time to work.
assert!(crate::mem::size_of::<$u>() >= 2);

// eagerly decode 4 characters at a time
while n >= 10000 {
let rem = (n % 10000) as isize;
n /= 10000;
// eagerly decode 4 characters at a time
while n >= 10000 {
let rem = (n % 10000) as isize;
n /= 10000;

let d1 = (rem / 100) << 1;
let d2 = (rem % 100) << 1;
curr -= 4;
let d1 = (rem / 100) << 1;
let d2 = (rem % 100) << 1;
curr -= 4;
// SAFETY: `d1`, `d2` are each max 198, so `buf_ptr[d1..d1 + 1]` is safe to access
unsafe {
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2);
}
}

// if we reach here numbers are <= 9999, so at most 4 chars long
let mut n = n as isize; // possibly reduce 64bit math
// if we reach here numbers are <= 9999, so at most 4 chars long
let mut n = n as isize; // possibly reduce 64bit math

// decode 2 more chars, if > 2 chars
if n >= 100 {
let d1 = (n % 100) << 1;
n /= 100;
curr -= 2;
// decode 2 more chars, if > 2 chars
if n >= 100 {
let d1 = (n % 100) << 1;
n /= 100;
curr -= 2;
// SAFETY: `d1` is max 198, so `buf_ptr[d1..d1 + 1]` is safe to access
unsafe {
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
}
}

// decode last 1 or 2 chars
if n < 10 {
curr -= 1;
// decode last 1 or 2 chars
if n < 10 {
curr -= 1;
// SAFETY: `curr` is still less than `buf.len()` and since `n` < 10, `n + '0'` is
// valid UTF-8
unsafe {
*buf_ptr.offset(curr) = (n as u8) + b'0';
} else {
let d1 = n << 1;
curr -= 2;
}
} else {
let d1 = n << 1;
curr -= 2;
// SAFETY: `d1` is max 18, so `buf_ptr[d1..d1 + 1]` is safe to access
unsafe {
ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2);
}
}

// SAFETY: `curr` > 0 (since we made `buf` large enough), and all the chars are valid
// UTF-8 since `DEC_DIGITS_LUT` is
let buf_slice = unsafe {
str::from_utf8_unchecked(
slice::from_raw_parts(buf_ptr.offset(curr), buf.len() - curr as usize))
Expand Down
8 changes: 4 additions & 4 deletions src/libcore/hash/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,6 @@
//! }
//! ```

// ignore-tidy-undocumented-unsafe

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

use crate::fmt;
Expand Down Expand Up @@ -569,6 +567,8 @@ mod impls {
fn hash_slice<H: Hasher>(data: &[$ty], state: &mut H) {
let newlen = data.len() * mem::size_of::<$ty>();
let ptr = data.as_ptr() as *const u8;
// SAFETY: all of the requirements for `from_raw_parts` are guaranteed since
// `data` is a slice
state.write(unsafe { slice::from_raw_parts(ptr, newlen) })
}
}
Expand Down Expand Up @@ -688,7 +688,7 @@ mod impls {
// Thin pointer
state.write_usize(*self as *const () as usize);
} else {
// Fat pointer
// SAFETY: since it's not a thin pointer, it's a fat pointer
let (a, b) = unsafe {
*(self as *const Self as *const (usize, usize))
};
Expand All @@ -705,7 +705,7 @@ mod impls {
// Thin pointer
state.write_usize(*self as *const () as usize);
} else {
// Fat pointer
// SAFETY: since it's not a thin pointer, it's a fat pointer
let (a, b) = unsafe {
*(self as *const Self as *const (usize, usize))
};
Expand Down
Loading