14b65baa3Sticki# ralloc 26c5a0b16Sticki 36c5a0b16StickiRedox's fast & memory efficient userspace allocator. 44b65baa3Sticki 5fc19fb6dSticki## A note on its state. 6fc19fb6dSticki 7fc19fb6dStickiIt fully works, although it is relatively slow, since it haven't been optimized 8fc19fb6dStickiyet. There is currently no known bugs, but it haven't been carefully reviewed 9fc19fb6dStickiyet, so avoid using it in security critical programs. 10fc19fb6dSticki 11fc19fb6dStickiI consider the state of the code quality very good. 12fc19fb6dSticki 137f66ee45Sticki## Using ralloc 147f66ee45Sticki 157f66ee45StickiAdd ralloc to `Cargo.toml`: 167f66ee45Sticki 177f66ee45Sticki```toml 187f66ee45Sticki[dependencies.ralloc] 197f66ee45Stickigit = "https://github.com/redox-os/ralloc.git" 207f66ee45Sticki``` 217f66ee45Sticki 227f66ee45Stickithen import it in your main file: 237f66ee45Sticki 247f66ee45Sticki```rust 257f66ee45Stickiextern crate ralloc; 267f66ee45Sticki``` 277f66ee45Sticki 28*146a5db9Stickiralloc is now ready to roll! 297f66ee45Sticki 30fc19fb6dStickiNote that ralloc cannot coexist with another allocator, unless they're deliberately compatible. 31fc19fb6dSticki 324b65baa3Sticki## Features 334b65baa3Sticki 344b65baa3Sticki### Custom out-of-memory handlers 354b65baa3Sticki 364b65baa3StickiYou can set custom OOM handlers, by: 374b65baa3Sticki 384b65baa3Sticki```rust 394b65baa3Stickiextern crate ralloc; 404b65baa3Sticki 414b65baa3Stickifn my_handler() -> ! { 424b65baa3Sticki println!("Oh no. Blame somebody."); 434b65baa3Sticki} 444b65baa3Sticki 454b65baa3Stickifn main() { 46*146a5db9Sticki ralloc::lock().set_oom_handler(my_handler); 474b65baa3Sticki // Do some stuff... 484b65baa3Sticki} 494b65baa3Sticki``` 504b65baa3Sticki 514b65baa3Sticki### Debug check: double free 524b65baa3Sticki 53*146a5db9StickiOoh, this one is a cool one. ralloc detects various memory bugs when compiled 54*146a5db9Stickiwith the `debug_tools` feature. These checks include double free checks: 554b65baa3Sticki 564b65baa3Sticki```rust 57*146a5db9Stickiextern crate ralloc; 58*146a5db9Sticki 594b65baa3Stickifn main() { 604b65baa3Sticki // We start by allocating some stuff. 614b65baa3Sticki let a = Box::new(500u32); 624b65baa3Sticki // Then we memcpy the pointer (this is UB). 634b65baa3Sticki let b = Box::from_raw(&a as *mut u32); 644b65baa3Sticki // Now both destructors are called. First a, then b, which is a double 654b65baa3Sticki // free. Luckily, ralloc provides a nice message for you, when in debug 66*146a5db9Sticki // tools mode: 674b65baa3Sticki // Assertion failed: Double free. 684b65baa3Sticki 694b65baa3Sticki // Setting RUST_BACKTRACE allows you to get a stack backtrace, so that you 704b65baa3Sticki // can find where the double free occurs. 714b65baa3Sticki} 724b65baa3Sticki``` 734b65baa3Sticki 74*146a5db9Sticki### Debug check: memory leaks. 75*146a5db9Sticki 76*146a5db9Stickiralloc got memleak superpowers too! Enable `debug_tools` and do: 77*146a5db9Sticki 78*146a5db9Sticki```rust 79*146a5db9Stickiextern crate ralloc; 80*146a5db9Sticki 81*146a5db9Stickiuse std::mem; 82*146a5db9Sticki 83*146a5db9Stickifn main() { 84*146a5db9Sticki { 85*146a5db9Sticki // We start by allocating some stuff. 86*146a5db9Sticki let a = Box::new(500u32); 87*146a5db9Sticki // We then leak `a`. 88*146a5db9Sticki let b = mem::forget(a); 89*146a5db9Sticki } 90*146a5db9Sticki // The box is now leaked, and the destructor won't be called. 91*146a5db9Sticki 92*146a5db9Sticki // To debug this we insert a memory leak check in the end of our programs. 93*146a5db9Sticki // This will panic if a memory leak is found (and will be a NOOP without 94*146a5db9Sticki // `debug_tools`). 95*146a5db9Sticki ralloc::lock().debug_assert_no_leak(); 96*146a5db9Sticki} 97*146a5db9Sticki``` 98*146a5db9Sticki 994b65baa3Sticki### Partial deallocation 1004b65baa3Sticki 1014b65baa3StickiMany allocators limits deallocations to be allocated block, that is, you cannot 102*146a5db9Stickiperform arithmetics or split it. ralloc does not have such a limitation: 1034b65baa3Sticki 1044b65baa3Sticki```rust 105*146a5db9Stickiextern crate ralloc; 106*146a5db9Sticki 1074b65baa3Stickiuse std::mem; 108*146a5db9Sticki 1094b65baa3Stickifn main() { 1104b65baa3Sticki // We allocate 200 bytes. 1114b65baa3Sticki let vec = vec![0u8; 200]; 1124b65baa3Sticki // Cast it to a pointer. 1134b65baa3Sticki let ptr = vec.as_mut_ptr(); 1144b65baa3Sticki 1154b65baa3Sticki // To avoid UB, we leak the vector. 1164b65baa3Sticki mem::forget(vec); 1174b65baa3Sticki 1184b65baa3Sticki // Now, we create two vectors, each being 100 bytes long, effectively 1194b65baa3Sticki // splitting the original vector in half. 1204b65baa3Sticki let a = Vec::from_raw_parts(ptr, 100, 100); 1214b65baa3Sticki let b = Vec::from_raw_parts(ptr.offset(100), 100, 100); 1224b65baa3Sticki 1234b65baa3Sticki // Now, the destructor of a and b is called... Without a segfault! 1244b65baa3Sticki} 1254b65baa3Sticki``` 1264b65baa3Sticki 127*146a5db9Sticki### Separate deallocation 1284b65baa3Sticki 1294b65baa3StickiAnother cool feature is that you can deallocate things that weren't even 1304b65baa3Stickiallocated buffers in the first place! 1314b65baa3Sticki 1324b65baa3StickiConsider that you got a unused static variable, that you want to put into the 1334b65baa3Stickiallocation pool: 1344b65baa3Sticki 1354b65baa3Sticki```rust 1364b65baa3Stickiextern crate ralloc; 1374b65baa3Sticki 1384b65baa3Stickistatic mut BUFFER: [u8; 256] = [2; 256]; 1394b65baa3Sticki 1404b65baa3Stickifn main() { 1414b65baa3Sticki // Throw `BUFFER` into the memory pool. 1424b65baa3Sticki unsafe { 143*146a5db9Sticki ralloc::lock().free(&mut BUFFER as *mut u8, 256); 1444b65baa3Sticki } 1454b65baa3Sticki 1464b65baa3Sticki // Do some allocation. 1474b65baa3Sticki assert_eq!(*Box::new(0xDEED), 0xDEED); 1484b65baa3Sticki} 1494b65baa3Sticki``` 1504b65baa3Sticki 151*146a5db9Sticki### Top notch security 1524b65baa3Sticki 153*146a5db9StickiIf you are willing to trade a little performance, for extra security you can 154*146a5db9Stickicompile ralloc with the `security` flag. This will, along with other things, 155*146a5db9Stickimake frees zeroing. 1564b65baa3Sticki 157*146a5db9StickiIn other words, an attacker cannot for example inject malicious code or data, 158*146a5db9Stickiwhich can be exploited when forgetting to initialize the data you allocate. 1594b65baa3Sticki 1604b65baa3Sticki### Lock reuse 1614b65baa3Sticki 162*146a5db9StickiAcquiring a lock sequentially multiple times can be expensive. Therefore, 163*146a5db9Stickiralloc allows you to lock the allocator once, and reuse that: 164*146a5db9Sticki 165*146a5db9Sticki```rust 166*146a5db9Stickiextern crate ralloc; 167*146a5db9Sticki 168*146a5db9Stickifn main() { 169*146a5db9Sticki // Get that lock! 170*146a5db9Sticki let lock = ralloc::lock(); 171*146a5db9Sticki 172*146a5db9Sticki // All in one: 173*146a5db9Sticki let _ = lock.alloc(4, 2); 174*146a5db9Sticki let _ = lock.alloc(4, 2); 175*146a5db9Sticki let _ = lock.alloc(4, 2); 176*146a5db9Sticki 177*146a5db9Sticki // It is automatically released through its destructor. 178*146a5db9Sticki} 179*146a5db9Sticki``` 180*146a5db9Sticki 181*146a5db9Sticki### Security through the type system 182*146a5db9Sticki 183*146a5db9Stickiralloc makes heavy use of Rust's type system, to make safety guarantees. 184*146a5db9StickiInternally, ralloc has a primitive named `Block`. This is fairly simple, 185*146a5db9Stickidenoting a contagious segment of memory, but what is interesting is how it is 186*146a5db9Stickichecked at compile time to be unique. This is done through the affine type 187*146a5db9Stickisystem. 188*146a5db9Sticki 189*146a5db9StickiThis is just one of many examples. 1904b65baa3Sticki 1914b65baa3Sticki### Platform agnostic 1924b65baa3Sticki 193*146a5db9Stickiralloc is platform independent, with the only requirement of the following symbols: 194*146a5db9Sticki 195*146a5db9Sticki1. `sbrk`: For extending the data segment size. 196*146a5db9Sticki2. `sched_yield`: For the spinlock. 197*146a5db9Sticki3. `memcpy`, `memcmp`, `memset`: Core memory routines. 198*146a5db9Sticki4. `rust_begin_unwind`: For panicking. 199*146a5db9Sticki 200*146a5db9Sticki### Local allocators 201*146a5db9Sticki 202*146a5db9Stickiralloc allows you to create non-global allocators, for e.g. thread specific purposes: 203*146a5db9Sticki 204*146a5db9Sticki```rust 205*146a5db9Stickiextern crate ralloc; 206*146a5db9Sticki 207*146a5db9Stickifn main() { 208*146a5db9Sticki // We create an allocator. 209*146a5db9Sticki let my_alloc = ralloc::Allocator::new(); 210*146a5db9Sticki 211*146a5db9Sticki // Allocate some stuff through our local allocator. 212*146a5db9Sticki let _ = my_alloc.alloc(4, 2); 213*146a5db9Sticki let _ = my_alloc.alloc(4, 2); 214*146a5db9Sticki let _ = my_alloc.alloc(4, 2); 215*146a5db9Sticki} 216*146a5db9Sticki``` 217*146a5db9Sticki 218*146a5db9Sticki### Safe SBRK 219*146a5db9Sticki 220*146a5db9Stickiralloc provides a `sbrk`, which can be used safely without breaking the allocator. 221