docs/rust/unsafe.md
unsafe code in first-party Chromium codeRust is well-known as a memory-safe language, but it has an escape hatch in the form of unsafe Rust, which permits developers to take responsibility from the compiler. Unsafe Rust can be more powerful or faster than safe Rust, but requires careful and precise design, as well as additional mental effort spent manually ensuring that no undefined behavior is possible.
This document discusses when and how to use unsafe code in first-party Chromium. There is a different policy for unsafe code in third-party libraries.
unsafeUsage of unsafe Rust is strongly discouraged in Chromium. It opens the door to undefined behavior, which can lead to bugs, crashes, or security vulnerabilities. Whenever possible, you should write your code using only safe Rust.
However, there are times when unsafe code is unavoidable, such as interacting
with C/C++ code, or when the performance overhead of safety (from bounds checks,
ref-counting, etc) is deemed unacceptable. Developers are permitted to opt
in to unsafe Rust by adding the allow_unsafe = true flag to their GN target.
Ultimately, even Rust with unsafe blocks is safer than C++. We trust Chromium
developers to use their judgement when choosing when to use unsafe code.
Importantly,
Using unsafe Rust does not require any additional review or approvals.
Unsafe code should be reviewed by local owners just like safe Rust code, albeit
with the same extra scrutiny they would apply to other high-risk parts of a CL.
unsafeChromium requires that all unsafe code is accompanied by a safety comment.
There are two types of safety documentation:
unsafe fn, unsafe trait) declare something which is
unsafe to use, e.g. a function that dereferences a pointer could cause UB if the
pointer is null. The safety comment on a declaration must describe the
requirements for the function to be used safely:/// Frobinate the glorb
///
/// # Safety
/// * `glorb` must be valid to dereference (non-null, valid, aligned, etc.)
unsafe fn frobinate(glorb: *const Glorb) { ... }
Of course, taking a &Glorb in the first place would be better.
unsafe {}, unsafe impl, etc) invoke an unsafe item, and
must have a safety comment explaining how the requirements in the declaration
are met:let glorb : Glorb = Glorb::new();
/// SAFETY: the pointer is derived from a reference and is guaranteed to be
/// safe to dereference.
unsafe { frobinate(ptr::from_ref(&glorb)) };
Safety comments don't need to be verbose or rehash basic Rust concepts: you should assume the reader is familiar with the borrow checker, can look up the specific requirements to dereference a pointer, and so on. The most important thing is that the comments are complete and precise: they are the main (and sometimes only) way for readers to reason about safety, so they must have all the relevant information.
In the future the presence of safety comments will be enforced at compile time via a clippy lint.
Write a safe implementation first. You can always retrofit it with unsafe if
you really need the performance later.
Keep it minimal as much as possible:
Encapsulate the unsafety: avoid exposing unsafe APIs, and rely only on local invariants that you can enforce yourself.
unsafe blocks should wrap only the parts that are actually unsafe:
// Bad
unsafe { do_something_dangerous(do_something_safe()) };
// Good
let x = do_something_safe();
unsafe { do_something_dangerous(x) };
Be precise: Document all safety conditions in your comments. If something isn't documented, don't rely on it for safety.
Be pedantic: Safety considerations can be subtle; it's a good idea to familiarize yourself with unsafe resources like the Rustonomicon, and do web searches if you're even a little unclear about anything.