Skip to content

Commit 3a55c85

Browse files
ecstatic-morseRalfJung
authored andcommitted
Incorporate RalfJung's suggestions
This splits "valid" into "valid for reads" and "valid for writes", and also adds the concept of operation size to validity. Now functions which operate on sequences state that e.g. pointer args must be "valid for reads of size x".
1 parent ea5570c commit 3a55c85

File tree

2 files changed

+49
-52
lines changed

2 files changed

+49
-52
lines changed

src/libcore/intrinsics.rs

Lines changed: 11 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -976,19 +976,15 @@ extern "rust-intrinsic" {
976976
///
977977
/// Behavior is undefined if any of the following conditions are violated:
978978
///
979-
/// * Both `src` and `dst` must be properly aligned.
979+
/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes.
980980
///
981-
/// * `src.offset(i)` must be [valid] for all `i` in `0..count`. In other
982-
/// words, the region of memory which begins at `src` and has a length of
983-
/// `count * size_of::<T>()` bytes must belong to a single, live
984-
/// allocation.
981+
/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes.
985982
///
986-
/// * `dst.offset(i)` must be [valid] for all `i` in `0..count`. In other
987-
/// words, the region of memory which begins at `dst` and has a length of
988-
/// `count * size_of::<T>()` bytes must belong to a single, live
989-
/// allocation.
983+
/// * Both `src` and `dst` must be properly aligned.
990984
///
991-
/// * The two regions of memory must *not* overlap.
985+
/// * The region of memory beginning at `src` with a size of `count *
986+
/// size_of::<T>()` bytes must *not* overlap with the region of memory
987+
/// beginning at `dst` with the same size.
992988
///
993989
/// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of
994990
/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values
@@ -1064,17 +1060,11 @@ extern "rust-intrinsic" {
10641060
///
10651061
/// Behavior is undefined if any of the following conditions are violated:
10661062
///
1067-
/// * Both `src` and `dst` must be properly aligned.
1063+
/// * `src` must be [valid] for reads of `count * size_of::<T>()` bytes.
10681064
///
1069-
/// * `src.offset(i)` must be [valid] for all `i` in `0..count`. In other
1070-
/// words, the region of memory which begins at `src` and has a length of
1071-
/// `count * size_of::<T>()` bytes must belong to a single, live
1072-
/// allocation.
1065+
/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes.
10731066
///
1074-
/// * `dst.offset(i)` must be [valid] for all `i` in `0..count`. In other
1075-
/// words, the region of memory which begins at `dst` and has a length of
1076-
/// `count * size_of::<T>()` bytes must belong to a single, live
1077-
/// allocation.
1067+
/// * Both `src` and `dst` must be properly aligned.
10781068
///
10791069
/// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of
10801070
/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values
@@ -1116,12 +1106,9 @@ extern "rust-intrinsic" {
11161106
///
11171107
/// Behavior is undefined if any of the following conditions are violated:
11181108
///
1119-
/// * `dst` must be properly aligned.
1109+
/// * `dst` must be [valid] for writes of `count * size_of::<T>()` bytes.
11201110
///
1121-
/// * `dst.offset(i)` must be [valid] for all `i` in `0..count`. In other
1122-
/// words, the region of memory which begins at `dst` and has a length of
1123-
/// `count * size_of::<T>()` bytes must belong to a single, live
1124-
/// allocation.
1111+
/// * `dst` must be properly aligned.
11251112
///
11261113
/// Additionally, the caller must ensure that writing `count *
11271114
/// size_of::<T>()` bytes to the given region of memory results in a valid

src/libcore/ptr.rs

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -19,25 +19,38 @@
1919
//! Many functions in this module take raw pointers as arguments and dereference
2020
//! them. For this to be safe, these pointers must be valid. However, because
2121
//! rust does not yet have a formal memory model, determining whether an
22-
//! arbitrary pointer is a valid one can be tricky. One thing is certain:
23-
//! creating a raw pointer from a reference (e.g. `&x as *const _`) *always*
24-
//! results in a valid pointer. By exploiting this—and by taking care when
25-
//! using [pointer arithmetic]—users can be confident in the correctness of
26-
//! their unsafe code.
22+
//! arbitrary pointer is valid for a given operation can be tricky.
2723
//!
28-
//! For more information on dereferencing raw pointers, see the both the [book]
29-
//! and the section in the reference devoted to [undefined behavior][ub].
24+
//! There are two types of operations on memory, reads and writes. It is
25+
//! possible for a `*mut` to be valid for one operation and not the other. Since
26+
//! a `*const` can only be read and not written, it has no such ambiguity. For
27+
//! example, a `*mut` is not valid for writes if a a reference exists which
28+
//! [refers to the same memory][aliasing]. Therefore, each function in this
29+
//! module will document which operations must be valid on any `*mut` arguments.
30+
//!
31+
//! Additionally, some functions (e.g. [`copy`]) take a single pointer but
32+
//! operate on many values. In this case, the function will state the size of
33+
//! the operation for which the pointer must be valid. For example,
34+
//! `copy::<T>(&src, &mut dst, 3)` requires `dst` to be valid for writes of
35+
//! `size_of::<T>() * 3` bytes. When the documentation requires that a pointer
36+
//! be valid for an operation but omits the size of that operation, the size is
37+
//! implied to be `size_of::<T>()` bytes.
38+
//!
39+
//! For more information on the safety implications of dereferencing raw
40+
//! pointers, see the both the [book] and the section in the reference devoted
41+
//! to [undefined behavior][ub].
3042
//!
3143
//! ## Alignment
3244
//!
3345
//! Valid pointers are not necessarily properly aligned. However, most functions
3446
//! require their arguments to be properly aligned, and will explicitly state
35-
//! this requirement in the `Safety` section. Notable exceptions to this are
47+
//! this requirement in their documentation. Notable exceptions to this are
3648
//! [`read_unaligned`] and [`write_unaligned`].
3749
//!
38-
//! [ub]: ../../reference/behavior-considered-undefined.html
50+
//! [aliasing]: ../../nomicon/aliasing.html
3951
//! [book]: ../../book/second-edition/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer
40-
//! [pointer arithmetic]: ../../std/primitive.pointer.html#method.offset
52+
//! [ub]: ../../reference/behavior-considered-undefined.html
53+
//! [`copy`]: ./fn.copy.html
4154
//! [`read_unaligned`]: ./fn.read_unaligned.html
4255
//! [`write_unaligned`]: ./fn.write_unaligned.html
4356
@@ -83,7 +96,7 @@ pub use intrinsics::write_bytes;
8396
///
8497
/// Behavior is undefined if any of the following conditions are violated:
8598
///
86-
/// * `to_drop` must be [valid].
99+
/// * `to_drop` must be [valid] for reads.
87100
///
88101
/// * `to_drop` must be properly aligned.
89102
///
@@ -178,7 +191,7 @@ pub const fn null_mut<T>() -> *mut T { 0 as *mut T }
178191
///
179192
/// Behavior is undefined if any of the following conditions are violated:
180193
///
181-
/// * Both `x` and `y` must be [valid].
194+
/// * Both `x` and `y` must be [valid] for reads and writes.
182195
///
183196
/// * Both `x` and `y` must be properly aligned.
184197
///
@@ -240,17 +253,14 @@ pub unsafe fn swap<T>(x: *mut T, y: *mut T) {
240253
///
241254
/// Behavior is undefined if any of the following conditions are violated:
242255
///
243-
/// * Both `x` and `y` must be properly aligned.
244-
///
245-
/// * `x.offset(i)` must be [valid] for all `i` in `0..count`. In other words,
246-
/// the region of memory which begins at `x` and has a length of `count *
247-
/// size_of::<T>()` bytes must belong to a single, live allocation.
256+
/// * Both `x` and `y` must be [valid] for reads and writes of `count *
257+
/// size_of::<T>()` bytes.
248258
///
249-
/// * `y.offset(i)` must be [valid] for all `i` in `0..count`. In other words,
250-
/// the region of memory which begins at `y` and has a length of `count *
251-
/// size_of::<T>()` bytes must belong to a single, live allocation.
259+
/// * Both `x` and `y` must be properly aligned.
252260
///
253-
/// * The two regions of memory must *not* overlap.
261+
/// * The region of memory beginning at `x` with a size of `count *
262+
/// size_of::<T>()` bytes must *not* overlap with the region of memory
263+
/// beginning at `y` with the same size.
254264
///
255265
/// [valid]: ../ptr/index.html#safety
256266
///
@@ -359,7 +369,7 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) {
359369
///
360370
/// Behavior is undefined if any of the following conditions are violated:
361371
///
362-
/// * `dest` must be [valid].
372+
/// * `dest` must be [valid] for writes.
363373
///
364374
/// * `dest` must be properly aligned.
365375
///
@@ -395,7 +405,7 @@ pub unsafe fn replace<T>(dest: *mut T, mut src: T) -> T {
395405
///
396406
/// Behavior is undefined if any of the following conditions are violated:
397407
///
398-
/// * `src` must be [valid].
408+
/// * `src` must be [valid] for reads.
399409
///
400410
/// * `src` must be properly aligned. Use [`read_unaligned`] if this is not the
401411
/// case.
@@ -508,7 +518,7 @@ pub unsafe fn read<T>(src: *const T) -> T {
508518
///
509519
/// Behavior is undefined if any of the following conditions are violated:
510520
///
511-
/// * `src` must be [valid].
521+
/// * `src` must be [valid] for reads.
512522
///
513523
/// Like [`read`], `read_unaligned` creates a bitwise copy of `T`, regardless of
514524
/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the returned
@@ -585,7 +595,7 @@ pub unsafe fn read_unaligned<T>(src: *const T) -> T {
585595
///
586596
/// Behavior is undefined if any of the following conditions are violated:
587597
///
588-
/// * `dst` must be [valid].
598+
/// * `dst` must be [valid] for writes.
589599
///
590600
/// * `dst` must be properly aligned. Use [`write_unaligned`] if this is not the
591601
/// case.
@@ -659,7 +669,7 @@ pub unsafe fn write<T>(dst: *mut T, src: T) {
659669
///
660670
/// Behavior is undefined if any of the following conditions are violated:
661671
///
662-
/// * `dst` must be [valid].
672+
/// * `dst` must be [valid] for writes.
663673
///
664674
/// [valid]: ../ptr/index.html#safety
665675
///
@@ -734,7 +744,7 @@ pub unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
734744
///
735745
/// Behavior is undefined if any of the following conditions are violated:
736746
///
737-
/// * `src` must be [valid].
747+
/// * `src` must be [valid] for reads.
738748
///
739749
/// * `src` must be properly aligned.
740750
///
@@ -809,7 +819,7 @@ pub unsafe fn read_volatile<T>(src: *const T) -> T {
809819
///
810820
/// Behavior is undefined if any of the following conditions are violated:
811821
///
812-
/// * `dst` must be [valid].
822+
/// * `dst` must be [valid] for writes.
813823
///
814824
/// * `dst` must be properly aligned.
815825
///

0 commit comments

Comments
 (0)