diff options
Diffstat (limited to '')
-rw-r--r-- | rust/vendor/alloc-stdlib/README.md | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/rust/vendor/alloc-stdlib/README.md b/rust/vendor/alloc-stdlib/README.md new file mode 100644 index 0000000..f40bd29 --- /dev/null +++ b/rust/vendor/alloc-stdlib/README.md @@ -0,0 +1,205 @@ +# Framework for allocating memory in #![no_std] modules. + +[](https://crates.io/crates/alloc-no-stdlib) +[](https://travis-ci.org/dropbox/rust-alloc-no-stdlib) + + +## Requirements + * Rust 1.6 + +## Documentation +Currently there is no standard way to allocate memory from within a module that is no_std. +This provides a mechanism to allocate memory using the stdlib-independent +memory allocation system described by rust-alloc-no-stdlib +describe a memory allocation that can be satisfied entirely on +the stack, by unsafely linking to calloc, or by unsafely referencing a mutable global variable. +This library currently will leak memory if free_cell isn't specifically invoked on memory. + +However, if linked by a library that actually can depend on the stdlib then that library +can simply pass in a few allocators and use the standard Box allocation and will free automatically. + +This library should also make it possible to entirely jail a rust application that needs dynamic +allocations by preallocating a maximum limit of data upfront using calloc and +using seccomp to disallow future syscalls. + +## Usage + +There are 3 modes for allocating memory using the stdlib, each with advantages and disadvantages + + +### On the heap +This uses the standard Box facilities to allocate memory and assumeds a default constructor +for the given type + +```rust +let mut halloc = StandardAlloc::new(0); +for _i in 1..10 { // heap test + let mut x = <StandardAlloc as Allocator<u8>>::alloc_cell(&mut halloc, 100000) + x[0] = 4; + let mut y = <StandardAlloc as Allocator<u8>>::alloc_cell(&mut halloc, 100000) + y[0] = 5; + let mut z = <StandardAlloc as Allocator<u8>>::alloc_cell(&mut halloc, 100000) + z[0] = 6; + assert_eq!(y[0], 5); + halloc.free_cell(y); + assert_eq!(x[0], 4); + assert_eq!(x[9], 0); + assert_eq!(z[0], 6); +} +``` + +### On the heap +This uses the standard Box facilities to allocate memory but assuming a default user-provided value + +```rust +let mut halloc = HeapAlloc::<u8>::new(8); +for _i in 1..10 { // heap test + let mut x = halloc.alloc_cell(100000); + x[0] = 4; + let mut y = halloc.alloc_cell(110000); + y[0] = 5; + let mut z = halloc.alloc_cell(120000); + z[0] = 6; + assert_eq!(y[0], 5); + halloc.free_cell(y); + assert_eq!(x[0], 4); + assert_eq!(x[9], 8); + assert_eq!(z[0], 6); +} +``` + + +### On the heap, but uninitialized +This does allocate data every time it is requested, but it does not allocate the +memory, so naturally it is unsafe. The caller must initialize the memory properly +```rust +let mut halloc = unsafe{HeapAllocUninitialized::<u8>::new()}; +{ // heap test + let mut x = halloc.alloc_cell(100000); + x[0] = 4; + let mut y = halloc.alloc_cell(110000); + y[0] = 5; + let mut z = halloc.alloc_cell(120000); + z[0] = 6; + assert_eq!(y[0], 5); + halloc.free_cell(y); + assert_eq!(x[0], 4); + assert_eq!(x[9], 0); + assert_eq!(z[0], 6); + ... +} +``` + + +### On the heap in a single pool allocation +This does a single big allocation on the heap, after which no further usage of the stdlib +will happen. This can be useful for a jailed application that wishes to restrict syscalls +at this point + +```rust +use alloc_no_stdlib::HeapPrealloc; +... +let mut heap_global_buffer = define_allocator_memory_pool!(4096, u8, [0; 6 * 1024 * 1024], heap); +let mut ags = HeapPrealloc::<u8>::new_allocator(4096, &mut heap_global_buffer, uninitialized); +{ + let mut x = ags.alloc_cell(9999); + x.slice_mut()[0] = 4; + let mut y = ags.alloc_cell(4); + y[0] = 5; + ags.free_cell(y); + + //y.mem[0] = 6; // <-- this is an error (use after free) +} +``` + + + +### On the heap, uninitialized +This does a single big allocation on the heap, after which no further usage of the stdlib +will happen. This can be useful for a jailed application that wishes to restrict syscalls +at this point. This option keep does not set the memory to a valid value, so it is +necessarily marked unsafe + +```rust +use alloc_no_stdlib::HeapPrealloc; +... +let mut heap_global_buffer = unsafe{HeapPrealloc::<u8>::new_uninitialized_memory_pool(6 * 1024 * 1024)}; +let mut ags = HeapPrealloc::<u8>::new_allocator(4096, &mut heap_global_buffer, uninitialized); +{ + let mut x = ags.alloc_cell(9999); + x.slice_mut()[0] = 4; + let mut y = ags.alloc_cell(4); + y[0] = 5; + ags.free_cell(y); + + //y.mem[0] = 6; // <-- this is an error (use after free) +} +``` + +### With calloc +This is the most efficient way to get a zero'd dynamically sized buffer without the stdlib +It does invoke the C calloc function and hence must invoke unsafe code. +In this version, the number of cells are fixed to the parameter specified in the struct definition +(4096 in this example) + +```rust +extern { + fn calloc(n_elem : usize, el_size : usize) -> *mut u8; + fn malloc(len : usize) -> *mut u8; + fn free(item : *mut u8); +} + +declare_stack_allocator_struct!(CallocAllocatedFreelist4096, 4096, calloc); +... + +// the buffer is defined with 200 megs of zero'd memory from calloc +let mut calloc_global_buffer = unsafe {define_allocator_memory_pool!(4096, u8, [0; 200 * 1024 * 1024], calloc)}; +// and assigned to a new_allocator +let mut ags = CallocAllocatedFreelist4096::<u8>::new_allocator(&mut calloc_global_buffer.data, bzero); +{ + let mut x = ags.alloc_cell(9999); + x.slice_mut()[0] = 4; + let mut y = ags.alloc_cell(4); + y[0] = 5; + ags.free_cell(y); + //y.mem[0] = 6; // <-- this is an error (use after free) +} +``` + +### With a static, mutable buffer +If a single buffer of data is needed for the entire span of the application +Then the simplest way to do so without a zero operation on +the memory and without using the stdlib is to simply have a global allocated +structure. Accessing mutable static variables requires unsafe code; however, +so this code will invoke an unsafe block. + + +Make sure to only reference global_buffer in a single place, at a single time in the code +If it is used from two places or at different times, undefined behavior may result, +since multiple allocators may get access to global_buffer. + + +```rust +declare_stack_allocator_struct!(GlobalAllocatedFreelist, 16, global); +define_allocator_memory_pool!(16, u8, [0; 1024 * 1024 * 100], global, global_buffer); + +... +// this references a global buffer +let mut ags = GlobalAllocatedFreelist::<u8>::new_allocator(bzero); +unsafe { + bind_global_buffers_to_allocator!(ags, global_buffer, u8); +} +{ + let mut x = ags.alloc_cell(9999); + x.slice_mut()[0] = 4; + let mut y = ags.alloc_cell(4); + y[0] = 5; + ags.free_cell(y); + + //y.mem[0] = 6; // <-- this is an error (use after free) +} +``` + + +## Contributors +- Daniel Reiter Horn |