Code or interfaces whose memory safety cannot be verified by the type system.
The unsafe
keyword has two uses: to declare the existence of contracts the compiler can't check (unsafe fn
and unsafe trait
), and to declare that a programmer has checked that these contracts have been upheld (unsafe {}
and unsafe impl
, but also unsafe fn
-- see below). They are not mutually exclusive, as can be seen in unsafe fn
.
No matter what, Safe Rust can't cause Undefined Behavior. This is referred to as soundness: a well-typed program actually has the desired properties. The Nomicon has a more detailed explanation on the subject.
To ensure soundness, Safe Rust is restricted enough that it can be automatically checked. Sometimes, however, it is necessary to write code that is correct for reasons which are too clever for the compiler to understand. In those cases, you need to use Unsafe Rust.
Here are the abilities Unsafe Rust has in addition to Safe Rust:
unsafe
trait
sunsafe
functionsstatic
s (including extern
al ones)union
sHowever, this extra power comes with extra responsibilities: it is now up to you to ensure soundness. The unsafe
keyword helps by clearly marking the pieces of code that need to worry about this.
unsafe
Not all uses of unsafe
are equivalent: some are here to mark the existence of a contract the programmer must check, others are to say "I have checked the contract, go ahead and do this". The following discussion on Rust Internals has more in-depth explanations about this but here is a summary of the main points:
unsafe fn
: calling this function means abiding by a contract the compiler cannot enforce.unsafe trait
: implementing the trait
means abiding by a contract the compiler cannot enforce.unsafe {}
: the contract necessary to call the operations inside the block has been checked by the programmer and is guaranteed to be respected.unsafe impl
: the contract necessary to implement the trait has been checked by the programmer and is guaranteed to be respected.unsafe fn
also acts like an unsafe {}
block around the code inside the function. This means it is not just a signal to the caller, but also promises that the preconditions for the operations inside the function are upheld. Mixing these two meanings can be confusing and proposals exist to use unsafe {}
blocks inside such functions when making unsafe
operations.
See the Rustnomicon and the Reference for more informations.
unsafe
unsafe
can be used on functions. Note that functions and statics declared in extern
blocks are implicitly marked as unsafe
(but not functions declared as extern "something" fn ...
). Mutable statics are always unsafe, wherever they are declared. Methods can also be declared as unsafe
:
static mut FOO: &str = "hello"; unsafe fn unsafe_fn() {} extern "C" { fn unsafe_extern_fn(); static BAR: *mut u32; } trait SafeTraitWithUnsafeMethod { unsafe fn unsafe_method(&self); } struct S; impl S { unsafe fn unsafe_method_on_struct() {} }
Traits can also be declared as unsafe
:
unsafe trait UnsafeTrait {}
Since unsafe fn
and unsafe trait
indicate that there is a safety contract that the compiler cannot enforce, documenting it is important. The standard library has many examples of this, like the following which is an extract from Vec::set_len
. The # Safety
section explains the contract that must be fulfilled to safely call the function.
/// Forces the length of the vector to `new_len`. /// /// This is a low-level operation that maintains none of the normal /// invariants of the type. Normally changing the length of a vector /// is done using one of the safe operations instead, such as /// `truncate`, `resize`, `extend`, or `clear`. /// /// # Safety /// /// - `new_len` must be less than or equal to `capacity()`. /// - The elements at `old_len..new_len` must be initialized. pub unsafe fn set_len(&mut self, new_len: usize)
unsafe {}
blocks and impl
sPerforming unsafe
operations requires an unsafe {}
block:
/// Dereference the given pointer. /// /// # Safety /// /// `ptr` must be aligned and must not be dangling. unsafe fn deref_unchecked(ptr: *const i32) -> i32 { *ptr } let a = 3; let b = &a as *const _; // SAFETY: `a` has not been dropped and references are always aligned, // so `b` is a valid address. unsafe { assert_eq!(*b, deref_unchecked(b)); };
Traits marked as unsafe
must be impl
emented using unsafe impl
. This makes a guarantee to other unsafe
code that the implementation satisfies the trait's safety contract. The Send and Sync traits are examples of this behaviour in the standard library.
/// Implementors of this trait must guarantee an element is always /// accessible with index 3. unsafe trait ThreeIndexable<T> { /// Returns a reference to the element with index 3 in `&self`. fn three(&self) -> &T; } // The implementation of `ThreeIndexable` for `[T; 4]` is `unsafe` // because the implementor must abide by a contract the compiler cannot // check but as a programmer we know there will always be a valid element // at index 3 to access. unsafe impl<T> ThreeIndexable<T> for [T; 4] { fn three(&self) -> &T { // SAFETY: implementing the trait means there always is an element // with index 3 accessible. unsafe { self.get_unchecked(3) } } } let a = [1, 2, 4, 8]; assert_eq!(a.three(), &8);
© 2010 The Rust Project Developers
Licensed under the Apache License, Version 2.0 or the MIT license, at your option.
https://doc.rust-lang.org/std/keyword.unsafe.html