Repository navigation
Building a no_std program without explicitly using eyra now fails with "no global memory allocator found but one is required" #60
Description
This might not be Eyra specifically, and technically it's a non-issue, I only observed this when building a basic program that only needs the rustix dep, but having eyra in the Cargo.toml deps introduced a build failure with nightly in the past month. My actual project had two separate sources in src/bin/*.rs, one was for Eyra, another for Rustix.
Since it's highly likely one of the crates that @sunfishcode maintains, I thought I'd open an issue to raise awareness of the observation just in case there was a mistaken assumption made 🤔 I assume because of the eyra dep during compilation, even though it's not used/required, it now messes with the global allocator in some manner?
Reproduction
Cargo.toml:
[package]
name = "example"
version = "0.1.0"
edition = "2024"
[dependencies]
eyra = { version = "0.21.0", default-features = false }
rustix = { version = "1.0.0", default-features = false, features = ["runtime", "stdio"] }
# Requirements to build (unrelated to reported build failure with eyra)
# `no_std` usage in `src/main.rs` requires `panic="abort"`
# `lto = true` is a workaround required in nightly, alternatively `-Z build-std`
# More details covered in collapsed segment of:
# https://github.com/sunfishcode/eyra/issues/60#issuecomment-2892735792
[profile.release]
lto = true
panic = "abort"src/main.rs:
#![no_std]
#![no_main]
#[unsafe(no_mangle)]
pub extern "C" fn _start() -> ! {
hello_world();
exit();
}
fn exit() -> ! { unsafe { rustix::runtime::exit_thread(42) } }
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! { loop {} }
#[inline(always)]
fn hello_world() {
rustix::io::write(
unsafe { rustix::stdio::stdout() },
"Hello, world!\n".as_bytes()
).unwrap();
}Nightly May
rust-toolchain.toml:
[toolchain]
profile = "minimal"
channel = "nightly-2025-05-18"
components = ["rust-src"]
targets = ["x86_64-unknown-linux-gnu"]$ RUSTFLAGS="-C target-feature=+crt-static -C relocation-model=static -C link-arg=-nostartfiles" cargo build --release --target x86_64-unknown-linux-gnu
# ...
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: could not compile `example` (bin "example") due to 1 previous errorNightly April
An earlier nightly is required with older crate versions to compile approx a month ago:
[toolchain]
profile = "minimal"
channel = "nightly-2025-04-14"
components = ["rust-src"]
targets = ["x86_64-unknown-linux-gnu"]This requires a few changes to be compatible with the earlier nightly, but now it builds without the global allocator requirement:
# Rollback eyra one release:
$ cargo add eyra@0.20.0
# Pin `unwinding` for nightly compatibility:
# (related to newer nightly change making the naked attribute safe)
$ cargo update unwinding --precise 0.2.5
$ RUSTFLAGS="-C target-feature=+crt-static -C relocation-model=static -C link-arg=-nostartfiles" cargo +nightly-2025-04-14 build --release --target x86_64-unknown-linux-gnu
# ...
Compiling example v0.1.0 (/example)
Finished `release` profile [optimized] target(s) in 54.42sFor context, the eyra rollback made the following lock file adjustments:
Downgrading c-gull v0.22.1 -> v0.21.0
Downgrading c-scape v0.22.1 -> v0.21.0
Downgrading eyra v0.21.0 -> v0.20.0 (available: v0.22.0)
Downgrading getrandom v0.3.3 -> v0.2.16
Adding itoa v1.0.15
Adding linux-raw-sys v0.4.15
Downgrading origin v0.26.2 -> v0.24.0
Downgrading rand v0.9.1 -> v0.8.5
Downgrading rand_core v0.9.3 -> v0.6.4
Downgrading rand_pcg v0.9.0 -> v0.3.1
Adding rustix v0.38.44
Downgrading rustix-dlmalloc v0.2.2 -> v0.1.7
Downgrading rustix-futex-sync v0.4.0 -> v0.2.3
Downgrading rustix-openpty v0.2.0 -> v0.1.1
Downgrading wasi v0.14.2+wasi-0.2.4 -> v0.11.0+wasi-snapshot-preview1
Activity
bjorn3 commentedon May 19, 2025
It is expected that eyra isn't actually linked in if you don't reference it from your program in some way. (even
use eyra as _;should be enough to link it) Rustc just ignores dependencies passed in by cargo when the source code doesn't actually reference the dependency in question.polarathene commentedon May 19, 2025
I don't mind the compilation of the crates that occurs when I run the command, but the point was that
Cargo.tomljust had eyra added there, I had no actual use for it in the program compiled. Commenting it out will build successfully, but when the dep is declared inCargo.tomlit causes the global allocator fail.If you remove eyra from both nightly examples, the rustix program builds successfully. So I am not sure what changed, but I assume something is now being detected at build even though I am not opting into using eyra explicitly.
Perhaps I could better word the issue title? 😅
sunfishcode commentedon May 20, 2025
The error might be due to c-scape enabling the "fde-registry" feature of the unwinding crate. That feature causes the unwinding crate to use
alloc::boxed::Box, which I theorize is what's prompting that error. That said, I don't know why this didn't occur in older versions. If this is the problem, then the fix will probably be to chance c-scape to not enable fde-registry by default.polarathene commentedon May 20, 2025
UPDATE: Given the information I cited below regarding
c-scape+unwinding, that sounds quite likely?I see that because the rustix example is rather simple, a global allocator should only be required when using
alloc. Thus the change you mention is probably introducing a failure as crates are redundantly compiled?Since I don't actually use eyra in the example program (only in
Cargo.tomlto trigger the failure), I assume this is due to cargo building crates that won't actually be needed for buildingsrc/main.rs🤔 Cargo just doesn't know any better?I think my reproduction might be a little inaccurate 😬(EDIT: I've now added the two settings toCargo.toml)I had been using LTO with
panic=abort(which as noted here in the "Additional Context" section, the failure noted on nightly withrustixshouldn't really occur due topanic=abortremoving the need for an unwinder? And the follow-up comment at that issue further notesno_stdshould be skipping any requirement for an unwinder, butc-scapeenforced it regardless).So it may be related to the
unwindingdep inc-scapenot beingno_std/panic=abortaware?Settings required in `Cargo.toml` for building `no_std`
To build the Rustix example with
eyraremoved fromCargo.tomlstill seems to require enablinglto = true+panic = "abort"or adding the equivalentRUSTFLAGS='-C lto=true -C embed-bitcode=yes -C panic=abort'(EDIT:panic=abortwith-Z build-stdworks fine too).Not having that addition will fail to build on stable or nightly with (EDIT: stable channel only requires
-C panic=abortdue to panic handler):Additional Context (specific to
rustix/no_std)-C embed-bitcode=yesis implicit when usinglto=trueinCargo.tomlI think, as without that when using theRUSTFLAGSalternative,linux-raw-sysfails to build:I also noticed that LTO is only necessary with nightly due to this failure:
I have noticed that nightly bundles it's own
lld(rust-lld), I can use the system one via-C link-self-contained=no(error will replacerust-lldwithld-lldon fedora whenlldpackage is installed, no need for adding-C link-arg=-fuse-ld=lld).unwinding 0.2.5(which would now need to pinunwindingto that version too, or use a newer nightly withunwinding@0.2.6).-Z build-std(despite not using std). Enabling LTO instead presumably optimizes therust_eh_personalitysymbol away? I'm not entirely sure of the difference between stable and nightly channel regarding why only nightly needs one of these as a workaround.bjorn3 commentedon May 20, 2025
Even with panic=abort we still need to provide an unwinder in case non-Rust code attempts to unwind. As well as for backtraces.