Search code examples
rustembeddedrust-no-std

no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait


I am currently working on an embedded development project using the Rust.

However, when I tried to use my own library, which I had been using individually (and as a standard library), in an application on the embedded side, an error occurred as shown in the title.

error: no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait

For the sake of brevity and sharing, we will consider a reproducible folder structure as follows.

- foo
   |__ app
   |    |__ src
   |    |    |__ main.rs
   |    |__ Cargo.toml
   |
   |__ some-crate 
        |__ src
             |__ lib.rs

main.rs is currently look like below:

#![no_std]
#![no_main]
#![feature(default_alloc_error_handler)]
    
use sample_crate::add;
   
#[no_mangle]
extern "C" fn sample_main() {
    loop {
       add(2, 2);
    }
}

and some-crate/lib.rs

#![cfg_attr(not(feature = "std"), no_std)]
#![warn(unused_extern_crates, dead_code)]

#[cfg(not(feature = "std"))]
#[allow(unused_imports)]
#[macro_use]
extern crate alloc;

pub fn add(left: usize, right: usize) -> usize {
    left + right
}

It could compile if I do not import some-crate::add. How can I make this compile with third party crate?


Solution

  • If you link with alloc you need to have a global allocator. That is usually provided by std, but if you omit the std crate then you need to provide it yourself, as the no_std environment just does not know how to handle the memory.

    Many embedded systems have a reference implementation of good old C malloc/free functions. If you have those, or similar, you can do a binding to those C functions and then write something like this somewhere in your crate:

    use alloc::alloc::*;
    
    /// The global allocator type.
    #[derive(Default)]
    pub struct Allocator;
    
    unsafe impl GlobalAlloc for Allocator {
         unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
             malloc(layout.size() as u32) as *mut u8
         }
         unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
             free(ptr as *mut c_void);
         }
    }
    
    /// If there is an out of memory error, just panic.
    #[alloc_error_handler]
    fn my_allocator_error(_layout: Layout) -> ! {
        panic!("out of memory");
    }
    
    /// The static global allocator.
    #[global_allocator]
    static GLOBAL_ALLOCATOR: Allocator = Allocator;