-
Notifications
You must be signed in to change notification settings - Fork 16.7k
Open
Labels
Milestone
Description
Compiling and linking the following llvm ir behaves differently between llvm 20 and llvm 21. I think the llvm 21 behavior is a miscompilation. Causes this downstream issue: rust-lang/rust#153948
Gist: https://gist.github.com/hoodmane/50aac5028f24352fa59685acbea6b6e6
wasm_eh_regression.ll
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-f128:64-n32:64-S128-ni:1:10:20"
target triple = "wasm32-unknown-emscripten"
declare ptr @llvm.wasm.get.exception(token)
declare i32 @llvm.wasm.get.ehselector(token)
declare i32 @__gxx_wasm_personality_v0(...)
declare void @resume_unwind(i32) noreturn
declare void @do_catch(ptr, i32) nounwind
declare void @start_cleanup()
declare void @end_cleanup()
declare void @panic_in_cleanup() noreturn nounwind
declare void @panic_cannot_unwind() noreturn nounwind
define void @catch_unwind_in_cleanup() personality ptr @__gxx_wasm_personality_v0 {
start:
; Outer resume_unwind
invoke void @resume_unwind(i32 1)
to label %unreachable unwind label %outer_cleanuppad
outer_cleanuppad:
%outer_pad = cleanuppad within none []
call void @start_cleanup() [ "funclet"(token %outer_pad) ]
; Inner resume_unwind inside of drop
invoke void @resume_unwind(i32 2) [ "funclet"(token %outer_pad) ]
to label %unreachable unwind label %inner_catchswitch
; inner catch_unwind
inner_catchswitch:
%inner_cs = catchswitch within %outer_pad [label %inner_catchpad] unwind label %terminate_catchswitch
inner_catchpad:
%inner_cp = catchpad within %inner_cs [ptr null]
%exn = call ptr @llvm.wasm.get.exception(token %inner_cp)
%sel = call i32 @llvm.wasm.get.ehselector(token %inner_cp)
invoke void @do_catch(ptr %exn, i32 2) [ "funclet"(token %inner_cp) ]
to label %inner_catchret unwind label %terminate_catchswitch
; Call panic_in_cleanup if exception propagates out of inner_catchpad
; we catch everything so %terminate_catchswitch should be unreachable
terminate_catchswitch:
%term_cs = catchswitch within %outer_pad [label %terminate_catchpad] unwind label %outer_catchswitch
terminate_catchpad:
%term_pad = catchpad within %term_cs [ptr null]
call void @panic_in_cleanup() [ "funclet"(token %term_pad) ]
unreachable
inner_catchret:
; catchret exits the inner catchpad — back in the outer cleanup funclet
catchret from %inner_cp to label %outer_cleanupret
; propagate original exception
outer_cleanupret:
call void @end_cleanup() [ "funclet"(token %outer_pad) ]
cleanupret from %outer_pad unwind label %outer_catchswitch
; catch original exception
outer_catchswitch:
%outer_cs = catchswitch within none [label %outer_catchpad] unwind to caller
outer_catchpad:
%outer_cp = catchpad within %outer_cs [ptr null]
%exn2 = call ptr @llvm.wasm.get.exception(token %outer_cp)
%sel2 = call i32 @llvm.wasm.get.ehselector(token %outer_cp)
call void @do_catch(ptr %exn2, i32 1) [ "funclet"(token %outer_cp) ]
catchret from %outer_cp to label %done
done:
ret void
unreachable:
unreachable
}main.cpp
#include <stdexcept>
#include <stdio.h>
extern "C" void resume_unwind(int id) {
printf("resume_unwind %d\n", id);
throw std::runtime_error("panic");
}
extern "C" void do_catch(void* ptr, int id) {
printf("do_catch %d\n", id);
}
extern "C" void start_cleanup() {
printf("start cleanup\n");
}
extern "C" void end_cleanup() {
printf("end cleanup\n");
}
extern "C" void panic_in_cleanup() {
printf("panic_in_cleanup\n");
abort();
}
// Defined in the .ll file
extern "C" void catch_unwind_in_cleanup();
int main() {
catch_unwind_in_cleanup();
printf("returned successfully!\n");
return 0;
}run.sh
mkdir -p out
llc-20 \
-mtriple=wasm32-unknown-emscripten \
-exception-model=wasm \
-wasm-enable-eh \
-mattr=+exception-handling \
-filetype=obj \
wasm_eh_regression.ll \
-o out/wasm_eh_regression_llvm_20.o
llc-21 \
-mtriple=wasm32-unknown-emscripten \
-exception-model=wasm \
-wasm-enable-eh \
-mattr=+exception-handling \
-filetype=obj \
wasm_eh_regression.ll \
-o out/wasm_eh_regression_llvm_21.o
em++ -fwasm-exceptions -o out/test_llvm_20.js main.cpp out/wasm_eh_regression_llvm_20.o
em++ -fwasm-exceptions -o out/test_llvm_21.js main.cpp out/wasm_eh_regression_llvm_21.o
echo "llvm 20"
echo "--------"
node out/test_llvm_20.js
echo ""
echo ""
echo "llvm 21"
echo "--------"
node out/test_llvm_21.js
em++ --versionOutput:
Details
$ bash run.sh
llvm 20
--------
resume_unwind 1
start cleanup
resume_unwind 2
do_catch 2
end cleanup
do_catch 1
returned successfully!
llvm 21
--------
resume_unwind 1
start cleanup
resume_unwind 2
do_catch 2
end cleanup
panic_in_cleanup
Aborted(native code called abort())
wasm://wasm/0006d99e:1
RuntimeError: unreachable
at wasm://wasm/0006d99e:wasm-function[520]:0x17111
at abort (/home/hood/Documents/programming/tmp/llvm-wasm-eh-bug/out/test_llvm_21.js:587:5)
at __abort_js (/home/hood/Documents/programming/tmp/llvm-wasm-eh-bug/out/test_llvm_21.js:1053:7)
at wasm://wasm/0006d99e:wasm-function[16]:0x995
at wasm://wasm/0006d99e:wasm-function[12]:0x8a2
at wasm://wasm/0006d99e:wasm-function[15]:0x988
at wasm://wasm/0006d99e:wasm-function[13]:0x8c8
at wasm://wasm/0006d99e:wasm-function[14]:0x8f2
at /home/hood/Documents/programming/tmp/llvm-wasm-eh-bug/out/test_llvm_21.js:623:12
at callMain (/home/hood/Documents/programming/tmp/llvm-wasm-eh-bug/out/test_llvm_21.js:1747:15)
Node.js v24.14.0
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 5.0.3 (285c424dfa9e83b03cf8490c65ceadb7c45f28eb)Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
Type
Projects
Status
Needs Fix