Skip to content

The lack of safety requirements for some unsafe api documents in std #134242

Closed
@VaynNecol

Description

@VaynNecol

Location

core::alloc

core/alloc/trait.GlobalAlloc#method.alloc_zeroed

retval.Untyped = ["The allocated block of memory is guaranteed to be initialized but may be untyped."]

core/alloc/trait.GlobalAlloc#method.realloc

layout.Layout = ["`layout` has non-zero size."]
retval.Untyped = ["The allocated block of memory may or may not be initialized."]

core/alloc/trait.Allocator#method.grow

retval.Untyped = ["The allocated block of memory may or may not be initialized."]

core/alloc/trait.Allocator#method.grow_zeroed

ptr.Freed = ["If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been transferred to this allocator. "]
retval.Untyped = ["The allocated block of memory is guaranteed to be initialized but may be untyped."]

core::char

core/char/fn.from_u32_unchecked

i.Initialized = ["Not all valid `u32`s are valid `char`s, it may construct invalid `char` values."]

core::convert

core/convert/trait.FloatToInt

self.Bounded = [
    "The value must not be `NaN`.",
    "The value must not be infinite.",
    "The value must be representable in the return type `Int`, after truncating off its fractional part."
]

core::mem

core/mem/fn.transmute_copy

src.Initialized = [
    "Both the argument and the result must be valid at their given type.",
    "To transmute the inner type of the contents of a container, you must make sure to not violate any of the container's invariants."
]

src.Layout = [
    "Both types must have the same size.",
    "Note that source and destination are passed by-value, which means if `Src` or `Dst` contain padding, that padding is not guaranteed to be preserved by transmute.",
    "When transmuting values that point elsewhere (such as pointers, references, boxes…), the caller has to ensure proper alignment of the pointed-to values."
]

retval.Untyped = ["It is therefore your responsibility to guarantee that every value passed to transmute is valid at both types `Src` and `Dst`. Failing to uphold this condition may lead to unexpected and unstable compilation results."]

core::primitive

core/primitive.pointer#method.as_ref

self.Dereferencable = ["The memory range of the given size starting at the pointer must all be within the bounds of a single allocated object."]
self.Layout = ["The pointer must be properly aligned."]
retval.Aliased = [
    "You must enforce Rust's aliasing rules. In particular, while this reference exists, the memory the pointer points to must not get mutated.",
    "The returned lifetime `'a` is arbitrarily chosen and does not necessarily reflect the actual lifetime of the data."
]

core/primitive.pointer#method.as_uninit_ref

self.Dereferencable = ["The memory range of the given size starting at the pointer must all be within the bounds of a single allocated object."]
self.Layout = ["The pointer must be properly aligned."]
retval.Aliased = [
    "You must enforce Rust's aliasing rules. In particular, while this reference exists, the memory the pointer points to must not get mutated.",
    "The returned lifetime `'a` is arbitrarily chosen and does not necessarily reflect the actual lifetime of the data."
]

core/primitive.pointer#method.as_ref-1

self.Dereferencable = ["The memory range of the given size starting at the pointer must all be within the bounds of a single allocated object."]
self.Layout = ["The pointer must be properly aligned."]
retval.Aliased = [
    "You must enforce Rust's aliasing rules. In particular, while this reference exists, the memory the pointer points to must not get mutated.",
    "The returned lifetime `'a` is arbitrarily chosen and does not necessarily reflect the actual lifetime of the data."
]

core/primitive.pointer#method.as_uninit_ref-1

self.Dereferencable = ["The memory range of the given size starting at the pointer must all be within the bounds of a single allocated object."]
self.Layout = ["The pointer must be properly aligned."]
retval.Aliased = [
    "You must enforce Rust's aliasing rules. In particular, while this reference exists, the memory the pointer points to must not get mutated.",
    "The returned lifetime `'a` is arbitrarily chosen and does not necessarily reflect the actual lifetime of the data."
]

core/primitive.pointer#method.as_mut

self.Dereferencable = ["The memory range of the given size starting at the pointer must all be within the bounds of a single allocated object."]
self.Layout = ["The pointer must be properly aligned."]
retval.Aliased = [
    "You must enforce Rust's aliasing rules. In particular, while this reference exists, the memory the pointer points to must not get accessed (read or written) through any other pointer.",
    "The returned lifetime `'a` is arbitrarily chosen and does not necessarily reflect the actual lifetime of the data."
]

core/primitive.slice#method.align_to 

