# Advanced Features Previous chapters incorporate the base tools to work with Rust as mainly intended, but there is morea bit different and esoteric ways to complete the Rust ecosystem. They complement specific situations. # Unsafe Rust is based on compiling the safest code possible, trying to prevent memory errors, catching issues at compile time,... but we can also code without making use of that - `Unsafe` Static analysis is conservative, even when something might work it expects the case where it will not thus not allowing certain things. `Unsafe` means that the compiler should ignore some safety measures and the coder takes full responsibility. Inherently, all programs are unsafe, how you interact with memory and the layers below is not as easy as safe coding, thus to interact with it you still have to do unsafe operations. ## Unsafe Superpowers ```rust unsafe { // Unsafe block allows the following operations: /// - Dereferencing raw pointers /// - Calling unsafe methods/functions /// - Modify mutable `STATIC` variables /// - Implement unsafe traits /// - Access fields of a `union` (unsafe feature) } ``` Unsafe does not disable ALL checks, it allows certain operations. Borrow checker is still set in place, it only allows the previously mention operations. `unsafe` does not mean dangerous, it still should access memory in a valid way and programmer takes resposibility of it. Best way to use `unsafe` is to create the underlying code with `unsafe` then make available a safe implementation of it. ### Dereferencing a Raw Pointer We now have `raw pointers` -> `*const T` `*mut T`: - Ignore borrowing rules -> Multiple mutable borrows at same variable - May not point to valid memory - Can be `NULL` - Don't implement a `Drop` or automatic cleanup Allows: - Faster code (less execution or checks) - Interface with outher languages or hardware which does not uphold Rust safety system ```rust let mut num = 5; let r1 = &num as *const i32; // Create pointer is safe let r2 = &mut num as *mut i32; // Creating pointer mutable is still safe unsafe { let deref_v = *r1; // Accessing the pointer is UNSAFE! } ``` ### Calling Unsafe Functions or Methods ```rust unsafe fn dangerous(){} //Unsafe makes the whole function an unsafe block! //... unsafe { dangerous(); // We know exactly what dangerous does and will now call it with all the knowledge of that function available } ``` #### Creating Safe abstractions of Unsafe code A function containing `unsafe` code can be safe! ```rust // Ex: split_at_mut function let mut v = vec![1,2,3,4,5,6]; let r = &mut v[..]; let (a,b) = r.split_at_mut(3); assert_eq!(a, &mut [1, 2, 3]); assert_eq!(b, &mut [4, 5, 6]); // Illegal implementation fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) { let len = slice.len(); assert!(mid <= len); (&mut slice[..mid], &mut slice[mid..]) // Return tuple, has 2 mutable borrows to the same vector, illegal! } // Unsafe Implementation use std::slice; fn split_at_mut(slice: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) { let len = slice.len(); let ptr = slice.as_mut_ptr(); // Creates pointer of the vector/slice assert!(mid <= len); unsafe { // We will now access pointer = UNSAFE ( // Takes pointer and creates a slice given number of elements after the element the pointer points at slice::form_raw_parts_mut(ptr, mid), // A pointer can move elements it points to thus // ptr.add(3) === point[3] // .add() is unsafe method, trusts the coder with knowing that the memory at certain location will be safe slice::from_raw_parts_mut(ptr.add(mid), len - mid) ) } // slice::from_raw_parts_mut returns a safe type, as slice which points to specific memory // One issue here is, slice is now given back in two parts, but ownership goes back to the original variable, what happens? // Is it now 2 parts of memory that have access to it? } ``` #### Using `extern` Function - Calling external code To use code form another language - inherently unsafe, but specially because we can't actually check anything the Rust way! ```rust extern "C" { fn abs(input: i32) -> i32; } //... unsafe { println!("Absolut of -3 in C is: {}", abs(-3)); } ``` `extern "ABI" { //code_calls }` The same way could be done from other languages: ```rust #[no_mangle] // Avoid compiler changing function names // That happens when compiler adds information for other processes of compilation / linking pub extern "C" fn call_from_c() { pintln!("Rust called from C!"); } ``` ### Acessing or Modifying a `mut static variable` Global variables = static variables in Rust Constants =/= static variables: - Constants can be duplicated in memory - Static variable access always a fixed memory address - Constants can't be modified - Static variables can be modified but access is unsage then ```rust static mut COUNTER: u32 = 0; // mutable static variable fn add_to_count(inc: u32) { unsafe { // Function is safe, but access is marked as unsafe COUNTER += inc; // modifying variable unsafely } } fn main() { add_to_count(3); unsafe { println!("COUNTER: {}", COUNTER); // Accessing unsafe static variable } } ``` Why is it unsafe? Static variables are that, variables. They have no checks in place to make sure multiple threads are accessing them. Prefer smart pointers. ### Implementing an `unsafe trait` ```rust unsafe trait Foo { // methods go here // trait must be marked unsafe, it at least 1 method is unsafe } unsafe impl Foo for i32 { // method implementations go here // Implementation of unsafe methods } fn main() {} ``` Ex: `Send` `Sync` If a struct has types that are `unsafe` or don't implement already the `Send/Sync` traits, we have to implement the type. Mark it as unsafe and let the compiler knwo we are the ones checking that the methods are safe. ### Accessing Fields of a Union `union` is like a struct but the used fields depend on what is intended to access at a time (Useful to interface with `C`). ```rust union MyUnion { f1: u32, f2: f32, } /// The union does not have 2 fields, it has memory for 1 /// We can either access f1 or f2, if we access a field that was not initialized, we will get the memory footprint intended but it may not make sense! let u = MyUnion {f1: 1}; unsafe {println!("What is f2: {}.", u.f2);} // MyUnion is initialized as a u32 value, we will take 4bytes and read them as a f32 instead, which may not match f1 intended value! ``` For more: https://doc.rust-lang.org/reference/items/unions.html They are cool ## When to use `unsafe` code When needed, it is not bad just more unsafe.