Movatterモバイル変換


[0]ホーム

URL:


Keyboard shortcuts

Press or to navigate between chapters

PressS or/ to search in the book

Press? to show this help

PressEsc to hide this help

The Rust Reference

    Behavior considered undefined

    Rust code is incorrect if it exhibits any of the behaviors in the followinglist. This includes code withinunsafe blocks andunsafe functions.unsafe only means that avoiding undefined behavior is on the programmer; itdoes not change anything about the fact that Rust programs must never causeundefined behavior.

    It is the programmer’s responsibility when writingunsafe code to ensure thatany safe code interacting with theunsafe code cannot trigger thesebehaviors.unsafe code that satisfies this property for any safe client iscalledsound; ifunsafe code can be misused by safe code to exhibitundefined behavior, it isunsound.

    Warning

    The following list is not exhaustive; it may grow or shrink. There is no formal model of Rust’s semantics for what is and is not allowed in unsafe code, so there may be more behavior considered unsafe. We also reserve the right to make some of the behavior in that list defined in the future. In other words, this list does not say that anything willdefinitely always be undefined in all future Rust version (but we might make such commitments for some list items in the future).

    Please read theRustonomicon before writing unsafe code.

    • Data races.
    • Breaking the pointer aliasing rules. The exact aliasing rules are not determined yet, but here is an outline of the general principles:&T must point to memory that is not mutated while they are live (except for data inside anUnsafeCell<U>),and&mut T must point to memory that is not read or written by any pointer not derived from the reference and that no other reference points to while they are live.Box<T> is treated similar to&'static mut T for the purpose of these rules.The exact liveness duration is not specified, but some bounds exist:

      • For references, the liveness duration is upper-bounded by the syntacticlifetime assigned by the borrow checker; it cannot be live anylonger than that lifetime.
      • Each time a reference or box is dereferenced or reborrowed, it is considered live.
      • Each time a reference or box is passed to or returned from a function, it is considered live.
      • When a reference (but not aBox!) is passed to a function, it is live at least as long as that function call, again except if the&T contains anUnsafeCell<U>.

      All this also applies when values of these types are passed in a (nested) field of a compound type, but not behind pointer indirections.

    • Mutating immutable bytes.All bytes reachable through aconst-promoted expression are immutable, as well as bytes reachable through borrows instatic andconst initializers that have beenlifetime-extended to'static.The bytes owned by an immutable binding or immutablestatic are immutable, unless those bytes are part of anUnsafeCell<U>.

      Moreover, the bytespointed to by a shared reference, including transitively through other references (both shared and mutable) andBoxes, are immutable; transitivity includes those references stored in fields of compound types.

      A mutation is any write of more than 0 bytes which overlaps with any of the relevant bytes (even if that write does not change the memory contents).

    • Invoking undefined behavior via compiler intrinsics.
    • Executing code compiled with platform features that the current platformdoes not support (seetarget_feature),except if the platform explicitly documents this to be safe.
    • Calling a function with the wrongcall ABI, or unwinding past a stack frame that does not allow unwinding (e.g. by calling a"C-unwind" function imported or transmuted as a"C" function or function pointer).
    • Producing aninvalid value. “Producing” avalue happens any time a value is assigned to or read from a place, passed toa function/primitive operation or returned from a function/primitiveoperation.
    • Incorrect use of inline assembly. For more details, refer to therules tofollow when writing code that uses inline assembly.
    • Inconst context: transmuting or otherwisereinterpreting a pointer (reference, raw pointer, or function pointer) intosome allocation as a non-pointer type (such as integers).‘Reinterpreting’ refers to loading the pointer value at integer type without acast, e.g. by doing raw pointer casts or using a union.
    • Violating assumptions of the Rust runtime. Most assumptions of the Rust runtime are currently not explicitly documented.
      • For assumptions specifically related to unwinding, see thepanic documentation.
      • The runtime assumes that a Rust stack frame is not deallocated without executing destructors for local variables owned by the stack frame. This assumption can be violated by C functions likelongjmp.

    Note

    Undefined behavior affects the entire program. For example, calling a function in C that exhibits undefined behavior of C means your entire program contains undefined behaviour that can also affect the Rust code. And vice versa, undefined behavior in Rust can cause adverse affects on code executed by any FFI calls to other languages.

    Pointed-to bytes

    The span of bytes a pointer or reference “points to” is determined by the pointer value and the size of the pointee type (usingsize_of_val).

    Places based on misaligned pointers

    A place is said to be “based on a misaligned pointer” if the last* projectionduring place computation was performed on a pointer that was not aligned for itstype. (If there is no* projection in the place expression, then this isaccessing the field of a local orstatic and rustc will guarantee proper alignment. Ifthere are multiple* projection, then each of them incurs a load of thepointer-to-be-dereferenced itself from memory, and each of these loads issubject to the alignment constraint. Note that some* projections can beomitted in surface Rust syntax due to automatic dereferencing; we areconsidering the fully expanded place expression here.)

    For instance, ifptr has type*const S whereS has an alignment of 8, thenptr must be 8-aligned or else(*ptr).f is “based on an misaligned pointer”.This is true even if the type of the fieldf isu8 (i.e., a type withalignment 1). In other words, the alignment requirement derives from the type ofthe pointer that was dereferenced,not the type of the field that is beingaccessed.

    Note that a place based on a misaligned pointer only leads to Undefined Behaviorwhen it is loaded from or stored to.

    &raw const/&raw mut on such a place is allowed.

    &/&mut on a place requires the alignment of the field type (orelse the program would be “producing an invalid value”), which generally is aless 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 bemore aligned than the type that contains it, i.e.,repr(packed). This meansthat being based on an aligned pointer is always sufficient to ensure that thenew reference is aligned, but it is not always necessary.

    Dangling pointers

    A reference/pointer is “dangling” if not all of the bytes itpoints to are part of the same live allocation (so in particular they all have to bepart ofsome allocation).

    If the size is 0, then the pointer is trivially never “dangling”(even if it is a null pointer).

    Note that dynamically sized types (such as slices and strings) point to theirentire range, so it is important that the length metadata is never too large.

    In particular, the dynamic size of a Rust value (as determined bysize_of_val)must never exceedisize::MAX, since it is impossible for a single allocationto be larger thanisize::MAX.

    Invalid values

    The Rust compiler assumes that all values produced during program execution are“valid”, and producing an invalid value is hence immediate UB.

    Whether a value is valid depends on the type:

    • Abool value must befalse (0) ortrue (1).
    • Afn pointer value must be non-null.
    • Achar value must not be a surrogate (i.e., must not be in the range0xD800..=0xDFFF) and must be equal to or less thanchar::MAX.
    • A! value must never exist.
    • An integer (i*/u*), floating point value (f*), or raw pointer must beinitialized, i.e., must not be obtained from uninitialized memory.
    • Astr value is treated like[u8], i.e. it must be initialized.
    • Anenum must have a valid discriminant, and all fields of the variant indicated by that discriminant must be valid at their respective type.
    • Astruct, tuple, and array requires all fields/elements to be valid at their respective type.
    • For aunion, the exact validity requirements are not decided yet.Obviously, all values that can be created entirely in safe code are valid.If the union has a zero-sized field, then every possible value is valid.Further details arestill being debated.
    • A reference orBox<T> must be aligned and non-null, it cannot bedangling, and it must point to a valid value(in case of dynamically sized types, using the actual dynamic type of thepointee as determined by the metadata).Note that the last point (about pointing to a valid value) remains a subject of some debate.
    • The metadata of a wide reference,Box<T>, or raw pointer must matchthe type of the unsized tail:
      • dyn Trait metadata must be a pointer to a compiler-generated vtable forTrait.(For raw pointers, this requirement remains a subject of some debate.)
      • Slice ([T]) metadata must be a validusize.Furthermore, for wide references andBox<T>, slice metadata is invalidif it makes the total size of the pointed-to value bigger thanisize::MAX.
    • If a type has a custom range of a valid values, then a valid value must be in that range.In the standard library, this affectsNonNull<T> andNonZero<T>.

      Note

      rustc achieves this with the unstablerustc_layout_scalar_valid_range_* attributes.

    Note: Uninitialized memory is also implicitly invalid for any type that hasa restricted set of valid values. In other words, the only cases in whichreading uninitialized memory is permitted are insideunions and in “padding”(the gaps between the fields of a type).


    [8]ページ先頭

    ©2009-2025 Movatter.jp