self.Initialized = [
    "Both the `T` and the `U` must be valid at their given type.",
    "To transmute the inner type of the contents of a container, you must make sure to not violate any of the container's invariants."
]
self.Layout = [
    "Both types must have the same size.",
    "Note that source and destination are passed by-value, which means if `T` or `U` contain padding, that padding is not guaranteed to be preserved by transmute.",
    "This method has no purpose when either input element `T` or output element `U` are zero-sized and will return the original slice without splitting anything.",
    "When transmuting values that point elsewhere (such as pointers, references, boxes…), the caller has to ensure proper alignment of the pointed-to values."
]
retval.Initialized = ["Both the argument and the result must be valid at their given type."]
retval.Aliased = [
    "It can turn a `*mut T` into an `&mut T`.",
    "It can extend a lifetime, or shorten an invariant lifetime."
]
retval.Untyped = ["It is therefore your responsibility to guarantee that every value passed to transmute is valid at both types `T` and `U`. Failing to uphold this condition may lead to unexpected and unstable compilation results."]

core/primitive.slice#method.align_to_mut 

self.Initialized = [
    "Both the `T` and the `U` must be valid at their given type.",
    "To transmute the inner type of the contents of a container, you must make sure to not violate any of the container's invariants."
]
self.Layout = [
    "Both types must have the same size.",
    "Note that source and destination are passed by-value, which means if `T` or `U` contain padding, that padding is not guaranteed to be preserved by transmute.",
    "This method has no purpose when either input element `T` or output element `U` are zero-sized and will return the original slice without splitting anything.",
    "When transmuting values that point elsewhere (such as pointers, references, boxes…), the caller has to ensure proper alignment of the pointed-to values."
]
retval.Initialized = ["Both the argument and the result must be valid at their given type."]
retval.Aliased = [
    "It can turn a `*mut T` into an `&mut T`.",
    "It can extend a lifetime, or shorten an invariant lifetime."
]
retval.Untyped = ["It is therefore your responsibility to guarantee that every value passed to transmute is valid at both types `T` and `U`. Failing to uphold this condition may lead to unexpected and unstable compilation results."]

core::ptr

core/ptr/fn.swap_nonoverlapping 

x.Untyped = ["The operation is untyped in the sense that data may be uninitialized or otherwise violate the requirements of `T`."]
y.Untyped = ["The operation is untyped in the sense that data may be uninitialized or otherwise violate the requirements of `T`."]

core/ptr/fn.copy 

dst.Leaked = [""]

core/ptr/struct.NonNull#method.as_uninit_ref

self.Allocated = ["Even for operations of size zero, the pointer must not be pointing to deallocated memory."]
self.Dereferencable = ["The memory range of the given size starting at the pointer must all be within the bounds of a single allocated object."]
self.Layout = ["The pointer must be properly aligned."]
retval.Aliased = [
    "You must enforce Rust's aliasing rules. In particular, while this reference exists, the memory the pointer points to must not get mutated.",
    "The returned lifetime `'a` is arbitrarily chosen and does not necessarily reflect the actual lifetime of the data."
]

core/ptr/struct.NonNull#method.as_mut

self.Allocated = ["Even for operations of size zero, the pointer must not be pointing to deallocated memory."]
self.Initialized = ["The pointer must point to an initialized instance of `T`."]
self.Dereferencable = ["The memory range of the given size starting at the pointer must all be within the bounds of a single allocated object."]
self.Layout = ["The pointer must be properly aligned."]
retval.Aliased = [
    "You must enforce Rust's aliasing rules. In particular, while this reference exists, the memory the pointer points to must not get accessed (read or written) through any other pointer.",
    "The returned lifetime `'a` is arbitrarily chosen and does not necessarily reflect the actual lifetime of the data."
]

core/ptr/struct.NonNull#method.offset

self.Allocated = ["Even for operations of size zero, the pointer must not be pointing to deallocated memory."]

core/ptr/struct.NonNull#method.add

self.Allocated = ["Even for operations of size zero, the pointer must not be pointing to deallocated memory."]

core/ptr/struct.NonNull#method.sub

self.Allocated = ["Even for operations of size zero, the pointer must not be pointing to deallocated memory."]

core/ptr/struct.NonNull#method.offset_from

self.Allocated = ["Even for operations of size zero, the pointer must not be pointing to deallocated memory."]

core/ptr/struct.NonNull#method.sub_ptr

self.Allocated = ["Even for operations of size zero, the pointer must not be pointing to deallocated memory."]

core/ptr/struct.NonNull#method.as_uninit_slice

