Safety comments

Using unsafe blocks is often required in the Rust compiler or standard library, but this is not done without rules: each unsafe block should have a SAFETY: comment explaining why the block is safe, which invariants are used and must be respected. Below are some examples taken from the standard library:

Inside unsafe elements

This one shows how an unsafe function can pass the requirements through to its caller with the use of documentation in a # Safety section while still having more invariants needed that are not required from callers. clippy has a lint for # Safety sections by the way.

See the example on github

/// Converts a mutable string slice to a mutable byte slice.
///
/// # Safety
///
/// The caller must ensure that the content of the slice is valid UTF-8
/// before the borrow ends and the underlying `str` is used.
///
/// Use of a `str` whose contents are not valid UTF-8 is undefined behavior.
///
/// ...
pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
    // SAFETY: the cast from `&str` to `&[u8]` is safe since `str`
    // has the same layout as `&[u8]` (only libstd can make this guarantee).
    // The pointer dereference is safe since it comes from a mutable reference which
    // is guaranteed to be valid for writes.
    unsafe { &mut *(self as *mut str as *mut [u8]) }
}

This example is for a function but the same principle applies to unsafe traits like Send or Sync for example, though they have no # Safety section since their entire documentation is about why they are unsafe.

Note that in the Rust standard library, unsafe_op_in_unsafe_fn is active and so each unsafe operation in an unsafe function must be enclosed in an unsafe block. This makes it easier to review such functions and to document their unsafe parts.

Inside safe elements

Inside safe elements, a SAFETY: comment must not depend on anything from the caller beside properly constructed types and values (i.e, if your function receives a reference that is unaligned or null, it is the caller fault if it fails and not yours).

SAFETY comments in safe elements often rely on checks that are done before the unsafe block or on type invariants, like a division by NonZeroU8 would not check for 0 before dividing.

See the example on github

pub fn split_at(&self, mid: usize) -> (&str, &str) {
    // is_char_boundary checks that the index is in [0, .len()]
    if self.is_char_boundary(mid) {
        // SAFETY: just checked that `mid` is on a char boundary.
        unsafe { (self.get_unchecked(0..mid), self.get_unchecked(mid..self.len())) }
    } else {
        slice_error_fail(self, 0, mid)
    }
}