axlibc/
malloc.rs

1//! Provides the corresponding malloc(size_t) and free(size_t) when using the C user program.
2//!
3//! The normal malloc(size_t) and free(size_t) are provided by the library malloc.h, and
4//! sys_brk is used internally to apply for memory from the kernel. But in a unikernel like
5//! `ArceOS`, we noticed that the heap of the Rust user program is shared with the kernel. In
6//! order to maintain consistency, C user programs also choose to share the kernel heap,
7//! skipping the sys_brk step.
8
9use alloc::alloc::{alloc, dealloc};
10use core::alloc::Layout;
11use core::ffi::c_void;
12
13use crate::ctypes;
14
15#[repr(C, align(8))]
16struct MemoryControlBlock {
17    size: usize,
18}
19
20const CTRL_BLK_SIZE: usize = core::mem::size_of::<MemoryControlBlock>();
21
22/// Allocate memory and return the memory address.
23///
24/// Returns 0 on failure (the current implementation does not trigger an exception)
25#[unsafe(no_mangle)]
26pub unsafe extern "C" fn malloc(size: ctypes::size_t) -> *mut c_void {
27    // Allocate `(actual length) + 8`. The lowest 8 Bytes are stored in the actual allocated space size.
28    // This is because free(uintptr_t) has only one parameter representing the address,
29    // So we need to save in advance to know the size of the memory space that needs to be released
30    let layout = Layout::from_size_align(size + CTRL_BLK_SIZE, 8).unwrap();
31    unsafe {
32        let ptr = alloc(layout).cast::<MemoryControlBlock>();
33        assert!(!ptr.is_null(), "malloc failed");
34        ptr.write(MemoryControlBlock { size });
35        ptr.add(1).cast()
36    }
37}
38
39/// Deallocate memory.
40///
41/// (WARNING) If the address to be released does not match the allocated address, an error should
42/// occur, but it will NOT be checked out. This is due to the global allocator `Buddy_system`
43/// (currently used) does not check the validity of address to be released.
44#[unsafe(no_mangle)]
45pub unsafe extern "C" fn free(ptr: *mut c_void) {
46    if ptr.is_null() {
47        return;
48    }
49    let ptr = ptr.cast::<MemoryControlBlock>();
50    assert!(ptr as usize > CTRL_BLK_SIZE, "free a null pointer");
51    unsafe {
52        let ptr = ptr.sub(1);
53        let size = ptr.read().size;
54        let layout = Layout::from_size_align(size + CTRL_BLK_SIZE, 8).unwrap();
55        dealloc(ptr.cast(), layout)
56    }
57}