1# ralloc 2 3Redox's fast & memory efficient userspace allocator. 4 5## A note on its state. 6 7It fully works, although it is relatively slow, since it haven't been optimized 8yet. There is currently no known bugs, but it haven't been carefully reviewed 9yet, so avoid using it in security critical programs. 10 11I consider the state of the code quality very good. 12 13## Using ralloc 14 15Add ralloc to `Cargo.toml`: 16 17```toml 18[dependencies.ralloc] 19git = "https://github.com/redox-os/ralloc.git" 20``` 21 22then import it in your main file: 23 24```rust 25extern crate ralloc; 26``` 27 28ralloc is now ready to roll! 29 30Note that ralloc cannot coexist with another allocator, unless they're deliberately compatible. 31 32## Features 33 34### Custom out-of-memory handlers 35 36You can set custom OOM handlers, by: 37 38```rust 39extern crate ralloc; 40 41fn my_handler() -> ! { 42 println!("Oh no. Blame somebody."); 43} 44 45fn main() { 46 ralloc::lock().set_oom_handler(my_handler); 47 // Do some stuff... 48} 49``` 50 51### Debug check: double free 52 53Ooh, this one is a cool one. ralloc detects various memory bugs when compiled 54with the `debug_tools` feature. These checks include double free checks: 55 56```rust 57extern crate ralloc; 58 59fn main() { 60 // We start by allocating some stuff. 61 let a = Box::new(500u32); 62 // Then we memcpy the pointer (this is UB). 63 let b = Box::from_raw(&a as *mut u32); 64 // Now both destructors are called. First a, then b, which is a double 65 // free. Luckily, ralloc provides a nice message for you, when in debug 66 // tools mode: 67 // Assertion failed: Double free. 68 69 // Setting RUST_BACKTRACE allows you to get a stack backtrace, so that you 70 // can find where the double free occurs. 71} 72``` 73 74### Debug check: memory leaks. 75 76ralloc got memleak superpowers too! Enable `debug_tools` and do: 77 78```rust 79extern crate ralloc; 80 81use std::mem; 82 83fn main() { 84 { 85 // We start by allocating some stuff. 86 let a = Box::new(500u32); 87 // We then leak `a`. 88 let b = mem::forget(a); 89 } 90 // The box is now leaked, and the destructor won't be called. 91 92 // To debug this we insert a memory leak check in the end of our programs. 93 // This will panic if a memory leak is found (and will be a NOOP without 94 // `debug_tools`). 95 ralloc::lock().debug_assert_no_leak(); 96} 97``` 98 99### Partial deallocation 100 101Many allocators limits deallocations to be allocated block, that is, you cannot 102perform arithmetics or split it. ralloc does not have such a limitation: 103 104```rust 105extern crate ralloc; 106 107use std::mem; 108 109fn main() { 110 // We allocate 200 bytes. 111 let vec = vec![0u8; 200]; 112 // Cast it to a pointer. 113 let ptr = vec.as_mut_ptr(); 114 115 // To avoid UB, we leak the vector. 116 mem::forget(vec); 117 118 // Now, we create two vectors, each being 100 bytes long, effectively 119 // splitting the original vector in half. 120 let a = Vec::from_raw_parts(ptr, 100, 100); 121 let b = Vec::from_raw_parts(ptr.offset(100), 100, 100); 122 123 // Now, the destructor of a and b is called... Without a segfault! 124} 125``` 126 127### Separate deallocation 128 129Another cool feature is that you can deallocate things that weren't even 130allocated buffers in the first place! 131 132Consider that you got a unused static variable, that you want to put into the 133allocation pool: 134 135```rust 136extern crate ralloc; 137 138static mut BUFFER: [u8; 256] = [2; 256]; 139 140fn main() { 141 // Throw `BUFFER` into the memory pool. 142 unsafe { 143 ralloc::lock().free(&mut BUFFER as *mut u8, 256); 144 } 145 146 // Do some allocation. 147 assert_eq!(*Box::new(0xDEED), 0xDEED); 148} 149``` 150 151### Top notch security 152 153If you are willing to trade a little performance, for extra security you can 154compile ralloc with the `security` flag. This will, along with other things, 155make frees zeroing. 156 157In other words, an attacker cannot for example inject malicious code or data, 158which can be exploited when forgetting to initialize the data you allocate. 159 160### Lock reuse 161 162Acquiring a lock sequentially multiple times can be expensive. Therefore, 163ralloc allows you to lock the allocator once, and reuse that: 164 165```rust 166extern crate ralloc; 167 168fn main() { 169 // Get that lock! 170 let lock = ralloc::lock(); 171 172 // All in one: 173 let _ = lock.alloc(4, 2); 174 let _ = lock.alloc(4, 2); 175 let _ = lock.alloc(4, 2); 176 177 // It is automatically released through its destructor. 178} 179``` 180 181### Security through the type system 182 183ralloc makes heavy use of Rust's type system, to make safety guarantees. 184Internally, ralloc has a primitive named `Block`. This is fairly simple, 185denoting a contagious segment of memory, but what is interesting is how it is 186checked at compile time to be unique. This is done through the affine type 187system. 188 189This is just one of many examples. 190 191### Platform agnostic 192 193ralloc is platform independent, with the only requirement of the following symbols: 194 1951. `sbrk`: For extending the data segment size. 1962. `sched_yield`: For the spinlock. 1973. `memcpy`, `memcmp`, `memset`: Core memory routines. 1984. `rust_begin_unwind`: For panicking. 199 200### Local allocators 201 202ralloc allows you to create non-global allocators, for e.g. thread specific purposes: 203 204```rust 205extern crate ralloc; 206 207fn main() { 208 // We create an allocator. 209 let my_alloc = ralloc::Allocator::new(); 210 211 // Allocate some stuff through our local allocator. 212 let _ = my_alloc.alloc(4, 2); 213 let _ = my_alloc.alloc(4, 2); 214 let _ = my_alloc.alloc(4, 2); 215} 216``` 217 218### Safe SBRK 219 220ralloc provides a `sbrk`, which can be used safely without breaking the allocator. 221