Rust’s main draw is its powerful static guarantees about behavior. But safety
checks are conservative by nature: there are some programs that are actually
safe, but the compiler is not able to verify this is true. To write these kinds
of programs, we need to tell the compiler to relax its restrictions a bit. For
this, Rust has a keyword, unsafe
`unsafe. Code using
`. Code using unsafe
`unsafe` has less restrictions
than normal code does.
Let’s go over the syntax, and then we’ll talk semantics. unsafe
`unsafe` is used in
two contexts. The first one is to mark a function as unsafe:
unsafe fn danger_will_robinson() { // scary stuff }
All functions called from FFI must be marked as unsafe
`unsafe, for example. The second use of
`, for example.
The second use of unsafe
`unsafe` is an unsafe block:
unsafe { // scary stuff }
It’s important to be able to explicitly delineate code that may have bugs that
cause big problems. If a Rust program segfaults, you can be sure it’s somewhere
in the sections marked unsafe
`unsafe`.
Safe, in the context of Rust, means “doesn’t do anything unsafe.” Easy!
Okay, let’s try again: what is not safe to do? Here’s a list:
&mut T
`&mut Tand
` and &T
`&Tfollow LLVM’s scoped [noalias][noalias] model, except if the
` follow LLVM’s scoped noalias model, except if
the &T
`&Tcontains an
` contains an UnsafeCell<U>
`UnsafeCell`. Unsafe code must not violate these
aliasing guarantees.UnsafeCell<U>
`UnsafeCell`std::ptr::offset
`std::ptr::offset(
`
(offset
`offset` intrinsic), with
the exception of one byte past the end which is permitted.std::ptr::copy_nonoverlapping_memory
`std::ptr::copy_nonoverlapping_memory(
` (memcpy32
`memcpy32/
`/memcpy64
`memcpy64`
intrinsics) on overlapping buffersfalse
`false(0) or
` (0) or true
`true(1) in a
` (1) in a bool
`bool`enum
`enum` not included in its type definitionchar
`charwhich is a surrogate or above
` which is a surrogate or above char::MAX
`char::MAX`str
`str`Whew! That’s a bunch of stuff. It’s also important to notice all kinds of behaviors that are certainly bad, but are expressly not unsafe:
Rust cannot prevent all kinds of software problems. Buggy code can and will be
written in Rust. These things aren’t great, but they don’t qualify as unsafe
`unsafe`
specifically.
In both unsafe functions and unsafe blocks, Rust will let you do three things that you normally can not do. Just three. Here they are:
That’s it. It’s important that unsafe
`unsafedoes not, for example, ‘turn off the borrow checker’. Adding
` does not, for example, ‘turn off the
borrow checker’. Adding unsafe
`unsafe` to some random Rust code doesn’t change its
semantics, it won’t just start accepting anything.
But it will let you write things that do break some of the rules. Let’s go over these three abilities in order.
static mut
`static mut`Rust has a feature called ‘static mut
`static mut`’ which allows for mutable global state.
Doing so can cause a data race, and as such is inherently not safe. For more
details, see the static section of the book.
Raw pointers let you do arbitrary pointer arithmetic, and can cause a number of different memory safety and security issues. In some senses, the ability to dereference an arbitrary pointer is one of the most dangerous things you can do. For more on raw pointers, see their section of the book.
This last ability works with both aspects of unsafe
`unsafe: you can only call functions marked
`: you can only call
functions marked unsafe
`unsafe` from inside an unsafe block.
This ability is powerful and varied. Rust exposes some compiler intrinsics as unsafe functions, and some unsafe functions bypass safety checks, trading safety for speed.
I’ll repeat again: even though you can do arbitrary things in unsafe blocks and functions doesn’t mean you should. The compiler will act as though you’re upholding its invariants, so be careful!