rust-book/unsafe_blocks/src/main.rs

96 lines
2.8 KiB
Rust

//! Unsafe Example
//!
//! In Rust, unsafe means less automated safety, not no safety. It's an
//! escape hatch for code not normally allowed by the Rust compiler.
//!
//! Unsafe code allows the following 4 abilities:
//!
//! 1. Dereferencing raw pointers
//! 2. Calling an unsafe function or method
//! 3. Acessing/Mutating a mutable static variable (global)
//! 4. Implementing an unsafe trait
use std::slice;
extern "C" {
fn abs(input: i32) -> i32;
}
// Immutable static variable (global) - safe
static HELLO_WORLD: &str = "Hello, world!";
// Mutable static variable - unsafe to access or mutate
static mut COUNTER: u32 = 0;
fn raw_pointer() {
let mut num = 5;
// Casting references to raw pointers
// Raw pointers can be created in safe code,
// but can only be dereferenced in unsafe code
let r1 = &num as *const i32;
let r2 = &mut num as *mut i32;
unsafe {
println!("r1 is: {}", *r1);
println!("r2 is: {}", *r2);
}
}
/// An unsafe function can only be called within an unsafe block
/// This is essentially the same as wrapping the entire function in an unsafe block,
/// as an unsafe block in the function body is redundant
unsafe fn dangerous() {}
/// A 'safe' function can wrap unsafe code
fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
let len = slice.len();
let ptr = slice.as_mut_ptr(); // Get the raw pointer of the slice
assert!(mid <= len);
unsafe {
// These slice methods are unsafe because they require a valid pointer.
// Since the Rust compiler can not verify the safety of the pointers,
// the calls must be in an unsafe block. The function is still considered
// safe, though, because the original pointer is valid, and the bounds
// of the slice are verified with the assert call.
(
slice::from_raw_parts_mut(ptr, mid),
slice::from_raw_parts_mut(ptr.offset(mid as isize), len - mid)
)
}
}
/// A call to a function from a foreign programming language is considered
/// unsafe, as rust can not verify the safety of the external code.
/// While this can be wrapped in a 'safe' function, it is (unfortunately) up to the programmer
/// to make sure the call is actually safe
fn c_library_call() {
unsafe {
println!("Absolute value of -3 according to C: {}", abs(-3));
}
}
/// Mutable static variables (globals) are unsafe to access
/// or mutate due to the possibility of data races in multithreaded code
fn add_to_count(inc: u32) {
unsafe {
COUNTER += inc; // Mutating a mutable static variable is unsafe
}
}
fn main() {
raw_pointer();
add_to_count(3);
unsafe {
dangerous();
println!("COUNTER: {}", COUNTER); // Accessing a mutable static variable is unsafe
}
c_library_call();
}