How to use Allocator API in no-std binary?

I am trying to use the (currently unstable) allocator API in a no-std binary. By my understanding:

  • I need to make an allocator (say a bitmap-allocator) and implement the Allocator trait on it.
  • Since it's a no-std binary, I cannot use std::vec::Vec directly, so I need to go via alloc::vec::Vec.
  • alloc needs to be explicitly declared as extern crate, so I would do something like extern crate alloc as std_alloc (The rename is because there is a alloc module in the binary crate)
  • alloc::vec::Vec has a second type parameter which specifies the allocator - so I would create a new vector as let v: Vec<i32, BitmapAllocator> = Vec::new().

This is where I get a million errors of the form The size of for values of type <insert-type> cannot be known at compile time. The trait core::marker::Size is not implemented for <insert-same-type>, even for primitive types such as usize, which is most certainly Size.
Why does this happen? How do I fix it?

Can you give an example of such error?

Well, the errors are of the form The size of for values of type <insert-type> cannot be known at compile time. The trait core::marker::Size is not implemented for <insert-same-type>. There are also a bunch of duplicate lang item messages, which I guess are causing the trouble (and the other error is a result of it). The full message is too long to be pasted here, so here goes a termbin.

I'm no expert on unusual targets, but it looks to me like those errors have something to do with trying to use the alloc crate at all, not specifically the allocator API โ€” and in particular that you somehow have ended up with two different copies of core being loaded.

Can you post source code for your project so far? Especially its Cargo.toml and any other build configuration you have.

I'd also try renaming your alloc module instead of the alloc crate to see if something is weird there. (This shouldn't matter, but...)

2 Likes

Yes, that seems likely. And I have no clue how.

Oh, the target is simply aarch64-unknown-none-softfloat. However, it is a Tier 2 target, with support being limited to only no_std development, so maybe that's why alloc cannot be used (although that shouldn't be the case...)

Welp, the error still persists.

Sure, RedDocMD / LittleOsMirror ยท GitLab.
So, I am building by calling make, which in turn simply calls cargo build. The .cargo folder has a config.toml file which specifies the target, the linker script, and instructions to build compiler-builtins and core. The rust-toolchain.toml file pins down the nightly version and the targets. The rest is fairly vanilla....

I see:

[unstable]
build-std-features = ["compiler-builtins-mem"]
build-std = ["core", "compiler_builtins"]

Maybe you should include "alloc" in the list of crates to build here.

1 Like

Bingo! Thanks for the lead. Now we have just two errors:

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

error: `#[alloc_error_handler]` function required, but not found

note: use `#![feature(default_alloc_error_handler)]` for a default error handler

error: could not compile `LittleOS` due to 2 previous errors

So, is there a way to disable the global allocator? Or do I have to define it and pinky promise never to use it?

I noticed in your original message you mentioned Vec::new() but that function includes a reference to the global allocator; you need new_in() instead. Maybe fixing that will help? I don't know if merely linking alloc needs a global allocator.

1 Like

I think that's the case, since I removed the Vec::new() statement. I just have the extern crate alloc as std_alloc.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.