From 75fe727b785b43c5f31601adc19233d2efb186f0 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 11 Dec 2016 18:51:22 -0800 Subject: [PATCH] Implement RFC #1725 cc #37955 --- src/libcore/ptr.rs | 83 ++++++++++++++++++++++++++++++++++++++++++ src/libcoretest/lib.rs | 1 + src/libcoretest/ptr.rs | 23 ++++++++++++ 3 files changed, 107 insertions(+) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 2ad38de72b1..e3ca8eca76c 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -117,6 +117,8 @@ pub unsafe fn replace(dest: *mut T, mut src: T) -> T { /// `zero_memory`, or `copy_memory`). Note that `*src = foo` counts as a use /// because it will attempt to drop the value previously at `*src`. /// +/// The pointer must be aligned; use `read_unaligned` if that is not the case. +/// /// # Examples /// /// Basic usage: @@ -137,6 +139,44 @@ pub unsafe fn read(src: *const T) -> T { tmp } +/// Reads the value from `src` without moving it. This leaves the +/// memory in `src` unchanged. +/// +/// Unlike `read`, the pointer may be unaligned. +/// +/// # Safety +/// +/// Beyond accepting a raw pointer, this is unsafe because it semantically +/// moves the value out of `src` without preventing further usage of `src`. +/// If `T` is not `Copy`, then care must be taken to ensure that the value at +/// `src` is not used before the data is overwritten again (e.g. with `write`, +/// `zero_memory`, or `copy_memory`). Note that `*src = foo` counts as a use +/// because it will attempt to drop the value previously at `*src`. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// #![feature(ptr_unaligned)] +/// +/// let x = 12; +/// let y = &x as *const i32; +/// +/// unsafe { +/// assert_eq!(std::ptr::read_unaligned(y), 12); +/// } +/// ``` +#[inline(always)] +#[unstable(feature = "ptr_unaligned", issue = "37955")] +pub unsafe fn read_unaligned(src: *const T) -> T { + let mut tmp: T = mem::uninitialized(); + copy_nonoverlapping(src as *const u8, + &mut tmp as *mut T as *mut u8, + mem::size_of::()); + tmp +} + /// Overwrites a memory location with the given value without reading or /// dropping the old value. /// @@ -151,6 +191,8 @@ pub unsafe fn read(src: *const T) -> T { /// This is appropriate for initializing uninitialized memory, or overwriting /// memory that has previously been `read` from. /// +/// The pointer must be aligned; use `write_unaligned` if that is not the case. +/// /// # Examples /// /// Basic usage: @@ -171,6 +213,47 @@ pub unsafe fn write(dst: *mut T, src: T) { intrinsics::move_val_init(&mut *dst, src) } +/// Overwrites a memory location with the given value without reading or +/// dropping the old value. +/// +/// Unlike `write`, the pointer may be unaligned. +/// +/// # Safety +/// +/// This operation is marked unsafe because it accepts a raw pointer. +/// +/// It does not drop the contents of `dst`. This is safe, but it could leak +/// allocations or resources, so care must be taken not to overwrite an object +/// that should be dropped. +/// +/// This is appropriate for initializing uninitialized memory, or overwriting +/// memory that has previously been `read` from. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// #![feature(ptr_unaligned)] +/// +/// let mut x = 0; +/// let y = &mut x as *mut i32; +/// let z = 12; +/// +/// unsafe { +/// std::ptr::write_unaligned(y, z); +/// assert_eq!(std::ptr::read_unaligned(y), 12); +/// } +/// ``` +#[inline] +#[unstable(feature = "ptr_unaligned", issue = "37955")] +pub unsafe fn write_unaligned(dst: *mut T, src: T) { + copy_nonoverlapping(&src as *const T as *const u8, + dst as *mut u8, + mem::size_of::()); + mem::forget(src); +} + /// Performs a volatile read of the value from `src` without moving it. This /// leaves the memory in `src` unchanged. /// diff --git a/src/libcoretest/lib.rs b/src/libcoretest/lib.rs index b8c01e570f5..5b6686309a4 100644 --- a/src/libcoretest/lib.rs +++ b/src/libcoretest/lib.rs @@ -36,6 +36,7 @@ #![feature(iter_min_by)] #![feature(ordering_chaining)] #![feature(result_unwrap_or_default)] +#![feature(ptr_unaligned)] extern crate core; extern crate test; diff --git a/src/libcoretest/ptr.rs b/src/libcoretest/ptr.rs index f7fe61896f8..7f6f472bfbb 100644 --- a/src/libcoretest/ptr.rs +++ b/src/libcoretest/ptr.rs @@ -9,6 +9,7 @@ // except according to those terms. use core::ptr::*; +use core::cell::RefCell; #[test] fn test() { @@ -189,3 +190,25 @@ pub fn test_variadic_fnptr() { let mut s = SipHasher::new(); assert_eq!(p.hash(&mut s), q.hash(&mut s)); } + +#[test] +fn write_unaligned_drop() { + thread_local! { + static DROPS: RefCell> = RefCell::new(Vec::new()); + } + + struct Dropper(u32); + + impl Drop for Dropper { + fn drop(&mut self) { + DROPS.with(|d| d.borrow_mut().push(self.0)); + } + } + + { + let c = Dropper(0); + let mut t = Dropper(1); + unsafe { write_unaligned(&mut t, c); } + } + DROPS.with(|d| assert_eq!(*d.borrow(), [0])); +}