self.Allocated = ["Even for operations of size zero, the pointer must not be pointing to deallocated memory."]

core/ptr/struct.NonNull#method.as_uninit_slice_mut

self.Allocated = ["Even for operations of size zero, the pointer must not be pointing to deallocated memory."]

core::slice

core/slice/trait.SliceIndex#tymethod.get_unchecked

slice.Allocated = ["A dangling slice pointer is undefined behavior even if the resulting reference is not used."]
slice.Dereferencable = ["When `slice` is not dereferenceable is undefined behavior even if the resulting pointer is not used."]

core/slice/trait.SliceIndex#tymethod.get_unchecked_mut

slice.Allocated = ["A dangling slice pointer is undefined behavior even if the resulting reference is not used."]
slice.Dereferencable = ["When `slice` is not dereferenceable is undefined behavior even if the resulting pointer is not used."]

core::any

[] https://doc.rust-lang.org/core/any/trait.Any.html#method.downcast_ref_unchecked-2

self.Initialized = ["The contained value must be of type `T`."]

[] https://doc.rust-lang.org/core/any/trait.Any.html#method.downcast_mut_unchecked-2

self.Initialized = ["The contained value must be of type `T`."]

core::sync

core/sync/atomic/struct.AtomicBool#method.from_ptr

retval.Aliased = [
    "You must enforce Rust's aliasing rules. In particular, while this reference exists, the memory the pointer points to must not get mutated.",
    "The returned lifetime `'a` is arbitrarily chosen and does not necessarily reflect the actual lifetime of the data."
]

core/sync/atomic/struct.AtomicU8#method.from_ptr

retval.Aliased = [
    "You must enforce Rust's aliasing rules. In particular, while this reference exists, the memory the pointer points to must not get mutated.",
    "The returned lifetime `'a` is arbitrarily chosen and does not necessarily reflect the actual lifetime of the data."
]

core/sync/atomic/struct.AtomicU16#method.from_ptr

retval.Aliased = [
    "You must enforce Rust's aliasing rules. In particular, while this reference exists, the memory the pointer points to must not get mutated.",
    "The returned lifetime `'a` is arbitrarily chosen and does not necessarily reflect the actual lifetime of the data."
]

core/sync/atomic/struct.AtomicU32#method.from_ptr

retval.Aliased = [
    "You must enforce Rust's aliasing rules. In particular, while this reference exists, the memory the pointer points to must not get mutated.",
    "The returned lifetime `'a` is arbitrarily chosen and does not necessarily reflect the actual lifetime of the data."
]

core/sync/atomic/struct.AtomicU64#method.from_ptr

retval.Aliased = [
    "You must enforce Rust's aliasing rules. In particular, while this reference exists, the memory the pointer points to must not get mutated.",
    "The returned lifetime `'a` is arbitrarily chosen and does not necessarily reflect the actual lifetime of the data."
]

core/sync/atomic/struct.AtomicUsize#method.from_ptr

retval.Aliased = [
    "You must enforce Rust's aliasing rules. In particular, while this reference exists, the memory the pointer points to must not get mutated.",
    "The returned lifetime `'a` is arbitrarily chosen and does not necessarily reflect the actual lifetime of the data."
]

core/sync/atomic/struct.AtomicI8#method.from_ptr

retval.Aliased = [
    "You must enforce Rust's aliasing rules. In particular, while this reference exists, the memory the pointer points to must not get mutated.",
    "The returned lifetime `'a` is arbitrarily chosen and does not necessarily reflect the actual lifetime of the data."
]

core/sync/atomic/struct.AtomicI16#method.from_ptr

retval.Aliased = [
    "You must enforce Rust's aliasing rules. In particular, while this reference exists, the memory the pointer points to must not get mutated.",
    "The returned lifetime `'a` is arbitrarily chosen and does not necessarily reflect the actual lifetime of the data."
]

core/sync/atomic/struct.AtomicI32#method.from_ptr

retval.Aliased = [
    "You must enforce Rust's aliasing rules. In particular, while this reference exists, the memory the pointer points to must not get mutated.",
    "The returned lifetime `'a` is arbitrarily chosen and does not necessarily reflect the actual lifetime of the data."
]

core/sync/atomic/struct.AtomicI64#method.from_ptr

retval.Aliased = [
    "You must enforce Rust's aliasing rules. In particular, while this reference exists, the memory the pointer points to must not get mutated.",
    "The returned lifetime `'a` is arbitrarily chosen and does not necessarily reflect the actual lifetime of the data."
]

core/sync/atomic/struct.AtomicIsize#method.from_ptr

