From dfb93b217e08f891ecd6ee9d3afd569e255734ff Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 20 Jul 2019 13:01:13 +0200 Subject: [PATCH 01/21] UB --- src/what-unsafe-does.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/what-unsafe-does.md b/src/what-unsafe-does.md index 2ebd9170..4f081c0b 100644 --- a/src/what-unsafe-does.md +++ b/src/what-unsafe-does.md @@ -16,16 +16,19 @@ to your program. You definitely *should not* invoke Undefined Behavior. Unlike C, Undefined Behavior is pretty limited in scope in Rust. All the core language cares about is preventing the following things: -* Dereferencing null, dangling, or unaligned pointers +* Dereferencing null, dangling, or unaligned references or raw pointers +* Performing out-of-bounds arithmetic for the computation of a struct/tuple + field address * Reading [uninitialized memory][] * Breaking the [pointer aliasing rules][] -* Producing invalid primitive values: - * dangling/null references +* Producing/obtaining invalid primitive values: + * dangling/null/unaligned references * null `fn` pointers * a `bool` that isn't 0 or 1 * an undefined `enum` discriminant * a `char` outside the ranges [0x0, 0xD7FF] and [0xE000, 0x10FFFF] - * A non-utf8 `str` + * a non-utf8 `str` + * a compound type (`enum`/`struct`/array/tuple) with an invalid field * Unwinding into another language * Causing a [data race][race] From 1dcafde23da785b2c8aecca2742074469dfc5ec1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 20 Jul 2019 15:26:23 +0200 Subject: [PATCH 02/21] list more ptr offset computations --- src/what-unsafe-does.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/what-unsafe-does.md b/src/what-unsafe-does.md index 4f081c0b..62da5baf 100644 --- a/src/what-unsafe-does.md +++ b/src/what-unsafe-does.md @@ -17,8 +17,8 @@ Unlike C, Undefined Behavior is pretty limited in scope in Rust. All the core language cares about is preventing the following things: * Dereferencing null, dangling, or unaligned references or raw pointers -* Performing out-of-bounds arithmetic for the computation of a struct/tuple - field address +* Performing out-of-bounds arithmetic for the computation of an + `enum`/`struct`/array/slice/tuple field address * Reading [uninitialized memory][] * Breaking the [pointer aliasing rules][] * Producing/obtaining invalid primitive values: From 280761a65c13355bcbf0fa701cfb505d7c154854 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 20 Jul 2019 16:59:46 +0200 Subject: [PATCH 03/21] NonNull, NonZero* --- src/what-unsafe-does.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/what-unsafe-does.md b/src/what-unsafe-does.md index 62da5baf..b26951c8 100644 --- a/src/what-unsafe-does.md +++ b/src/what-unsafe-does.md @@ -28,6 +28,7 @@ language cares about is preventing the following things: * an undefined `enum` discriminant * a `char` outside the ranges [0x0, 0xD7FF] and [0xE000, 0x10FFFF] * a non-utf8 `str` + * a `NonNull` or `NonZero*` that is 0 * a compound type (`enum`/`struct`/array/tuple) with an invalid field * Unwinding into another language * Causing a [data race][race] From 86d9e2c5766fc3742286ec27a5dcd5019c6abab7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 20 Jul 2019 17:13:51 +0200 Subject: [PATCH 04/21] Define 'producing' --- src/what-unsafe-does.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/what-unsafe-does.md b/src/what-unsafe-does.md index b26951c8..18d99f57 100644 --- a/src/what-unsafe-does.md +++ b/src/what-unsafe-does.md @@ -21,7 +21,7 @@ language cares about is preventing the following things: `enum`/`struct`/array/slice/tuple field address * Reading [uninitialized memory][] * Breaking the [pointer aliasing rules][] -* Producing/obtaining invalid primitive values: +* Producing invalid primitive values: * dangling/null/unaligned references * null `fn` pointers * a `bool` that isn't 0 or 1 @@ -33,6 +33,9 @@ language cares about is preventing the following things: * Unwinding into another language * Causing a [data race][race] +"Producing" a value happens any time a value is assigned, passed to a +function/primitive operation or returned from a function/primitive operation. + That's it. That's all the causes of Undefined Behavior baked into Rust. Of course, unsafe functions and traits are free to declare arbitrary other constraints that a program must maintain to avoid Undefined Behavior. For From 3241c00e1866039cc77b5cb1923194114bd0e998 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 20 Jul 2019 22:49:30 +0200 Subject: [PATCH 05/21] handle recursion in the heading --- src/what-unsafe-does.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/what-unsafe-does.md b/src/what-unsafe-does.md index 18d99f57..01170518 100644 --- a/src/what-unsafe-does.md +++ b/src/what-unsafe-does.md @@ -21,7 +21,8 @@ language cares about is preventing the following things: `enum`/`struct`/array/slice/tuple field address * Reading [uninitialized memory][] * Breaking the [pointer aliasing rules][] -* Producing invalid primitive values: +* Producing invalid primitive values (either alone or as a field of a compound + type such as `enum`/`struct`/array/tuple): * dangling/null/unaligned references * null `fn` pointers * a `bool` that isn't 0 or 1 @@ -29,7 +30,6 @@ language cares about is preventing the following things: * a `char` outside the ranges [0x0, 0xD7FF] and [0xE000, 0x10FFFF] * a non-utf8 `str` * a `NonNull` or `NonZero*` that is 0 - * a compound type (`enum`/`struct`/array/tuple) with an invalid field * Unwinding into another language * Causing a [data race][race] From 909b14c5036fac7d3938ffcb69371f0a381d286d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 20 Jul 2019 22:52:40 +0200 Subject: [PATCH 06/21] subsume the NonNull things as library types --- src/what-unsafe-does.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/what-unsafe-does.md b/src/what-unsafe-does.md index 01170518..f3b10cc3 100644 --- a/src/what-unsafe-does.md +++ b/src/what-unsafe-does.md @@ -29,7 +29,8 @@ language cares about is preventing the following things: * an undefined `enum` discriminant * a `char` outside the ranges [0x0, 0xD7FF] and [0xE000, 0x10FFFF] * a non-utf8 `str` - * a `NonNull` or `NonZero*` that is 0 + * an invalid library type with custom invalid values, such as a `NonNull` or + `NonZero*` that is 0 * Unwinding into another language * Causing a [data race][race] From f59eca24f4398d0cd62316fd323afe0b1857ecfa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 20 Jul 2019 22:57:28 +0200 Subject: [PATCH 07/21] be more precise about dangling --- src/what-unsafe-does.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/what-unsafe-does.md b/src/what-unsafe-does.md index f3b10cc3..e5830444 100644 --- a/src/what-unsafe-does.md +++ b/src/what-unsafe-does.md @@ -16,7 +16,8 @@ to your program. You definitely *should not* invoke Undefined Behavior. Unlike C, Undefined Behavior is pretty limited in scope in Rust. All the core language cares about is preventing the following things: -* Dereferencing null, dangling, or unaligned references or raw pointers +* Loading from or storing to null, dangling, or unaligned references or raw + pointers * Performing out-of-bounds arithmetic for the computation of an `enum`/`struct`/array/slice/tuple field address * Reading [uninitialized memory][] @@ -37,6 +38,10 @@ language cares about is preventing the following things: "Producing" a value happens any time a value is assigned, passed to a function/primitive operation or returned from a function/primitive operation. +A reference/pointer is "dangling" if not all of the bytes it points to are part +of the same allocation. The span of bytes it points to is determined by the +pointer value and the size of the pointee type. + That's it. That's all the causes of Undefined Behavior baked into Rust. Of course, unsafe functions and traits are free to declare arbitrary other constraints that a program must maintain to avoid Undefined Behavior. For From 738a3388dee65904a1415addaf3b3fa770bcd0c0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Jul 2019 11:09:37 +0200 Subject: [PATCH 08/21] stick to broader UB for raw ptr offsets/derefs for now --- src/what-unsafe-does.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/what-unsafe-does.md b/src/what-unsafe-does.md index e5830444..cc02dc65 100644 --- a/src/what-unsafe-does.md +++ b/src/what-unsafe-does.md @@ -16,10 +16,8 @@ to your program. You definitely *should not* invoke Undefined Behavior. Unlike C, Undefined Behavior is pretty limited in scope in Rust. All the core language cares about is preventing the following things: -* Loading from or storing to null, dangling, or unaligned references or raw - pointers -* Performing out-of-bounds arithmetic for the computation of an - `enum`/`struct`/array/slice/tuple field address +* Dereferencing (using the `*` operator on) null, dangling, or unaligned + references or raw pointers * Reading [uninitialized memory][] * Breaking the [pointer aliasing rules][] * Producing invalid primitive values (either alone or as a field of a compound From 0f51082773ac6c51457b020ac2b5dea245c03b5a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Jul 2019 19:48:02 +0200 Subject: [PATCH 09/21] avoid redundant UB --- src/what-unsafe-does.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/what-unsafe-does.md b/src/what-unsafe-does.md index cc02dc65..259f433d 100644 --- a/src/what-unsafe-does.md +++ b/src/what-unsafe-does.md @@ -17,7 +17,7 @@ Unlike C, Undefined Behavior is pretty limited in scope in Rust. All the core language cares about is preventing the following things: * Dereferencing (using the `*` operator on) null, dangling, or unaligned - references or raw pointers + pointers * Reading [uninitialized memory][] * Breaking the [pointer aliasing rules][] * Producing invalid primitive values (either alone or as a field of a compound From efb50867b478ad7d4ae89dfce157244a5980d835 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Jul 2019 12:09:07 +0200 Subject: [PATCH 10/21] add more cases of UB --- src/what-unsafe-does.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/what-unsafe-does.md b/src/what-unsafe-does.md index 259f433d..873b1901 100644 --- a/src/what-unsafe-does.md +++ b/src/what-unsafe-does.md @@ -22,16 +22,21 @@ language cares about is preventing the following things: * Breaking the [pointer aliasing rules][] * Producing invalid primitive values (either alone or as a field of a compound type such as `enum`/`struct`/array/tuple): - * dangling/null/unaligned references + * dangling/null/unaligned references, references that do themselves point to + invalid values, or fat references (to a dynamically sized type) with + invalid metadata * null `fn` pointers * a `bool` that isn't 0 or 1 * an undefined `enum` discriminant * a `char` outside the ranges [0x0, 0xD7FF] and [0xE000, 0x10FFFF] * a non-utf8 `str` + * an uninitialized integer (`i*`/`u*`) or floating point value (`f*`) * an invalid library type with custom invalid values, such as a `NonNull` or `NonZero*` that is 0 * Unwinding into another language * Causing a [data race][race] +* Executing code compiled with platform features that the current platform does + not support (see [`target_feature`]) "Producing" a value happens any time a value is assigned, passed to a function/primitive operation or returned from a function/primitive operation. @@ -69,3 +74,4 @@ these problems are considered impractical to categorically prevent. [pointer aliasing rules]: references.html [uninitialized memory]: uninitialized.html [race]: races.html +[`target_feature`]: ../reference/attributes/codegen.html#the-target_feature-attribute From df5ff6327def099af1317be903f5a5a04533ddb6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Jul 2019 12:10:34 +0200 Subject: [PATCH 11/21] mention ! --- src/what-unsafe-does.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/what-unsafe-does.md b/src/what-unsafe-does.md index 873b1901..538f523f 100644 --- a/src/what-unsafe-does.md +++ b/src/what-unsafe-does.md @@ -22,13 +22,14 @@ language cares about is preventing the following things: * Breaking the [pointer aliasing rules][] * Producing invalid primitive values (either alone or as a field of a compound type such as `enum`/`struct`/array/tuple): - * dangling/null/unaligned references, references that do themselves point to - invalid values, or fat references (to a dynamically sized type) with - invalid metadata - * null `fn` pointers * a `bool` that isn't 0 or 1 * an undefined `enum` discriminant + * null `fn` pointers * a `char` outside the ranges [0x0, 0xD7FF] and [0xE000, 0x10FFFF] + * a `!` (all values are invalid for this type) + * dangling/null/unaligned references, references that do themselves point to + invalid values, or fat references (to a dynamically sized type) with + invalid metadata * a non-utf8 `str` * an uninitialized integer (`i*`/`u*`) or floating point value (`f*`) * an invalid library type with custom invalid values, such as a `NonNull` or From c41d49233c82b1b19874571405287a0e13a0769b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Jul 2019 12:18:51 +0200 Subject: [PATCH 12/21] explain when metadata is invalid --- src/what-unsafe-does.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/what-unsafe-does.md b/src/what-unsafe-does.md index 538f523f..75c8d414 100644 --- a/src/what-unsafe-does.md +++ b/src/what-unsafe-does.md @@ -17,7 +17,7 @@ Unlike C, Undefined Behavior is pretty limited in scope in Rust. All the core language cares about is preventing the following things: * Dereferencing (using the `*` operator on) null, dangling, or unaligned - pointers + pointers, or fat pointers with invalid metadata (see below) * Reading [uninitialized memory][] * Breaking the [pointer aliasing rules][] * Producing invalid primitive values (either alone or as a field of a compound @@ -30,6 +30,10 @@ language cares about is preventing the following things: * dangling/null/unaligned references, references that do themselves point to invalid values, or fat references (to a dynamically sized type) with invalid metadata + * slice metadata is invalid if the slice has a total size larger than + `isize::MAX` bytes in memory + * `dyn Trait` metadata is invalid if it is not a pointer to a vtable for + `Trait` that matches the actual dynamic trait the reference points to * a non-utf8 `str` * an uninitialized integer (`i*`/`u*`) or floating point value (`f*`) * an invalid library type with custom invalid values, such as a `NonNull` or From 1f613d82553e1734e531940200a7480ff78681a4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Jul 2019 12:19:42 +0200 Subject: [PATCH 13/21] Apply suggestions from code review Co-Authored-By: gnzlbg --- src/what-unsafe-does.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/what-unsafe-does.md b/src/what-unsafe-does.md index 75c8d414..e7c1a8c0 100644 --- a/src/what-unsafe-does.md +++ b/src/what-unsafe-does.md @@ -40,7 +40,7 @@ language cares about is preventing the following things: `NonZero*` that is 0 * Unwinding into another language * Causing a [data race][race] -* Executing code compiled with platform features that the current platform does +* Executing code compiled with target features that the current thread of execution does not support (see [`target_feature`]) "Producing" a value happens any time a value is assigned, passed to a From c73730bb8a14a2a3eb22e8dbd392e08faa9e8929 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 26 Jul 2019 09:13:24 +0200 Subject: [PATCH 14/21] raw ptrs must be initialized like integers --- src/what-unsafe-does.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/what-unsafe-does.md b/src/what-unsafe-does.md index e7c1a8c0..5bb7c923 100644 --- a/src/what-unsafe-does.md +++ b/src/what-unsafe-does.md @@ -35,7 +35,8 @@ language cares about is preventing the following things: * `dyn Trait` metadata is invalid if it is not a pointer to a vtable for `Trait` that matches the actual dynamic trait the reference points to * a non-utf8 `str` - * an uninitialized integer (`i*`/`u*`) or floating point value (`f*`) + * an uninitialized integer (`i*`/`u*`), floating point value (`f*`), or raw + pointer * an invalid library type with custom invalid values, such as a `NonNull` or `NonZero*` that is 0 * Unwinding into another language From bd6215eb7fec6ddd4b5330fff7a5be68c5c0d032 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 28 Jul 2019 12:22:13 +0200 Subject: [PATCH 15/21] resolve some nits --- src/what-unsafe-does.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/what-unsafe-does.md b/src/what-unsafe-does.md index 5bb7c923..bf68289b 100644 --- a/src/what-unsafe-does.md +++ b/src/what-unsafe-does.md @@ -17,9 +17,13 @@ Unlike C, Undefined Behavior is pretty limited in scope in Rust. All the core language cares about is preventing the following things: * Dereferencing (using the `*` operator on) null, dangling, or unaligned - pointers, or fat pointers with invalid metadata (see below) + pointers, or wide pointers with invalid metadata (see below) * Reading [uninitialized memory][] * Breaking the [pointer aliasing rules][] +* Unwinding into another language +* Causing a [data race][race] +* Executing code compiled with target features that the current thread of execution does + not support (see [`target_feature`]) * Producing invalid primitive values (either alone or as a field of a compound type such as `enum`/`struct`/array/tuple): * a `bool` that isn't 0 or 1 @@ -28,7 +32,7 @@ language cares about is preventing the following things: * a `char` outside the ranges [0x0, 0xD7FF] and [0xE000, 0x10FFFF] * a `!` (all values are invalid for this type) * dangling/null/unaligned references, references that do themselves point to - invalid values, or fat references (to a dynamically sized type) with + invalid values, or wide references (to a dynamically sized type) with invalid metadata * slice metadata is invalid if the slice has a total size larger than `isize::MAX` bytes in memory @@ -38,11 +42,7 @@ language cares about is preventing the following things: * an uninitialized integer (`i*`/`u*`), floating point value (`f*`), or raw pointer * an invalid library type with custom invalid values, such as a `NonNull` or - `NonZero*` that is 0 -* Unwinding into another language -* Causing a [data race][race] -* Executing code compiled with target features that the current thread of execution does - not support (see [`target_feature`]) + the `NonZero` family of types, that is 0 "Producing" a value happens any time a value is assigned, passed to a function/primitive operation or returned from a function/primitive operation. From 7386b5ceef24b5c9e402aa69a3c329345d999ae7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 28 Jul 2019 18:03:54 +0200 Subject: [PATCH 16/21] refactor null a bit --- src/what-unsafe-does.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/what-unsafe-does.md b/src/what-unsafe-does.md index bf68289b..89108186 100644 --- a/src/what-unsafe-does.md +++ b/src/what-unsafe-does.md @@ -16,8 +16,8 @@ to your program. You definitely *should not* invoke Undefined Behavior. Unlike C, Undefined Behavior is pretty limited in scope in Rust. All the core language cares about is preventing the following things: -* Dereferencing (using the `*` operator on) null, dangling, or unaligned - pointers, or wide pointers with invalid metadata (see below) +* Dereferencing (using the `*` operator on) dangling, or unaligned pointers, or + wide pointers with invalid metadata (see below) * Reading [uninitialized memory][] * Breaking the [pointer aliasing rules][] * Unwinding into another language @@ -31,7 +31,7 @@ language cares about is preventing the following things: * null `fn` pointers * a `char` outside the ranges [0x0, 0xD7FF] and [0xE000, 0x10FFFF] * a `!` (all values are invalid for this type) - * dangling/null/unaligned references, references that do themselves point to + * dangling/unaligned references, references that do themselves point to invalid values, or wide references (to a dynamically sized type) with invalid metadata * slice metadata is invalid if the slice has a total size larger than @@ -48,8 +48,9 @@ language cares about is preventing the following things: function/primitive operation or returned from a function/primitive operation. A reference/pointer is "dangling" if not all of the bytes it points to are part -of the same allocation. The span of bytes it points to is determined by the -pointer value and the size of the pointee type. +of the same allocation. In particular, null pointers are dangling. The span of bytes it +points to is determined by the pointer value and the size of the pointee type. +If the span is empty, "dangling" is the same as "non-null". That's it. That's all the causes of Undefined Behavior baked into Rust. Of course, unsafe functions and traits are free to declare arbitrary other From 864625f8384dd0f20134d9de68ee1f1eb7d2033c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 29 Jul 2019 13:57:53 +0200 Subject: [PATCH 17/21] fold uninit integer rule with reading uninit memory --- src/what-unsafe-does.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/what-unsafe-does.md b/src/what-unsafe-does.md index 89108186..fbb687b3 100644 --- a/src/what-unsafe-does.md +++ b/src/what-unsafe-does.md @@ -18,12 +18,11 @@ language cares about is preventing the following things: * Dereferencing (using the `*` operator on) dangling, or unaligned pointers, or wide pointers with invalid metadata (see below) -* Reading [uninitialized memory][] * Breaking the [pointer aliasing rules][] * Unwinding into another language * Causing a [data race][race] * Executing code compiled with target features that the current thread of execution does - not support (see [`target_feature`]) + not support (see [`target_feature`][]) * Producing invalid primitive values (either alone or as a field of a compound type such as `enum`/`struct`/array/tuple): * a `bool` that isn't 0 or 1 @@ -39,8 +38,8 @@ language cares about is preventing the following things: * `dyn Trait` metadata is invalid if it is not a pointer to a vtable for `Trait` that matches the actual dynamic trait the reference points to * a non-utf8 `str` - * an uninitialized integer (`i*`/`u*`), floating point value (`f*`), or raw - pointer + * an integer (`i*`/`u*`), floating point value (`f*`), or raw pointer read from + [uninitialized memory][] * an invalid library type with custom invalid values, such as a `NonNull` or the `NonZero` family of types, that is 0 From 64bf0a5931b547f8e9028410ce8f73dd2efc2c69 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 29 Jul 2019 13:59:39 +0200 Subject: [PATCH 18/21] fix def.n of dangling --- src/what-unsafe-does.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/what-unsafe-does.md b/src/what-unsafe-does.md index fbb687b3..58a78e22 100644 --- a/src/what-unsafe-does.md +++ b/src/what-unsafe-does.md @@ -46,10 +46,10 @@ language cares about is preventing the following things: "Producing" a value happens any time a value is assigned, passed to a function/primitive operation or returned from a function/primitive operation. -A reference/pointer is "dangling" if not all of the bytes it points to are part -of the same allocation. In particular, null pointers are dangling. The span of bytes it -points to is determined by the pointer value and the size of the pointee type. -If the span is empty, "dangling" is the same as "non-null". +A reference/pointer is "dangling" if it is null or not all of the bytes it +points to are part of the same allocation. The span of bytes it points to is +determined by the pointer value and the size of the pointee type. If the span +is empty, "dangling" is the same as "non-null". That's it. That's all the causes of Undefined Behavior baked into Rust. Of course, unsafe functions and traits are free to declare arbitrary other From 86a89ae669d9272f080eb7c17ddba6196dc055a4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Jul 2019 14:33:37 +0200 Subject: [PATCH 19/21] clarify dangling --- src/what-unsafe-does.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/what-unsafe-does.md b/src/what-unsafe-does.md index 58a78e22..228c970f 100644 --- a/src/what-unsafe-does.md +++ b/src/what-unsafe-does.md @@ -47,9 +47,10 @@ language cares about is preventing the following things: function/primitive operation or returned from a function/primitive operation. A reference/pointer is "dangling" if it is null or not all of the bytes it -points to are part of the same allocation. The span of bytes it points to is -determined by the pointer value and the size of the pointee type. If the span -is empty, "dangling" is the same as "non-null". +points to are part of the same allocation (so in particular they all have to be +part of *some* allocation). The span of bytes it points to is determined by the +pointer value and the size of the pointee type. As a consequence, if the span is +empty, "dangling" is the same as "non-null". That's it. That's all the causes of Undefined Behavior baked into Rust. Of course, unsafe functions and traits are free to declare arbitrary other From c5778a1f49ec791b64ed1d84464125b97e35dfe4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 16 Aug 2019 11:12:22 +0200 Subject: [PATCH 20/21] drop parenthetical --- src/what-unsafe-does.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/what-unsafe-does.md b/src/what-unsafe-does.md index 228c970f..c8e7e430 100644 --- a/src/what-unsafe-does.md +++ b/src/what-unsafe-does.md @@ -21,8 +21,8 @@ language cares about is preventing the following things: * Breaking the [pointer aliasing rules][] * Unwinding into another language * Causing a [data race][race] -* Executing code compiled with target features that the current thread of execution does - not support (see [`target_feature`][]) +* Executing code compiled with [target features][] that the current thread of execution does + not support * Producing invalid primitive values (either alone or as a field of a compound type such as `enum`/`struct`/array/tuple): * a `bool` that isn't 0 or 1 @@ -81,4 +81,4 @@ these problems are considered impractical to categorically prevent. [pointer aliasing rules]: references.html [uninitialized memory]: uninitialized.html [race]: races.html -[`target_feature`]: ../reference/attributes/codegen.html#the-target_feature-attribute +[target features]: ../reference/attributes/codegen.html#the-target_feature-attribute From 7703c188d9e8e08708c87cefd1eff9a8b1ddd59e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 16 Aug 2019 11:17:33 +0200 Subject: [PATCH 21/21] some edits --- src/what-unsafe-does.md | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/what-unsafe-does.md b/src/what-unsafe-does.md index c8e7e430..49cf121c 100644 --- a/src/what-unsafe-does.md +++ b/src/what-unsafe-does.md @@ -23,25 +23,25 @@ language cares about is preventing the following things: * Causing a [data race][race] * Executing code compiled with [target features][] that the current thread of execution does not support -* Producing invalid primitive values (either alone or as a field of a compound - type such as `enum`/`struct`/array/tuple): +* Producing invalid values (either alone or as a field of a compound type such + as `enum`/`struct`/array/tuple): * a `bool` that isn't 0 or 1 - * an undefined `enum` discriminant - * null `fn` pointers + * an `enum` with an invalid discriminant + * a null `fn` pointer * a `char` outside the ranges [0x0, 0xD7FF] and [0xE000, 0x10FFFF] * a `!` (all values are invalid for this type) - * dangling/unaligned references, references that do themselves point to - invalid values, or wide references (to a dynamically sized type) with - invalid metadata + * a reference that is dangling, unaligned, points to an invalid value, or + that has invalid metadata (if wide) * slice metadata is invalid if the slice has a total size larger than `isize::MAX` bytes in memory * `dyn Trait` metadata is invalid if it is not a pointer to a vtable for `Trait` that matches the actual dynamic trait the reference points to - * a non-utf8 `str` + * a `str` that isn't valid UTF-8 * an integer (`i*`/`u*`), floating point value (`f*`), or raw pointer read from [uninitialized memory][] - * an invalid library type with custom invalid values, such as a `NonNull` or - the `NonZero` family of types, that is 0 + * a type with custom invalid values that is one of those values, such as a + `NonNull` that is null. (Requesting custom invalid values is an unstable + feature, but some stable libstd types, like `NonNull`, make use of it.) "Producing" a value happens any time a value is assigned, passed to a function/primitive operation or returned from a function/primitive operation. @@ -50,7 +50,9 @@ A reference/pointer is "dangling" if it is null or not all of the bytes it points to are part of the same allocation (so in particular they all have to be part of *some* allocation). The span of bytes it points to is determined by the pointer value and the size of the pointee type. As a consequence, if the span is -empty, "dangling" is the same as "non-null". +empty, "dangling" is the same as "non-null". Note that slices point to their +entire range, so it's very important that the length metadata is never too +large. If for some reason this is too cumbersome, consider using raw pointers. That's it. That's all the causes of Undefined Behavior baked into Rust. Of course, unsafe functions and traits are free to declare arbitrary other