xref: /relibc/ralloc/README.md (revision 146a5db98f2dcff608e1f3a30330e0cf1527786e)
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