retval.Aliased = [
    "You must enforce Rust's aliasing rules. In particular, while this reference exists, the memory the pointer points to must not get mutated.",
    "The returned lifetime `'a` is arbitrarily chosen and does not necessarily reflect the actual lifetime of the data."
]

core/sync/atomic/struct.AtomicPtr#method.from_ptr

retval.Aliased = [
    "You must enforce Rust's aliasing rules. In particular, while this reference exists, the memory the pointer points to must not get mutated.",
    "The returned lifetime `'a` is arbitrarily chosen and does not necessarily reflect the actual lifetime of the data."
]

alloc::ffi

alloc/ffi/struct.CString#method.from_raw 

ptr.Allocated = [
    "The raw pointer must point to a block of memory allocated by the global allocator.",
    "Other usage (trying to take ownership of a string that was allocated by foreign code) is likely to lead to undefined behavior or allocator corruption."
]
retval.DualOwned = ["Retakes ownership of a `CString` that was transferred to C via `CString::into_raw`."]

alloc::boxed

alloc/boxed/struct.Box#method.from_raw

self.Allocated = [
    "For non-zero-sized values, a `Box` will use the Global allocator for its allocation.",
    "For zero-sized values, the `Box` pointer still has to be valid for reads and writes (always be non-null pointers)."
]

alloc/boxed/struct.Box#method.from_raw_in

self.Allocated = [
    "For non-zero-sized values, a `Box` will use the in the given allocator for its allocation.",
    "For zero-sized values, the `Box` pointer still has to be valid for reads and writes (always be non-null pointers)."
]

alloc::sync

alloc/sync/struct.Arc#method.increment_strong_count

ptr.Allocated = ["`ptr` must point to a block of memory allocated by the global allocator."]

alloc/sync/struct.Arc#method.decrement_strong_count

ptr.Allocated = ["`ptr` must point to a block of memory allocated by the global allocator."]

alloc/sync/struct.Weak#method.from_raw

ptr.Allocated = ["`ptr` must point to a block of memory allocated by the global allocator."]

core::intrinsics

core/intrinsics/fn.unaligned_volatile_load

src.Allocated = [
    "A null pointer is never valid, not even for accesses of size zero.",
    "Even for operations of size zero, the pointer must not be pointing to deallocated memory."
]
src.Initialized = ["`src` must point to a properly initialized value of type `T`."]
src.Dereferencable = ["The memory range of the given size starting at the pointer must all be within the bounds of a single allocated object."]
retval.DualOwned = [
    "If `T` is not `Copy`, using both the returned value and the value at `src` can violate memory safety. Note that assigning to `src` counts as a use because it will attempt to drop the value at `src`.",
    "However, storing non-`Copy` types in volatile memory is almost certainly incorrect."
]

core/intrinsics/fn.unaligned_volatile_store

dst.Allocated = [
    "A null pointer is never valid, not even for accesses of size zero.",
    "Even for operations of size zero, the pointer must not be pointing to deallocated memory."
]
dst.Dereferencable = ["The memory range of the given size starting at the pointer must all be within the bounds of a single allocated object."]
dst.Leaked = ["This is safe, but it could leak allocations or resources, so care should be taken not to overwrite an object that should be dropped."]

core/intrinsics/fn.volatile_copy_memory

src.Allocated = [
    "A null pointer is never valid, not even for accesses of size zero.",
    "Even for operations of size zero, the pointer must not be pointing to deallocated memory."
]
src.Dereferencable = ["The memory range of the given size (`count * size_of::<T>()` bytes) starting at the pointer must all be within the bounds of a single allocated object."]

src.Layout = ["`src` must be properly aligned."]
dst.Allocated = [
    "A null pointer is never valid, not even for accesses of size zero.",
    "Even for operations of size zero, the pointer must not be pointing to deallocated memory."
]
dst.Dereferencable = ["The memory range of the given size (`count * size_of::<T>()` bytes) starting at the pointer must all be within the bounds of a single allocated object."]
dst.Layout = ["`dst` must be properly aligned."]
dst.DualOwned = ["If `T` is not `Copy`, using both the values in the region beginning at `self` and the region beginning at `*dst` can violate memory safety. Note that assigning to `*dst` counts as a use because it will attempt to drop the value at `*dst`."]
dst.Untyped = ["The copy is untyped in the sense that data may be uninitialized or otherwise violate the requirements of `T`."]
dst.Leaked = [""]

core/intrinsics/fn.volatile_copy_nonoverlapping_memory

