about summary refs log tree commit diff
path: root/src/libcore/ptr
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-07-05 13:53:07 +0200
committerGitHub <noreply@github.com>2019-07-05 13:53:07 +0200
commitd3569ddf320cc7bb33f53483892fc3f8204dc62a (patch)
treebc79c7b585546a1f981595167ce3da55991528b6 /src/libcore/ptr
parent84527e4676e21a574ff7d20d9680283cead0e828 (diff)
parent54527db7b0316b3921f3f66bdc58cf3377c37902 (diff)
downloadrust-d3569ddf320cc7bb33f53483892fc3f8204dc62a.tar.gz
rust-d3569ddf320cc7bb33f53483892fc3f8204dc62a.zip
Rollup merge of #62323 - Centril:clarify-read-unaligned, r=RalfJung
Clarify unaligned fields in ptr::{read,write}_unaligned

r? @RalfJung
Diffstat (limited to 'src/libcore/ptr')
-rw-r--r--src/libcore/ptr/mod.rs88
1 files changed, 53 insertions, 35 deletions
diff --git a/src/libcore/ptr/mod.rs b/src/libcore/ptr/mod.rs
index da781d7e9fe..2a6c2b1331e 100644
--- a/src/libcore/ptr/mod.rs
+++ b/src/libcore/ptr/mod.rs
@@ -625,42 +625,50 @@ pub unsafe fn read<T>(src: *const T) -> T {
 /// [read-ownership]: ./fn.read.html#ownership-of-the-returned-value
 /// [valid]: ../ptr/index.html#safety
 ///
-/// # Examples
+/// ## On `packed` structs
 ///
-/// Access members of a packed struct by reference:
+/// It is currently impossible to create raw pointers to unaligned fields
+/// of a packed struct.
 ///
-/// ```
-/// use std::ptr;
+/// Attempting to create a raw pointer to an `unaligned` struct field with
+/// an expression such as `&packed.unaligned as *const FieldType` creates an
+/// intermediate unaligned reference before converting that to a raw pointer.
+/// That this reference is temporary and immediately cast is inconsequential
+/// as the compiler always expects references to be properly aligned.
+/// As a result, using `&packed.unaligned as *const FieldType` causes immediate
+/// *undefined behavior* in your program.
 ///
+/// An example of what not to do and how this relates to `read_unaligned` is:
+///
+/// ```no_run
 /// #[repr(packed, C)]
 /// struct Packed {
 ///     _padding: u8,
 ///     unaligned: u32,
 /// }
 ///
-/// let x = Packed {
+/// let packed = Packed {
 ///     _padding: 0x00,
 ///     unaligned: 0x01020304,
 /// };
 ///
 /// let v = unsafe {
-///     // Take the address of a 32-bit integer which is not aligned.
-///     // This must be done as a raw pointer; unaligned references are invalid.
-///     let unaligned = &x.unaligned as *const u32;
-///
-///     // Dereferencing normally will emit an aligned load instruction,
-///     // causing undefined behavior.
-///     // let v = *unaligned; // ERROR
+///     // Here we attempt to take the address of a 32-bit integer which is not aligned.
+///     let unaligned =
+///         // A temporary unaligned reference is created here which results in
+///         // undefined behavior regardless of whether the reference is used or not.
+///         &packed.unaligned
+///         // Casting to a raw pointer doesn't help; the mistake already happened.
+///         as *const u32;
 ///
-///     // Instead, use `read_unaligned` to read improperly aligned values.
-///     let v = ptr::read_unaligned(unaligned);
+///     let v = std::ptr::read_unaligned(unaligned);
 ///
 ///     v
 /// };
-///
-/// // Accessing unaligned values directly is safe.
-/// assert!(x.unaligned == v);
 /// ```
+///
+/// Accessing unaligned fields directly with e.g. `packed.unaligned` is safe however.
+// FIXME: Update docs based on outcome of RFC #2582 and friends.
 #[inline]
 #[stable(feature = "ptr_unaligned", since = "1.17.0")]
 pub unsafe fn read_unaligned<T>(src: *const T) -> T {
@@ -789,38 +797,48 @@ pub unsafe fn write<T>(dst: *mut T, src: T) {
 ///
 /// [valid]: ../ptr/index.html#safety
 ///
-/// # Examples
+/// ## On `packed` structs
 ///
-/// Access fields in a packed struct:
+/// It is currently impossible to create raw pointers to unaligned fields
+/// of a packed struct.
 ///
-/// ```
-/// use std::{mem, ptr};
+/// Attempting to create a raw pointer to an `unaligned` struct field with
+/// an expression such as `&packed.unaligned as *const FieldType` creates an
+/// intermediate unaligned reference before converting that to a raw pointer.
+/// That this reference is temporary and immediately cast is inconsequential
+/// as the compiler always expects references to be properly aligned.
+/// As a result, using `&packed.unaligned as *const FieldType` causes immediate
+/// *undefined behavior* in your program.
 ///
+/// An example of what not to do and how this relates to `write_unaligned` is:
+///
+/// ```no_run
 /// #[repr(packed, C)]
-/// #[derive(Default)]
 /// struct Packed {
 ///     _padding: u8,
 ///     unaligned: u32,
 /// }
 ///
 /// let v = 0x01020304;
-/// let mut x: Packed = unsafe { mem::zeroed() };
-///
-/// unsafe {
-///     // Take a reference to a 32-bit integer which is not aligned.
-///     let unaligned = &mut x.unaligned as *mut u32;
+/// let mut packed: Packed = unsafe { std::mem::zeroed() };
 ///
-///     // Dereferencing normally will emit an aligned store instruction,
-///     // causing undefined behavior because the pointer is not aligned.
-///     // *unaligned = v; // ERROR
+/// let v = unsafe {
+///     // Here we attempt to take the address of a 32-bit integer which is not aligned.
+///     let unaligned =
+///         // A temporary unaligned reference is created here which results in
+///         // undefined behavior regardless of whether the reference is used or not.
+///         &mut packed.unaligned
+///         // Casting to a raw pointer doesn't help; the mistake already happened.
+///         as *mut u32;
 ///
-///     // Instead, use `write_unaligned` to write improperly aligned values.
-///     ptr::write_unaligned(unaligned, v);
-/// }
+///     std::ptr::write_unaligned(unaligned, v);
 ///
-/// // Accessing unaligned values directly is safe.
-/// assert!(x.unaligned == v);
+///     v
+/// };
 /// ```
+///
+/// Accessing unaligned fields directly with e.g. `packed.unaligned` is safe however.
+// FIXME: Update docs based on outcome of RFC #2582 and friends.
 #[inline]
 #[stable(feature = "ptr_unaligned", since = "1.17.0")]
 pub unsafe fn write_unaligned<T>(dst: *mut T, src: T) {