From b29823c3a9eae89e58ae1186715840cda1db164c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 31 Jul 2023 14:45:00 +0200 Subject: [PATCH 1/2] replace 'UB on raw ptr deref' with UB on place projection/access --- src/behavior-considered-undefined.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/behavior-considered-undefined.md b/src/behavior-considered-undefined.md index 9d1732d07..855d89f7c 100644 --- a/src/behavior-considered-undefined.md +++ b/src/behavior-considered-undefined.md @@ -23,9 +23,11 @@ code. * Data races. -* Evaluating a [dereference expression] (`*expr`) on a raw pointer that is - [dangling] or unaligned, even in [place expression context] - (e.g. `addr_of!(*expr)`). +* Accessing (loading from or storing to) a place that is [dangling] or unaligned. +* Performing a place projection that violates the requirements of [in-bounds + pointer arithmetic][offset]. A place projection is a [field + expression][project-field], a [tuple index expression][project-tuple], or an + [array/slice index expression][project-slice]. * Breaking the [pointer aliasing rules]. `Box`, `&mut T` and `&T` follow LLVM’s scoped [noalias] model, except if the `&T` contains an [`UnsafeCell`]. References and boxes must not be [dangling] while they are @@ -124,8 +126,11 @@ must never exceed `isize::MAX`. [Rustonomicon]: ../nomicon/index.html [`NonNull`]: ../core/ptr/struct.NonNull.html [`NonZero*`]: ../core/num/index.html -[dereference expression]: expressions/operator-expr.md#the-dereference-operator [place expression context]: expressions.md#place-expressions-and-value-expressions [rules]: inline-assembly.md#rules-for-inline-assembly [points to]: #pointed-to-bytes [pointed to]: #pointed-to-bytes +[offset]: ../std/primitive.pointer.html#method.offset +[project-field]: expressions/field-expr.md +[project-tuple]: expressions/tuple-expr.md#tuple-indexing-expressions +[project-slice]: expressions/array-expr.md#array-and-slice-indexing-expressions From 051d5d7440b4115b74ab5bb69d4ca054986e26ae Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 22 Aug 2023 19:29:43 +0200 Subject: [PATCH 2/2] explain place alignment --- src/behavior-considered-undefined.md | 35 ++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/behavior-considered-undefined.md b/src/behavior-considered-undefined.md index 855d89f7c..62cfb7b79 100644 --- a/src/behavior-considered-undefined.md +++ b/src/behavior-considered-undefined.md @@ -23,7 +23,8 @@ code. * Data races. -* Accessing (loading from or storing to) a place that is [dangling] or unaligned. +* Accessing (loading from or storing to) a place that is [dangling] or [based on + a misaligned pointer]. * Performing a place projection that violates the requirements of [in-bounds pointer arithmetic][offset]. A place projection is a [field expression][project-field], a [tuple index expression][project-tuple], or an @@ -66,7 +67,7 @@ code. * A `!` (all values are invalid for this type). * An integer (`i*`/`u*`), floating point value (`f*`), or raw pointer obtained from [uninitialized memory][undef], or uninitialized memory in a `str`. - * A reference or `Box` that is [dangling], unaligned, or points to an invalid value. + * A reference or `Box` that is [dangling], misaligned, or points to an invalid value. * Invalid metadata in a wide reference, `Box`, or raw pointer: * `dyn Trait` metadata is invalid if it is not a pointer to a vtable for `Trait` that matches the actual dynamic trait the pointer or reference points to. @@ -100,6 +101,36 @@ reading uninitialized memory is permitted are inside `union`s and in "padding" The span of bytes a pointer or reference "points to" is determined by the pointer value and the size of the pointee type (using `size_of_val`). +### Places based on misaligned pointers +[based on a misaligned pointer]: #places-based-on-misaligned-pointers + +A place is said to be "based on a misaligned pointer" if the last `*` projection +during place computation was performed on a pointer that was not aligned for its +type. (If there is no `*` projection in the place expression, then this is +accessing the field of a local and rustc will guarantee proper alignment. If +there are multiple `*` projection, then each of them incurs a load of the +pointer-to-be-dereferenced itself from memory, and each of these loads is +subject to the alignment constraint. Note that some `*` projections can be +omitted in surface Rust syntax due to automatic dereferencing; we are +considering the fully expanded place expression here.) + +For instance, if `ptr` has type `*const S` where `S` has an alignment of 8, then +`ptr` must be 8-aligned or else `(*ptr).f` is "based on an misaligned pointer". +This is true even if the type of the field `f` is `u8` (i.e., a type with +alignment 1). In other words, the alignment requirement derives from the type of +the pointer that was dereferenced, *not* the type of the field that is being +accessed. + +Note that a place based on a misaligned pointer only leads to Undefined Behavior +when it is loaded from or stored to. `addr_of!`/`addr_of_mut!` on such a place +is allowed. `&`/`&mut` on a place requires the alignment of the field type (or +else the program would be "producing an invalid value"), which generally is a +less restrictive requirement than being based on an aligned pointer. Taking a +reference will lead to a compiler error in cases where the field type might be +more aligned than the type that contains it, i.e., `repr(packed)`. This means +that being based on an aligned pointer is always sufficient to ensure that the +new reference is aligned, but it is not always necessary. + ### Dangling pointers [dangling]: #dangling-pointers