From cfd52bba1f77515017bdd1cd8d18ea2747990c2c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 10 Dec 2025 14:46:40 -0800 Subject: [PATCH] rustc: Stop passing `--allow-undefined` on wasm targets This commit updates how the linker is invoked on WebAssembly targets (all of them) to avoid passing the `--allow-undefined` flag to the linker. Historically, if I remember this correctly, when `wasm-ld` was first integrated this was practically required because at the time it was otherwise impossible to import a function from the host into a wasm binary. Or, at least, I'm pretty sure that was why this was added. At the time, as the documentation around this option indicates, it was known that this was going to be a hazard. This doesn't match behavior on native, for example, and can easily paper over what should be a linker error with some sort of other obscure runtime error. An example is that this program currently compiles and links, it just prints null: unsafe extern "C" { static nonexistent: u8; } fn main() { println!("{:?}", &raw const nonexistent); } This can easily lead to mistakes like rust-lang/libc/4880 and defer what should be a compile-time link error to weird or unusual behavior at link time. Additionally, in the intervening time since `wasm-ld` was first introduced here, lots has changed and notably this program works as expected: #[link(wasm_import_module = "host")] unsafe extern "C" { fn foo(); } fn main() { unsafe { foo(); } } Notably this continues to compile without error and the final wasm binary indeed has an imported function from the host. What this change means, however, is that this program: unsafe extern "C" { fn foo(); } fn main() { unsafe { foo(); } } this currently compiles successfully and emits an import from the `env` module. After this change, however, this will fail to compile with a link error stating that the `foo` symbol is not defined. --- compiler/rustc_target/src/spec/base/wasm.rs | 10 ---------- tests/run-make/wasm-stringify-ints-small/foo.rs | 2 ++ tests/run-make/wasm-unexpected-features/foo.rs | 5 +++++ tests/ui/linking/executable-no-mangle-strip.rs | 1 + 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_target/src/spec/base/wasm.rs b/compiler/rustc_target/src/spec/base/wasm.rs index 7ede45766ea59..1f0f564a77908 100644 --- a/compiler/rustc_target/src/spec/base/wasm.rs +++ b/compiler/rustc_target/src/spec/base/wasm.rs @@ -28,16 +28,6 @@ pub(crate) fn options() -> TargetOptions { // stack overflow will be guaranteed to trap as it underflows instead of // corrupting static data. concat!($prefix, "--stack-first"), - // FIXME we probably shouldn't pass this but instead pass an explicit list - // of symbols we'll allow to be undefined. We don't currently have a - // mechanism of knowing, however, which symbols are intended to be imported - // from the environment and which are intended to be imported from other - // objects linked elsewhere. This is a coarse approximation but is sure to - // hide some bugs and frustrate someone at some point, so we should ideally - // work towards a world where we can explicitly list symbols that are - // supposed to be imported and have all other symbols generate errors if - // they remain undefined. - concat!($prefix, "--allow-undefined"), // LLD only implements C++-like demangling, which doesn't match our own // mangling scheme. Tell LLD to not demangle anything and leave it up to // us to demangle these symbols later. Currently rustc does not perform diff --git a/tests/run-make/wasm-stringify-ints-small/foo.rs b/tests/run-make/wasm-stringify-ints-small/foo.rs index 7a947f013ad48..50ced86f3bc24 100644 --- a/tests/run-make/wasm-stringify-ints-small/foo.rs +++ b/tests/run-make/wasm-stringify-ints-small/foo.rs @@ -1,5 +1,6 @@ #![crate_type = "cdylib"] +#[link(wasm_import_module = "the-world")] extern "C" { fn observe(ptr: *const u8, len: usize); } @@ -7,6 +8,7 @@ extern "C" { macro_rules! s { ( $( $f:ident -> $t:ty );* $(;)* ) => { $( + #[link(wasm_import_module = "the-world")] extern "C" { fn $f() -> $t; } diff --git a/tests/run-make/wasm-unexpected-features/foo.rs b/tests/run-make/wasm-unexpected-features/foo.rs index 5c7aa2d619046..37062cb6f9d33 100644 --- a/tests/run-make/wasm-unexpected-features/foo.rs +++ b/tests/run-make/wasm-unexpected-features/foo.rs @@ -14,6 +14,11 @@ unsafe extern "Rust" { fn __rust_alloc_error_handler(size: usize, align: usize) -> !; } +#[rustc_std_internal_symbol] +pub unsafe fn __rdl_alloc_error_handler(_size: usize, _align: usize) -> ! { + loop {} +} + #[used] static mut BUF: [u8; 1024] = [0; 1024]; diff --git a/tests/ui/linking/executable-no-mangle-strip.rs b/tests/ui/linking/executable-no-mangle-strip.rs index cc283dc53ee3a..240c16af67bdb 100644 --- a/tests/ui/linking/executable-no-mangle-strip.rs +++ b/tests/ui/linking/executable-no-mangle-strip.rs @@ -1,5 +1,6 @@ //@ run-pass //@ ignore-windows-gnu: only statics marked with used can be GC-ed on windows-gnu +//@ ignore-wasm: wasm, for better or worse, exports all #[no_mangle] // Regression test for . // Functions in the binary marked with no_mangle should be GC-ed if they