src.Allocated = [
    "A null pointer is never valid, not even for accesses of size zero.",
    "Even for operations of size zero, the pointer must not be pointing to deallocated memory."
]
src.Dereferencable = [
    "The memory range of the given size (`count * size_of::<T>()` bytes) starting at the pointer must all be within the bounds of a single allocated object.",
    "The region of memory beginning at `src` with a size of `count * size_of::<T>()` bytes must not overlap with the region of memory beginning at `dst` with the same size."
]
src.Layout = ["`src` must be properly aligned."]
dst.Allocated = [
    "A null pointer is never valid, not even for accesses of size zero.",
    "Even for operations of size zero, the pointer must not be pointing to deallocated memory."
]
dst.Dereferencable = [
    "The memory range of the given size (`count * size_of::<T>()` bytes) starting at the pointer must all be within the bounds of a single allocated object.",
    "The region of memory beginning at `src` with a size of `count * size_of::<T>()` bytes must not overlap with the region of memory beginning at `dst` with the same size."
]
dst.Layout = ["`dst` must be properly aligned."]
dst.DualOwned = ["If `T` is not `Copy`, using both the values in the region beginning at `self` and the region beginning at `*dst` can violate memory safety. Note that assigning to `*dst` counts as a use because it will attempt to drop the value at `*dst`."]
dst.Untyped = ["The copy is untyped in the sense that data may be uninitialized or otherwise violate the requirements of `T`."]
dst.Leaked = [""]

core/intrinsics/fn.volatile_set_memory

dst.Allocated = [
    "A null pointer is never valid, not even for accesses of size zero.",
    "Even for operations of size zero, the pointer must not be pointing to deallocated memory."
]
dst.Dereferencable = ["The memory range of the given size (`count * size_of::<T>()` bytes) starting at the pointer must all be within the bounds of a single allocated object."]
dst.Layout = ["`dst` must be properly aligned ('min_align_of::<T>()')."]
dst.Untyped = ["Additionally, note that changing `dst` in this way can easily lead to undefined behavior (UB) later if the written bytes are not a valid representation of some `T`."]
dst.Leaked = [""]

core/intrinsics/fn.copy

dst.Leaked = [""]

core/intrinsics/fn.copy_nonoverlapping

dst.Leaked = [""]

core/intrinsics/fn.drop_in_place

to_drop.Allocated = [
    "`to_drop` must be nonnull, even if T has size 0.",
    "Even for operations of size zero, the pointer must not be pointing to deallocated memory."
]
to_drop.Initialized = ["The value `to_drop` points to must be valid for dropping, which may mean it must uphold additional invariants. These invariants depend on the type of the value being dropped."]
to_drop.Dereferencable = ["The memory range of the given size starting at the pointer must all be within the bounds of a single allocated object."]
to_drop.Layout = [
    "`to_drop` must be properly aligned, even if `T` has size 0.",
    "Unaligned values cannot be dropped in place, they must be copied to an aligned location first using `ptr::read_unaligned`."
]
to_drop.Freed = ["Executes the destructor (if any) of the pointed-to value."]

core/intrinsics/fn.write_bytes

dst.Leaked = [""]

Summary

We found that the documentation regarding the safety requirements of unsafe APIs in the Rust std has disadvantages.

In short:

  1. Consistency: Inconsistent text for the same safety requirements.
  2. Completeness: Some APIs have missing safety requirements.
  3. Intuitiveness: Safety requirements for APIs require linking to additional pages for further details.

We published our research on these issues at ICSE 2024 and uploaded an extended version that optimizes the classification of safety requirements on arXiv. https://arxiv.org/abs/2412.06251

Based on the latest version, we reorganize the documents for the standard library's Unsafe APIs, focusing solely on safety requirements, without addressing other functionalities. The document links the original API documents, safety requirements, and corresponding parameters/return value altogether.

For easier viewing, I encoded it into a TOML file, and the link is: Safety Documents

During the process of reorganizing the documents, I found that some APIs had missing safety descriptions. In this issue, we’ve organized a checklist in the format of "namespace—API" for the Rust team. The refined documents we modified is just a preliminary attempt, and we hope that Rust can provide more user-friendly and structured documents for unsafe APIs in the future.

The above outlines the shortcomings I have identified. If there are any errors or if further discussion is needed, I would also greatly appreciate feedback from the Rust team 😊.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-docsArea: Documentation for any part of the project, including the compiler, standard library, and toolsC-discussionCategory: Discussion or questions that doesn't represent real issues.T-libsRelevant to the library team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions