unsafe-fields

Crates.iounsafe-fields
lib.rsunsafe-fields
version0.2.1
sourcesrc
created_at2024-10-21 18:06:36.034125
updated_at2024-10-22 18:08:28.897277
descriptionMake it unsafe to access or modify fields with safety invariants
homepage
repositoryhttps://github.com/google/zerocopy
max_upload_size
id1417773
size34,459
Joshua Liebow-Feeser (joshlf)

documentation

README

unsafe-fields

Support for unsafe fields.

This crate provides the unsafe_fields! macro, which can be used to mark fields as unsafe. Unsafe fields automatically have their types wrapped using the Unsafe wrapper type. An Unsafe is intended to be used to for struct, enum, or union fields which carry safety invariants. All accessors are unsafe, which requires any use of an Unsafe field to be inside an unsafe block. One exception is Unsafe::as_ref, which is available when the zerocopy_0_8 feature is enabled. See its docs for more information.

An unsafe field has the type Unsafe<O, F, const NAME_HASH: u128>. O is the enclosing type (struct, enum, or union), F is the type of the field, and NAME_HASH is the hash of the field's name. O prevents swapping unsafe fields of the same F type between different enclosing types, and NAME_HASH prevents swapping different fields of the same F type within the same enclosing type. Note that swapping the same field between instances of the same type cannot be prevented.

Examples

use unsafe_fields::{unsafe_fields, Unsafe};

unsafe_fields! {
    /// A `usize` which is guaranteed to be even.
    pub struct EvenUsize {
        // INVARIANT: `n` is even.
        #[unsafe]
        n: usize,
    }
}

impl EvenUsize {
    /// Constructs a new `EvenUsize`.
    ///
    /// Returns `None` if `n` is odd.
    pub fn new(n: usize) -> Option<EvenUsize> {
        if n % 2 != 0 {
            return None;
        }
        // SAFETY: We just confirmed that `n` is even.
        let n = unsafe { Unsafe::new(n) };
        Some(EvenUsize { n })
    }
}

Attempting to swap unsafe fields of the same type is prevented:

use unsafe_fields::{unsafe_fields, Unsafe};

unsafe_fields! {
    /// A range.
    pub struct Range {
        // INVARIANT: `lo <= hi`.
        #[unsafe]
        lo: usize,
        #[unsafe]
        hi: usize,
    }
}

impl Range {
    pub fn swap(&mut self) {
        // ERROR: Mismatched types
        core::mem::swap(&mut self.lo, &mut self.hi);
    }
}

Limitations

Note that we cannot prevent Unsafes from being swapped between the same field in instances of the same type:

use unsafe_fields::{unsafe_fields, Unsafe};

unsafe_fields! {
    /// A `usize` which is guaranteed to be even.
    pub struct EvenUsize {
        // INVARIANT: `n` is even.
        #[unsafe]
        n: usize,
    }
}

pub fn swap(a: &mut EvenUsize, b: &mut EvenUsize) {
    core::mem::swap(&mut a.n, &mut b.n);
}

Disclaimer

Disclaimer: This is not an officially supported Google product.

Commit count: 1123

cargo fmt