Skip to content

Commit 0d1b9f4

Browse files
committed
Auto merge of #38309 - sfackler:rfc-1725, r=alexcrichton
Implement RFC #1725 (read_unaligned, write_unaligned) cc #37955 r? @alexcrichton
2 parents ace092f + 75fe727 commit 0d1b9f4

File tree

3 files changed

+107
-0
lines changed

3 files changed

+107
-0
lines changed

src/libcore/ptr.rs

+83
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ pub unsafe fn replace<T>(dest: *mut T, mut src: T) -> T {
117117
/// `zero_memory`, or `copy_memory`). Note that `*src = foo` counts as a use
118118
/// because it will attempt to drop the value previously at `*src`.
119119
///
120+
/// The pointer must be aligned; use `read_unaligned` if that is not the case.
121+
///
120122
/// # Examples
121123
///
122124
/// Basic usage:
@@ -137,6 +139,44 @@ pub unsafe fn read<T>(src: *const T) -> T {
137139
tmp
138140
}
139141

142+
/// Reads the value from `src` without moving it. This leaves the
143+
/// memory in `src` unchanged.
144+
///
145+
/// Unlike `read`, the pointer may be unaligned.
146+
///
147+
/// # Safety
148+
///
149+
/// Beyond accepting a raw pointer, this is unsafe because it semantically
150+
/// moves the value out of `src` without preventing further usage of `src`.
151+
/// If `T` is not `Copy`, then care must be taken to ensure that the value at
152+
/// `src` is not used before the data is overwritten again (e.g. with `write`,
153+
/// `zero_memory`, or `copy_memory`). Note that `*src = foo` counts as a use
154+
/// because it will attempt to drop the value previously at `*src`.
155+
///
156+
/// # Examples
157+
///
158+
/// Basic usage:
159+
///
160+
/// ```
161+
/// #![feature(ptr_unaligned)]
162+
///
163+
/// let x = 12;
164+
/// let y = &x as *const i32;
165+
///
166+
/// unsafe {
167+
/// assert_eq!(std::ptr::read_unaligned(y), 12);
168+
/// }
169+
/// ```
170+
#[inline(always)]
171+
#[unstable(feature = "ptr_unaligned", issue = "37955")]
172+
pub unsafe fn read_unaligned<T>(src: *const T) -> T {
173+
let mut tmp: T = mem::uninitialized();
174+
copy_nonoverlapping(src as *const u8,
175+
&mut tmp as *mut T as *mut u8,
176+
mem::size_of::<T>());
177+
tmp
178+
}
179+
140180
/// Overwrites a memory location with the given value without reading or
141181
/// dropping the old value.
142182
///
@@ -151,6 +191,8 @@ pub unsafe fn read<T>(src: *const T) -> T {
151191
/// This is appropriate for initializing uninitialized memory, or overwriting
152192
/// memory that has previously been `read` from.
153193
///
194+
/// The pointer must be aligned; use `write_unaligned` if that is not the case.
195+
///
154196
/// # Examples
155197
///
156198
/// Basic usage:
@@ -171,6 +213,47 @@ pub unsafe fn write<T>(dst: *mut T, src: T) {
171213
intrinsics::move_val_init(&mut *dst, src)
172214
}
173215

216+
/// Overwrites a memory location with the given value without reading or
217+
/// dropping the old value.
218+
///
219+
/// Unlike `write`, the pointer may be unaligned.
220+
///
221+
/// # Safety
222+
///
223+
/// This operation is marked unsafe because it accepts a raw pointer.
224+
///
225+
/// It does not drop the contents of `dst`. This is safe, but it could leak
226+
/// allocations or resources, so care must be taken not to overwrite an object
227+
/// that should be dropped.
228+
///
229+
/// This is appropriate for initializing uninitialized memory, or overwriting
230+
/// memory that has previously been `read` from.
231+
///
232+
/// # Examples
233+
///
234+
/// Basic usage:
235+
///
236+
/// ```
237+
/// #![feature(ptr_unaligned)]
238+
///
239+
/// let mut x = 0;
240+
/// let y = &mut x as *mut i32;
241+
/// let z = 12;
242+
///
243+
/// unsafe {
244+
/// std::ptr::write_unaligned(y, z);
245+
/// assert_eq!(std::ptr::read_unaligned(y), 12);
246+
/// }
247+
/// ```
248+
#[inline]
249+
#[unstable(feature = "ptr_unaligned", issue = "37955")]
250+
pub unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
251+
copy_nonoverlapping(&src as *const T as *const u8,
252+
dst as *mut u8,
253+
mem::size_of::<T>());
254+
mem::forget(src);
255+
}
256+
174257
/// Performs a volatile read of the value from `src` without moving it. This
175258
/// leaves the memory in `src` unchanged.
176259
///

src/libcoretest/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#![feature(iter_min_by)]
3737
#![feature(ordering_chaining)]
3838
#![feature(result_unwrap_or_default)]
39+
#![feature(ptr_unaligned)]
3940

4041
extern crate core;
4142
extern crate test;

src/libcoretest/ptr.rs

+23
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
// except according to those terms.
1010

1111
use core::ptr::*;
12+
use core::cell::RefCell;
1213

1314
#[test]
1415
fn test() {
@@ -189,3 +190,25 @@ pub fn test_variadic_fnptr() {
189190
let mut s = SipHasher::new();
190191
assert_eq!(p.hash(&mut s), q.hash(&mut s));
191192
}
193+
194+
#[test]
195+
fn write_unaligned_drop() {
196+
thread_local! {
197+
static DROPS: RefCell<Vec<u32>> = RefCell::new(Vec::new());
198+
}
199+
200+
struct Dropper(u32);
201+
202+
impl Drop for Dropper {
203+
fn drop(&mut self) {
204+
DROPS.with(|d| d.borrow_mut().push(self.0));
205+
}
206+
}
207+
208+
{
209+
let c = Dropper(0);
210+
let mut t = Dropper(1);
211+
unsafe { write_unaligned(&mut t, c); }
212+
}
213+
DROPS.with(|d| assert_eq!(*d.borrow(), [0]));
214+
}

0 commit comments

Comments
 (0)