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