diff --git a/src/what-unsafe-does.md b/src/what-unsafe-does.md index 2ebd9170..49cf121c 100644 --- a/src/what-unsafe-does.md +++ b/src/what-unsafe-does.md @@ -16,18 +16,43 @@ 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 -* Reading [uninitialized memory][] +* Dereferencing (using the `*` operator on) dangling, or unaligned pointers, or + wide pointers with invalid metadata (see below) * Breaking the [pointer aliasing rules][] -* Producing invalid primitive values: - * dangling/null 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` * Unwinding into another language * Causing a [data race][race] +* Executing code compiled with [target features][] that the current thread of execution does + not support +* 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 `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) + * 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 `str` that isn't valid UTF-8 + * an integer (`i*`/`u*`), floating point value (`f*`), or raw pointer read from + [uninitialized memory][] + * 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. + +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". 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 @@ -58,3 +83,4 @@ these problems are considered impractical to categorically prevent. [pointer aliasing rules]: references.html [uninitialized memory]: uninitialized.html [race]: races.html +[target features]: ../reference/attributes/codegen.html#the-target_feature-attribute