96 lines
2.8 KiB
Rust
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();
|
|
}
|