Closed
Description
Original issue in emscripten-core/emscripten#15722 / rust-lang/rust#91628.
The minimal repro for C/C++ looks like this:
extern char maybe_func;
int main() {
int(*func)() = (int(*)())&maybe_func;
return func();
}
This produces the following LLVM IR with -target wasm32-unknown-emscripten
(but likely reproducible with other Wasm targets too):
@maybe_func = external local_unnamed_addr global i8, align 1
define hidden noundef i32 @__main_argc_argv(i32 noundef %0, ptr nocapture noundef readnone %1) local_unnamed_addr #0 {
%3 = tail call noundef i32 @maybe_func()
ret i32 %3
}
attributes #0 = { mustprogress norecurse "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" }
The Wasm generated by LLVM is corrupted, and wasm-opt
, wasm-validate
etc fail:
$ emcc temp.c -O -Wl,--allow-undefined
[parse exception: attempted pop from empty stack / beyond block start boundary at 262 (at 0:262)]
Fatal: error in parsing input
emcc: error: '/home/rreverser/emsdk/upstream/bin/wasm-emscripten-finalize --dyncalls-i64 --pass-arg=legalize-js-interface-exported-helpers a.out.wasm -o a.out.wasm --detect-features' failed (returned 1)
As discussed in linked issues, this is likely due to maybe_func
being called directly without bitcast handling that Wasm function pointers require. IIUC this is not possible to solve in general for arbitrary casts, but should be doable for extern symbols.