From 21b502b275ca7d9a7f43c4e1cf09b0b547ecc645 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 20 Jul 2019 13:19:36 +0200 Subject: [PATCH 1/8] warn that raw pointers must be aligned when used, and that writes cause drop --- src/libstd/primitive_docs.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 65fd8c83e1ce5..cab58799d68d4 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -362,8 +362,11 @@ mod prim_unit { } /// /// *[See also the `std::ptr` module](ptr/index.html).* /// -/// Working with raw pointers in Rust is uncommon, -/// typically limited to a few patterns. +/// Working with raw pointers in Rust is uncommon, typically limited to a few patterns. +/// Raw pointers can be unaligned or null when unused. However, when a raw pointer is used to +/// load/store data from/to memory, they must be non-null and aligned. +/// Storing through a raw pointer (`*ptr = data`) calls `drop` on the old value, so +/// [`write`] must be used if memory is not already initialized. /// /// Use the [`null`] and [`null_mut`] functions to create null pointers, and the /// [`is_null`] method of the `*const T` and `*mut T` types to check for null. @@ -442,6 +445,7 @@ mod prim_unit { } /// [`offset`]: ../std/primitive.pointer.html#method.offset /// [`into_raw`]: ../std/boxed/struct.Box.html#method.into_raw /// [`drop`]: ../std/mem/fn.drop.html +/// [`write`]: ../std/ptr/fn.write.html #[stable(feature = "rust1", since = "1.0.0")] mod prim_pointer { } From 2e6b13a649ce4a8f5a608d10133dd2b4b30c35c1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 20 Jul 2019 13:20:08 +0200 Subject: [PATCH 2/8] references must be aligned; also move up the warning that fn ptrs must be non-NULL --- src/libstd/primitive_docs.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index cab58799d68d4..95b803e3461ec 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -895,9 +895,9 @@ mod prim_usize { } /// A reference represents a borrow of some owned value. You can get one by using the `&` or `&mut` /// operators on a value, or by using a `ref` or `ref mut` pattern. /// -/// For those familiar with pointers, a reference is just a pointer that is assumed to not be null. -/// In fact, `Option<&T>` has the same memory representation as a nullable pointer, and can be -/// passed across FFI boundaries as such. +/// For those familiar with pointers, a reference is just a pointer that is assumed to be +/// aligned and not null. In fact, `Option<&T>` has the same memory representation as a +/// nullable but aligned pointer, and can be passed across FFI boundaries as such. /// /// In most cases, references can be used much like the original value. Field access, method /// calling, and indexing work the same (save for mutability rules, of course). In addition, the @@ -1040,6 +1040,11 @@ mod prim_ref { } /// [`FnMut`]: ops/trait.FnMut.html /// [`FnOnce`]: ops/trait.FnOnce.html /// +/// Function pointers are pointers that point to *code*, not data. They can be called +/// just like functions. Like references, function pointers are assumed to not be null, +/// so if you want to pass a function pointer over FFI and be able to accommodate null pointers, +/// make your type `Option` with your required signature. +/// /// Plain function pointers are obtained by casting either plain functions, or closures that don't /// capture an environment: /// @@ -1095,10 +1100,6 @@ mod prim_ref { } /// /// These markers can be combined, so `unsafe extern "stdcall" fn()` is a valid type. /// -/// Like references in rust, function pointers are assumed to not be null, so if you want to pass a -/// function pointer over FFI and be able to accommodate null pointers, make your type -/// `Option` with your required signature. -/// /// Function pointers implement the following traits: /// /// * [`Clone`] From f502bf78cba8974cdfbd20f3b524d86b982e5e2b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Jul 2019 12:08:19 +0200 Subject: [PATCH 3/8] sync with nomicon: raw ptr must be non-dangling and aligned every time it is dereferenced --- src/libstd/primitive_docs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 95b803e3461ec..0f66e8cd47ea3 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -363,8 +363,8 @@ mod prim_unit { } /// *[See also the `std::ptr` module](ptr/index.html).* /// /// Working with raw pointers in Rust is uncommon, typically limited to a few patterns. -/// Raw pointers can be unaligned or null when unused. However, when a raw pointer is used to -/// load/store data from/to memory, they must be non-null and aligned. +/// Raw pointers can be unaligned or null when unused. However, when a raw pointer is +/// dereferenced (using the `*` operator), it must be non-null and aligned. /// Storing through a raw pointer (`*ptr = data`) calls `drop` on the old value, so /// [`write`] must be used if memory is not already initialized. /// From 40812224cad0d8b89d52fc1ffc3d44e1615794d4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Jul 2019 12:13:57 +0200 Subject: [PATCH 4/8] apply feedback --- src/libstd/primitive_docs.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 0f66e8cd47ea3..5fa15f1fbde36 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -363,10 +363,11 @@ mod prim_unit { } /// *[See also the `std::ptr` module](ptr/index.html).* /// /// Working with raw pointers in Rust is uncommon, typically limited to a few patterns. -/// Raw pointers can be unaligned or null when unused. However, when a raw pointer is +/// Raw pointers can be unaligned or [`null`] when unused. However, when a raw pointer is /// dereferenced (using the `*` operator), it must be non-null and aligned. -/// Storing through a raw pointer (`*ptr = data`) calls `drop` on the old value, so -/// [`write`] must be used if memory is not already initialized. +/// Storing through a raw pointer using `*ptr = data` calls `drop` on the old value, so +/// [`write`] must be used if memory is not already initialized---otherwise `drop` +/// would be called on the uninitialized memory. /// /// Use the [`null`] and [`null_mut`] functions to create null pointers, and the /// [`is_null`] method of the `*const T` and `*mut T` types to check for null. @@ -896,7 +897,8 @@ mod prim_usize { } /// operators on a value, or by using a `ref` or `ref mut` pattern. /// /// For those familiar with pointers, a reference is just a pointer that is assumed to be -/// aligned and not null. In fact, `Option<&T>` has the same memory representation as a +/// aligned, not null, and pointing to valid (initialized) memory. +/// In fact, `Option<&T>` has the same memory representation as a /// nullable but aligned pointer, and can be passed across FFI boundaries as such. /// /// In most cases, references can be used much like the original value. Field access, method From a7b924654070f59297e86ff372ac74c5c701929f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Jul 2019 10:33:11 +0200 Subject: [PATCH 5/8] weasle, weasle --- src/libstd/primitive_docs.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 5fa15f1fbde36..b7196a8670138 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -1043,9 +1043,9 @@ mod prim_ref { } /// [`FnOnce`]: ops/trait.FnOnce.html /// /// Function pointers are pointers that point to *code*, not data. They can be called -/// just like functions. Like references, function pointers are assumed to not be null, -/// so if you want to pass a function pointer over FFI and be able to accommodate null pointers, -/// make your type `Option` with your required signature. +/// just like functions. Like references, function pointers are, among other things, assumed to +/// not be null, so if you want to pass a function pointer over FFI and be able to accommodate null +/// pointers, make your type `Option` with your required signature. /// /// Plain function pointers are obtained by casting either plain functions, or closures that don't /// capture an environment: From 91967816c3851b4b796ce774bde49a9f47681bca Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Jul 2019 15:32:58 +0200 Subject: [PATCH 6/8] account for non-drop-glue types --- src/libstd/primitive_docs.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index b7196a8670138..ead1987d04b56 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -365,9 +365,10 @@ mod prim_unit { } /// Working with raw pointers in Rust is uncommon, typically limited to a few patterns. /// Raw pointers can be unaligned or [`null`] when unused. However, when a raw pointer is /// dereferenced (using the `*` operator), it must be non-null and aligned. +/// /// Storing through a raw pointer using `*ptr = data` calls `drop` on the old value, so -/// [`write`] must be used if memory is not already initialized---otherwise `drop` -/// would be called on the uninitialized memory. +/// [`write`] must be used if the type has drop glue and memory is not already +/// initialized---otherwise `drop` would be called on the uninitialized memory. /// /// Use the [`null`] and [`null_mut`] functions to create null pointers, and the /// [`is_null`] method of the `*const T` and `*mut T` types to check for null. From dd5045ed630b7577296087f09f559bb9c08f68e2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Jul 2019 17:48:01 +0200 Subject: [PATCH 7/8] Apply suggestions from code review Co-Authored-By: gnzlbg --- src/libstd/primitive_docs.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index ead1987d04b56..b79cfa3eead23 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -363,12 +363,12 @@ mod prim_unit { } /// *[See also the `std::ptr` module](ptr/index.html).* /// /// Working with raw pointers in Rust is uncommon, typically limited to a few patterns. -/// Raw pointers can be unaligned or [`null`] when unused. However, when a raw pointer is +/// Raw pointers can be unaligned or [`null`]. However, when a raw pointer is /// dereferenced (using the `*` operator), it must be non-null and aligned. /// /// Storing through a raw pointer using `*ptr = data` calls `drop` on the old value, so /// [`write`] must be used if the type has drop glue and memory is not already -/// initialized---otherwise `drop` would be called on the uninitialized memory. +/// initialized - otherwise `drop` would be called on the uninitialized memory. /// /// Use the [`null`] and [`null_mut`] functions to create null pointers, and the /// [`is_null`] method of the `*const T` and `*mut T` types to check for null. @@ -898,7 +898,10 @@ mod prim_usize { } /// operators on a value, or by using a `ref` or `ref mut` pattern. /// /// For those familiar with pointers, a reference is just a pointer that is assumed to be -/// aligned, not null, and pointing to valid (initialized) memory. +/// aligned, not null, and pointing to memory containing a valid value of `T` - for example, +/// `&bool` can only point to an allocation containing the integer values `1` (`true`) or `0` +/// (`false`), but the behavior of creating a `&bool` that points to an allocation containing +/// the value `3` is undefined. /// In fact, `Option<&T>` has the same memory representation as a /// nullable but aligned pointer, and can be passed across FFI boundaries as such. /// From 65cf10d90276e40bd8cc27a79d6c6f0d13e0cc7a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Jul 2019 17:51:52 +0200 Subject: [PATCH 8/8] word things more like we usually do --- src/libstd/primitive_docs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index b79cfa3eead23..d9a3da66a6786 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -900,8 +900,8 @@ mod prim_usize { } /// For those familiar with pointers, a reference is just a pointer that is assumed to be /// aligned, not null, and pointing to memory containing a valid value of `T` - for example, /// `&bool` can only point to an allocation containing the integer values `1` (`true`) or `0` -/// (`false`), but the behavior of creating a `&bool` that points to an allocation containing -/// the value `3` is undefined. +/// (`false`), but creating a `&bool` that points to an allocation containing +/// the value `3` causes undefined behaviour. /// In fact, `Option<&T>` has the same memory representation as a /// nullable but aligned pointer, and can be passed across FFI boundaries as such. ///