Are assert! statements included in unsafe blocks?

In the Rust documentation for assert here https://doc.rust-lang.org/std/macro.assert.html it is stated that " Unsafe code relies on assert! to enforce run-time invariants that, if violated could lead to unsafety." This seems to counter my concept of systems programming languages not inserting things implicitly. The section on unsafe code in the rust book also makes no mentions of the assert macro being inserted.

Am I misunderstanding the sentence and assert! is not actually inserted in unsafe code, or am I not understanding the need for such statements?

You, the developer, has to actually write assertions if you want your unsafe blocks to assert their invariant constraints.

1 Like

I think this would be more clear as "unsafe code often relies on assert! to...". It should be read as descriptive, not prescriptive - unsafe code is not required to do this, and the compiler does not insert assert!. It's just describing the fact that most unsafe code segments do use assert! and friends to validate data before using it in unsafe code blocks.

4 Likes

assert!ions are usually placed inside a safe context before doing an unsafe thing:

fn safe_fn(x: usize) {
    assert!(x != 0);
    unsafe {
        cannot_take_0(x);
    }
}

However, sometimes it is unfeasible to split unsafe blocks up, and would lead to code clutter. Hence, you may move your assert!ion into unsafe code.

It is useful to include assert! calls however, since they may signal the compiler to optimize better *:

fn foo(up_to: usize, slice: &mut [usize]) {
    assert!(up_to < slice.len());
    for i in 0..up_to {
        slice[i] *= 2;
    }
}

Might be optimized to an equivalent of

fn foo(up_to: usize, slice: &mut [usize]) {
    assert!(up_to < slice.len());
    for i in 0..up_to {
        unsafe {
            *slice.get_unchecked_mut(i) *= 2;
        }
    }
}

Which elides the bounds checks.


*However, I might personally write that function in a more functional style:

fn foo(up_to: usize, slice: &mut [usize]) {
    slice[..up_to]
        .iter_mut()
        .for_each(|x| *x *= 2);
}
2 Likes
3 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.