-1

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 {}
}
p3zhy
  • 81
  • 8
  • Could you please clarify what doesn't work as intended with the code given? – E_net4 Jan 07 '22 at 10:33
  • This code works on Linux but not on my device. Because Rust request for memory is much larger than the capacity of my device. – p3zhy Jan 07 '22 at 10:40
  • I'm still confused. What does the RfR paragraph quoted (about initialization of **static** memory) have to do with your question (about allocation of **heap** memory)? – trent Jan 07 '22 at 10:52
  • Rust requires a very large amount of memory, while my code defines a three byte vector. – p3zhy Jan 07 '22 at 11:01
  • 1
    That doesn't answer my question. What does the OOM issue have to do with static initialization? – trent Jan 07 '22 at 11:18
  • I guess because initialization is not done correctly, rust requests the wrong amount of memory – p3zhy Jan 07 '22 at 11:26
  • 1
    Why do you believe those things are related? Off the top of my head, if `MY_HEAP` is uninitialized, you need to initialize it with `ptr::write` instead of `=`, but that error would manifest as a spurious `free`, not OOM. – trent Jan 07 '22 at 11:37
  • Please explain your solution more clearly. – p3zhy Jan 07 '22 at 11:58
  • 1
    Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/240822/discussion-between-trent---and-pejman). – trent Jan 07 '22 at 12:08
  • 1
    You can add `assert!(MY_HEAP.is_none())` to the beginning of `main()` and see if the assert trips. If the assert passes, your static is initialized correctly. Trent's solution implies that your problem lies somewhere other than where you think it is, and you should check what your allocator receives and returns to debug it. Perhaps your allocation library is not correctly initialized? – user4815162342 Jan 07 '22 at 13:00
  • assert!(MY_HEAP.is_none()) in linux passed but in my device failed! – p3zhy Jan 07 '22 at 13:39

1 Answers1

1

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 ᶠᵒʳᵐᵉʳˡʸ ᶜˡ

Tyler2P
  • 2,324
  • 26
  • 22
  • 31
p3zhy
  • 81
  • 8