Rust compiler provides us the guarantee that if the code is compiled correctly without any error, then it will not cause any memory safety problems, but the check might be conservative and will even reject valid code because it cannot be recognized as “safe”. When dealing with low-level hardware or some other tasks, unsafe Rust seems to be a must. unsafe
trait will enable us to
union
sUnsafe will not disable borrow checker or any any other of Rust’s safety checks. This keyword only gives us the power to access to the above five things that are not checked by the Rust compiler. Unsafe is not intended to increase the danger; rather, it is means of accessing low-level components that cannot be manipulated with safe
code.
To isolate unsafe code as much as possible, it is best to enclose unsafe code within a safe abstraction and provide a safe API.
Rust compiler will always ensures that a reference points to something valid when we are using safe code. With unsafe Rust, we can directly access the raw pointer that is very similar to reference. As with references, raw pointers can be immutable or mutable and are written as *const T
and *mut T
, respectively.
Different from references and smart pointers, raw pointers:
NonNull<T>
)Raw pointers in Rust are almost the same as those in C / C++. By opting out of having Rust enforce these guarantees, we can give up guaranteed safety in exchange for greater performance or the ability to interface with another language or hardware where Rust’s guarantees don’t apply.
let mut num = 5;
// Cast reference to const int32_t*
let r1 = &num as *const i32;
// Cast mutable reference to int32_t*
let r2 = &mut num as *mut i32;
We can create raw pointers in safe code but are not allowed to dereference them unless in unsafe block.
let num = 5;
let addr = 0x12345678;
let ptr = &num as *const i32;
let ptr_ud = addr as *const i32;
unsafe {
// OK!
println!("num is {}", *ptr);
// Bad! This will cause segmentation fault.
prtinln!("UD: ", *addr);
}