Search code examples
rustallocationrust-no-std

The initial values of static variables may not even match what’s specified in the source code


I'm working on a project around embedded systems. So I have to implement an alloc method for allocating a new segment of memory and dealloc for returning a past allocation to the allocator to reuse.

The following paragraph is taken from Book Rust for Rustaceans:

On platforms that truly run no code before they jump to the defined start symbol, like most embedded devices, the initial values of static variables may not even match what’s specified in the source code. In such cases, your initialization function will need to explicitly initialize the various static memory segments with the initial data values specified in your program binary.

I have exactly the same problem as in the paragraph above. At the run time Rust allocates a very large heap memory. Does anyone have a solution to this problem?

This code works on Linux but not on my device. Because Rust request for memory is much larger than the capacity of my device.

pub struct Heap {
    pub vector: Vec<u8>,
}

pub static mut MY_HEAP: Option<Heap> = None;

fn main() {
    unsafe {
        MY_HEAP = Some(Heap {
            vector: vec![1, 2, 3],
        })
    };
    unsafe {
        match &mut MY_HEAP {
            Some(h) => {
                println!("{:?}", h.vector);
            }
            None => (),
        }
    }
}

You can see the implementation of allocator below :

#![feature(allocator_api)]
#![feature(alloc_error_handler)]
#![no_std]
#![crate_name = "ql_alloc"]
#![crate_type = "rlib"]

use ql_sys as ql;
use core::alloc::{GlobalAlloc, Layout};
pub struct QLAllocator;

unsafe impl GlobalAlloc for QLAllocator {
    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
        let a = ql::Ql_MEM_Alloc(layout.size() as u32) as *mut u8;
        a
    }
    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
        ql::Ql_MEM_Free(ptr as *mut _ as *mut cty::c_void);
    }
}

#[alloc_error_handler]
fn on_oom(layout: Layout) -> ! {
    loop {}
}

Solution

  • I replaced MY_HEAP = Some(...) with core::ptr::write(&mut MY_HEAP, Some(...)) and problem was resolved.

    pub struct Heap {
        pub vector: Vec<u8>,
    }
    
    pub static mut MY_HEAP: Option<Heap> = None;
    
    fn main() {
        unsafe {
            assert!(MY_HEAP.is_none());
        }
        unsafe {
            core::ptr::write(
                &mut MY_HEAP,
                Some(Heap {
                    vector: vec![1, 2, 3],
                }),
            );
        };
        unsafe {
            match &mut MY_HEAP {
                Some(h) => {
                    println!("{:?}", h.vector);
                }
                None => (),
            }
        }
    }
    

    Thanks to trent ᶠᵒʳᵐᵉʳˡʸ ᶜˡ