Deny unsafe ops in unsafe fns, part 2
This commit is contained in:
parent
8ee1dec77b
commit
8a515e963c
9 changed files with 103 additions and 37 deletions
|
|
@ -1,6 +1,7 @@
|
|||
//! An implementation of SipHash.
|
||||
|
||||
#![allow(deprecated)] // the types in this module are deprecated
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
use crate::cmp;
|
||||
use crate::marker::PhantomData;
|
||||
|
|
@ -130,15 +131,19 @@ unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 {
|
|||
let mut i = 0; // current byte index (from LSB) in the output u64
|
||||
let mut out = 0;
|
||||
if i + 3 < len {
|
||||
out = load_int_le!(buf, start + i, u32) as u64;
|
||||
// SAFETY: `i` cannot be greater than `len`, and the caller must guarantee
|
||||
// that the index start..start+len is in bounds.
|
||||
out = unsafe { load_int_le!(buf, start + i, u32) } as u64;
|
||||
i += 4;
|
||||
}
|
||||
if i + 1 < len {
|
||||
out |= (load_int_le!(buf, start + i, u16) as u64) << (i * 8);
|
||||
// SAFETY: same as above.
|
||||
out |= (unsafe { load_int_le!(buf, start + i, u16) } as u64) << (i * 8);
|
||||
i += 2
|
||||
}
|
||||
if i < len {
|
||||
out |= (*buf.get_unchecked(start + i) as u64) << (i * 8);
|
||||
// SAFETY: same as above.
|
||||
out |= (unsafe { *buf.get_unchecked(start + i) } as u64) << (i * 8);
|
||||
i += 1;
|
||||
}
|
||||
debug_assert_eq!(i, len);
|
||||
|
|
|
|||
|
|
@ -178,9 +178,10 @@ where
|
|||
{
|
||||
unsafe fn get_unchecked(&mut self, i: usize) -> I::Item {
|
||||
match self.iter {
|
||||
Some(ref mut iter) => iter.get_unchecked(i),
|
||||
// SAFETY: the caller must uphold the contract for `TrustedRandomAccess::get_unchecked`.
|
||||
Some(ref mut iter) => unsafe { iter.get_unchecked(i) },
|
||||
// SAFETY: the caller asserts there is an item at `i`, so we're not exhausted.
|
||||
None => intrinsics::unreachable(),
|
||||
None => unsafe { intrinsics::unreachable() },
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -272,7 +272,8 @@ where
|
|||
T: Copy,
|
||||
{
|
||||
unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item {
|
||||
*self.it.get_unchecked(i)
|
||||
// SAFETY: the caller must uphold the contract for `TrustedRandomAccess::get_unchecked`.
|
||||
unsafe { *self.it.get_unchecked(i) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -402,7 +403,8 @@ where
|
|||
T: Clone,
|
||||
{
|
||||
default unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item {
|
||||
self.it.get_unchecked(i).clone()
|
||||
// SAFETY: the caller must uphold the contract for `TrustedRandomAccess::get_unchecked`.
|
||||
unsafe { self.it.get_unchecked(i) }.clone()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -418,7 +420,8 @@ where
|
|||
T: Copy,
|
||||
{
|
||||
unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item {
|
||||
*self.it.get_unchecked(i)
|
||||
// SAFETY: the caller must uphold the contract for `TrustedRandomAccess::get_unchecked`.
|
||||
unsafe { *self.it.get_unchecked(i) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -930,7 +933,8 @@ where
|
|||
F: FnMut(I::Item) -> B,
|
||||
{
|
||||
unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item {
|
||||
(self.f)(self.iter.get_unchecked(i))
|
||||
// SAFETY: the caller must uphold the contract for `TrustedRandomAccess::get_unchecked`.
|
||||
(self.f)(unsafe { self.iter.get_unchecked(i) })
|
||||
}
|
||||
#[inline]
|
||||
fn may_have_side_effect() -> bool {
|
||||
|
|
@ -1392,7 +1396,8 @@ where
|
|||
I: TrustedRandomAccess,
|
||||
{
|
||||
unsafe fn get_unchecked(&mut self, i: usize) -> (usize, I::Item) {
|
||||
(self.count + i, self.iter.get_unchecked(i))
|
||||
// SAFETY: the caller must uphold the contract for `TrustedRandomAccess::get_unchecked`.
|
||||
(self.count + i, unsafe { self.iter.get_unchecked(i) })
|
||||
}
|
||||
|
||||
fn may_have_side_effect() -> bool {
|
||||
|
|
|
|||
|
|
@ -271,7 +271,8 @@ where
|
|||
B: TrustedRandomAccess,
|
||||
{
|
||||
unsafe fn get_unchecked(&mut self, i: usize) -> (A::Item, B::Item) {
|
||||
(self.a.get_unchecked(i), self.b.get_unchecked(i))
|
||||
// SAFETY: the caller must uphold the contract for `TrustedRandomAccess::get_unchecked`.
|
||||
unsafe { (self.a.get_unchecked(i), self.b.get_unchecked(i)) }
|
||||
}
|
||||
|
||||
fn may_have_side_effect() -> bool {
|
||||
|
|
|
|||
|
|
@ -309,6 +309,7 @@
|
|||
//! [`min`]: trait.Iterator.html#method.min
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
use crate::ops::Try;
|
||||
|
||||
|
|
|
|||
|
|
@ -189,12 +189,14 @@ macro_rules! step_identical_methods {
|
|||
() => {
|
||||
#[inline]
|
||||
unsafe fn forward_unchecked(start: Self, n: usize) -> Self {
|
||||
start.unchecked_add(n as Self)
|
||||
// SAFETY: the caller has to guarantee that `start + n` doesn't overflow.
|
||||
unsafe { start.unchecked_add(n as Self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn backward_unchecked(start: Self, n: usize) -> Self {
|
||||
start.unchecked_sub(n as Self)
|
||||
// SAFETY: the caller has to guarantee that `start - n` doesn't overflow.
|
||||
unsafe { start.unchecked_sub(n as Self) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -450,21 +452,33 @@ unsafe impl Step for char {
|
|||
#[inline]
|
||||
unsafe fn forward_unchecked(start: char, count: usize) -> char {
|
||||
let start = start as u32;
|
||||
let mut res = Step::forward_unchecked(start, count);
|
||||
// SAFETY: the caller must guarantee that this doesn't overflow
|
||||
// the range of values for a char.
|
||||
let mut res = unsafe { Step::forward_unchecked(start, count) };
|
||||
if start < 0xD800 && 0xD800 <= res {
|
||||
res = Step::forward_unchecked(res, 0x800);
|
||||
// SAFETY: the caller must guarantee that this doesn't overflow
|
||||
// the range of values for a char.
|
||||
res = unsafe { Step::forward_unchecked(res, 0x800) };
|
||||
}
|
||||
char::from_u32_unchecked(res)
|
||||
// SAFETY: because of the previous contract, this is guaranteed
|
||||
// by the caller to be a valid char.
|
||||
unsafe { char::from_u32_unchecked(res) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn backward_unchecked(start: char, count: usize) -> char {
|
||||
let start = start as u32;
|
||||
let mut res = Step::backward_unchecked(start, count);
|
||||
// SAFETY: the caller must guarantee that this doesn't overflow
|
||||
// the range of values for a char.
|
||||
let mut res = unsafe { Step::backward_unchecked(start, count) };
|
||||
if start >= 0xE000 && 0xE000 > res {
|
||||
res = Step::backward_unchecked(res, 0x800);
|
||||
// SAFETY: the caller must guarantee that this doesn't overflow
|
||||
// the range of values for a char.
|
||||
res = unsafe { Step::backward_unchecked(res, 0x800) };
|
||||
}
|
||||
char::from_u32_unchecked(res)
|
||||
// SAFETY: because of the previous contract, this is guaranteed
|
||||
// by the caller to be a valid char.
|
||||
unsafe { char::from_u32_unchecked(res) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -122,7 +122,9 @@ impl<T> ManuallyDrop<T> {
|
|||
#[stable(feature = "manually_drop_take", since = "1.42.0")]
|
||||
#[inline]
|
||||
pub unsafe fn take(slot: &mut ManuallyDrop<T>) -> T {
|
||||
ptr::read(&slot.value)
|
||||
// SAFETY: we are reading from a reference, which is guaranteed
|
||||
// to be valid for reads.
|
||||
unsafe { ptr::read(&slot.value) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -152,7 +154,10 @@ impl<T: ?Sized> ManuallyDrop<T> {
|
|||
#[stable(feature = "manually_drop", since = "1.20.0")]
|
||||
#[inline]
|
||||
pub unsafe fn drop(slot: &mut ManuallyDrop<T>) {
|
||||
ptr::drop_in_place(&mut slot.value)
|
||||
// SAFETY: we are dropping the value pointed to by a mutable reference
|
||||
// which is guaranteed to be valid for writes.
|
||||
// It is up to the caller to make sure that `slot` isn't dropped again.
|
||||
unsafe { ptr::drop_in_place(&mut slot.value) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -494,8 +494,12 @@ impl<T> MaybeUninit<T> {
|
|||
#[inline(always)]
|
||||
#[rustc_diagnostic_item = "assume_init"]
|
||||
pub unsafe fn assume_init(self) -> T {
|
||||
intrinsics::assert_inhabited::<T>();
|
||||
ManuallyDrop::into_inner(self.value)
|
||||
// SAFETY: the caller must guarantee that `self` is initialized.
|
||||
// This also means that `self` must be a `value` variant.
|
||||
unsafe {
|
||||
intrinsics::assert_inhabited::<T>();
|
||||
ManuallyDrop::into_inner(self.value)
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads the value from the `MaybeUninit<T>` container. The resulting `T` is subject
|
||||
|
|
@ -558,8 +562,12 @@ impl<T> MaybeUninit<T> {
|
|||
#[unstable(feature = "maybe_uninit_extra", issue = "63567")]
|
||||
#[inline(always)]
|
||||
pub unsafe fn read(&self) -> T {
|
||||
intrinsics::assert_inhabited::<T>();
|
||||
self.as_ptr().read()
|
||||
// SAFETY: the caller must guarantee that `self` is initialized.
|
||||
// Reading from `self.as_ptr()` is safe since `self` should be initialized.
|
||||
unsafe {
|
||||
intrinsics::assert_inhabited::<T>();
|
||||
self.as_ptr().read()
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a shared reference to the contained value.
|
||||
|
|
@ -620,8 +628,12 @@ impl<T> MaybeUninit<T> {
|
|||
#[unstable(feature = "maybe_uninit_ref", issue = "63568")]
|
||||
#[inline(always)]
|
||||
pub unsafe fn get_ref(&self) -> &T {
|
||||
intrinsics::assert_inhabited::<T>();
|
||||
&*self.value
|
||||
// SAFETY: the caller must guarantee that `self` is initialized.
|
||||
// This also means that `self` must be a `value` variant.
|
||||
unsafe {
|
||||
intrinsics::assert_inhabited::<T>();
|
||||
&*self.value
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a mutable (unique) reference to the contained value.
|
||||
|
|
@ -738,8 +750,12 @@ impl<T> MaybeUninit<T> {
|
|||
#[unstable(feature = "maybe_uninit_ref", issue = "63568")]
|
||||
#[inline(always)]
|
||||
pub unsafe fn get_mut(&mut self) -> &mut T {
|
||||
intrinsics::assert_inhabited::<T>();
|
||||
&mut *self.value
|
||||
// SAFETY: the caller must guarantee that `self` is initialized.
|
||||
// This also means that `self` must be a `value` variant.
|
||||
unsafe {
|
||||
intrinsics::assert_inhabited::<T>();
|
||||
&mut *self.value
|
||||
}
|
||||
}
|
||||
|
||||
/// Assuming all the elements are initialized, get a slice to them.
|
||||
|
|
@ -752,7 +768,11 @@ impl<T> MaybeUninit<T> {
|
|||
#[unstable(feature = "maybe_uninit_slice_assume_init", issue = "none")]
|
||||
#[inline(always)]
|
||||
pub unsafe fn slice_get_ref(slice: &[Self]) -> &[T] {
|
||||
&*(slice as *const [Self] as *const [T])
|
||||
// SAFETY: casting slice to a `*const [T]` is safe since the caller guarantees that
|
||||
// `slice` is initialized, and`MaybeUninit` is guaranteed to have the same layout as `T`.
|
||||
// The pointer obtained is valid since it refers to memory owned by `slice` which is a
|
||||
// reference and thus guaranteed to be valid for reads.
|
||||
unsafe { &*(slice as *const [Self] as *const [T]) }
|
||||
}
|
||||
|
||||
/// Assuming all the elements are initialized, get a mutable slice to them.
|
||||
|
|
@ -765,7 +785,9 @@ impl<T> MaybeUninit<T> {
|
|||
#[unstable(feature = "maybe_uninit_slice_assume_init", issue = "none")]
|
||||
#[inline(always)]
|
||||
pub unsafe fn slice_get_mut(slice: &mut [Self]) -> &mut [T] {
|
||||
&mut *(slice as *mut [Self] as *mut [T])
|
||||
// SAFETY: similar to safety notes for `slice_get_ref`, but we have a
|
||||
// mutable reference which is also guaranteed to be valid for writes.
|
||||
unsafe { &mut *(slice as *mut [Self] as *mut [T]) }
|
||||
}
|
||||
|
||||
/// Gets a pointer to the first element of the array.
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
//! types, initializing and manipulating memory.
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
use crate::clone;
|
||||
use crate::cmp;
|
||||
|
|
@ -623,8 +624,11 @@ pub const fn needs_drop<T>() -> bool {
|
|||
#[allow(deprecated)]
|
||||
#[rustc_diagnostic_item = "mem_zeroed"]
|
||||
pub unsafe fn zeroed<T>() -> T {
|
||||
intrinsics::assert_zero_valid::<T>();
|
||||
MaybeUninit::zeroed().assume_init()
|
||||
// SAFETY: the caller must guarantee that an all-zero value is valid for `T`.
|
||||
unsafe {
|
||||
intrinsics::assert_zero_valid::<T>();
|
||||
MaybeUninit::zeroed().assume_init()
|
||||
}
|
||||
}
|
||||
|
||||
/// Bypasses Rust's normal memory-initialization checks by pretending to
|
||||
|
|
@ -656,8 +660,11 @@ pub unsafe fn zeroed<T>() -> T {
|
|||
#[allow(deprecated)]
|
||||
#[rustc_diagnostic_item = "mem_uninitialized"]
|
||||
pub unsafe fn uninitialized<T>() -> T {
|
||||
intrinsics::assert_uninit_valid::<T>();
|
||||
MaybeUninit::uninit().assume_init()
|
||||
// SAFETY: the caller must guarantee that an unitialized value is valid for `T`.
|
||||
unsafe {
|
||||
intrinsics::assert_uninit_valid::<T>();
|
||||
MaybeUninit::uninit().assume_init()
|
||||
}
|
||||
}
|
||||
|
||||
/// Swaps the values at two mutable locations, without deinitializing either one.
|
||||
|
|
@ -922,9 +929,14 @@ pub fn drop<T>(_x: T) {}
|
|||
pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
|
||||
// If U has a higher alignment requirement, src may not be suitably aligned.
|
||||
if align_of::<U>() > align_of::<T>() {
|
||||
ptr::read_unaligned(src as *const T as *const U)
|
||||
// SAFETY: `src` is a reference which is guaranteed to be valid for reads.
|
||||
// The caller must guarantee that the actual transmutation is safe.
|
||||
unsafe { ptr::read_unaligned(src as *const T as *const U) }
|
||||
} else {
|
||||
ptr::read(src as *const T as *const U)
|
||||
// SAFETY: `src` is a reference which is guaranteed to be valid for reads.
|
||||
// We just checked that `src as *const U` was properly aligned.
|
||||
// The caller must guarantee that the actual transmutation is safe.
|
||||
unsafe { ptr::read(src as *const T as *const U) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue