Skip to content

Latest commit

 

History

History
137 lines (99 loc) · 4.69 KB

0000-unsafe-fields.md

File metadata and controls

137 lines (99 loc) · 4.69 KB

Summary

Fields may be declared unsafe. Unsafe fields may only be mutated (excluding interior mutability) or initialized in an unsafe context. Reading the value of an unsafe field may occur in either safe or unsafe contexts. An unsafe field may be relied upon as a safety invariant in other unsafe code.

Motivation

Emphasis on safety is a key strength of Rust. A major point here is that any code path that can result in undefined behavior must be explicitly marked with the unsafe keyword. However, the current system is insufficient. While Rust provides the unsafe keyword at the function level, there is currently no mechanism to mark fields as unsafe.

For a real-world example, consider the Vec type in the standard library. It has a len field that is used to store the number of elements present. Setting this field is exposed publicly in the Vec::set_len method, which has safety requirements:

  • new_len must be less than or equal to capacity().
  • The elements at old_len..new_len must be initialized.

This field is safe to read, but unsafe to mutate or initialize due to the invariants. These invariants cannot be expressed in the type system, so they must be enforced manually. Failure to do so may result in undefined behavior elsewhere in Vec.

By introducing unsafe fields, Rust can improve the situation where a field that is otherwise safe is used as a safety invariant.

Guide-level explanation

Fields may be declared unsafe. Unsafe fields may only be initialized or accessed mutably in an unsafe context. Reading the value of an unsafe field may occur in either safe or unsafe contexts. An unsafe field may be relied upon as a safety invariant in other unsafe code.

Here is an example to illustrate usage:

struct Foo {
    safe_field: u32,
    /// Safety: Value must be an odd number.
    unsafe unsafe_field: u32,
}

// Unsafe field initialization requires an `unsafe` block.
// Safety: `unsafe_field` is odd.
let mut foo = unsafe {
    Foo {
        safe_field: 0,
        unsafe_field: 1,
    }
};

// Safe field: no unsafe block.
foo.safe_field = 1;

// Unsafe field with mutation: unsafe block is required.
// Safety: The value is odd.
unsafe { foo.unsafe_field = 3; }

// Unsafe field without mutation: no unsafe block.
println!("{}", foo.unsafe_field);

For a full description of where a mutable access is considered to have occurred (and why), see RFC 3323. Keep in mind that due to reborrowing, a mutable access of an unsafe field is not necessarily explicit.

fn change_unsafe_field(foo: &mut Foo) {
    // Safety: An odd number plus two remains an odd number.
    unsafe { foo.unsafe_field += 2; }
}

Reference-level explanation

Syntax

Using the syntax from the reference for structs, the change needed to support unsafe fields is minimal.

StructField :
   OuterAttribute*
   Visibility?
+  unsafe?
   IDENTIFIER : Type

TupleField :
   OuterAttribute*
   Visibility?
+  unsafe?
   Type

Behavior

An unsafe field may only be mutated or initialized in an unsafe context. Failure to do so is a compile error.

"Mutable use" in the compiler

The concept of a "mutable use" already exists within the compiler. This catches all situations that are relevant here, including ptr::addr_of_mut!, &mut, and direct assignment to a field, while excluding interior mutability. As such, formal semantics of what constitutes a "mutable use" are not stated here.

Drawbacks

  • Additional syntax for macros to handle
  • More syntax to learn

Prior art

Some items in the Rust standard library have #[rustc_layout_scalar_valid_range_start], #[rustc_layout_scalar_valid_range_end], or both. These items have identical behavior to that of unsafe fields described here. It is likely (though not required by this RFC) that these items will be required to use unsafe fields, which would reduce special-casing of the standard library.

Unresolved questions

  • If the syntax for restrictions does not change, what is the ordering of keywords on a field that is both unsafe and mut-restricted?
  • Are there any interactions or edge cases with other language features that need to be considered?

Future possibilities

??