rust-osdev/linked-list-allocator

How to provide implementation of libc calloc, free, realloc

Closed this issue · 4 comments

I'm currently using alloc-cortex-m which uses this crate and I'd like to implement some memory intrinsics of libc using the list allocator. In particular I need to implement calloc, free, realloc but I'm currently stuck with how to do it.

I think I've managed to do it for calloc (https://os.phil-opp.com/heap-allocation/ has been helpfulp 😄), but I've no idea for free and realloc. alloc::dealloc requires to know the layout, but the C function provides only a pointer, whereas alloc::realloc is not currently implemented in this crate.

This is what I've written so far, the target is thumbv7m-none-eabi:

const ALIGN: usize = core::mem::size_of::<i32>();

#[no_mangle]
pub extern "C" fn calloc(num: size_t, size: size_t) -> *mut c_void {
    let size = (num * size) as usize;
    let layout = core::alloc::Layout::from_size_align(size, ALIGN).expect("Cannot create layout");

    unsafe { alloc::alloc::alloc(layout) as *mut c_void }
}

#[no_mangle]
pub extern "C" fn free(_ptr: *mut u8) {
    unimplemented!()
}

#[no_mangle]
pub extern "C" fn realloc(ptr: *mut c_void, size: size_t) -> *mut c_void {
    if ptr.is_null() {
        return calloc(1, size);
    }

    unimplemented!()
}

I do not know the answer regarding free + realloc, but I have a suggestion for your calloc implementation. I believe you should be using alloc_zeroed instead of alloc because calloc guarantees zero-initialized memory.

-    unsafe { alloc::alloc::alloc(layout) as *mut c_void }
+    unsafe { alloc::alloc::alloc_zeroed(layout) as *mut c_void }

Thanks for the suggestion. For free and realloc, my only idea for now would be copying alloc-cortex-m implementation but with some map to keep track of the layouts keyed by the pointers but that map itself would require heap memory

C-style malloc/free normally stores some metadata alongside the allocation, which can then be read again on free. So if you allocate 100 bytes, malloc will allocate a few bytes more and additionally store the allocation size (and maybe other parameters). See https://danluu.com/malloc-tutorial/ for more details on this.

A simple solution for realloc is to allocate a new block of memory, copy over the contents, and then deallocate the old memory block. This is already implemented by the GlobalAlloc::realloc method, so this should work (after adding metadata to allocations for determining the size of the old block).

A more efficient implementation of realloc could check whether the memory block adjacent to the current allocation is unused and large enough to increase the size of the memory block in-place. However, this would require support from this crate and might not be easy to implement. Given that we allocate the heap memory linearly, the probability that the adjacent block is free is relatively low, so I'm not sure whether this optimization is worth the effort.

Hope this helps!

Yup that's enough for me! I'm closing the issue, I think I have enough info for now thanks