Issue |
126365
|
Summary |
Clang Interpreter (clang::IncrementalCompilerBuilder) Crashes on MinGW-w64 When Executing Exception-Throwing IR Function
|
Labels |
clang
|
Assignees |
|
Reporter |
ikappaki
|
Hi,
I'm debugging an issue on MinGW-w64 in a project that uses `clang::IncrementalCompilerBuilder`. The problem occurs when calling an IR function that throws an exception, causing the program to crash.
Could this be an issue with calling an exception-throwing function from an IR module using `clang::IncrementalCompilerBuilder` on `MinGW-w64`? Or is it perhaps that am I missing something in my setup?
I was able to reproduce the issue in a minimal example outside the project:
- The crash does not occur when using `llvm::ExecutionEngine`.
- The issue only happens on Windows (`MinGW-w64`) and not on Linux.
```
$ clang --version
clang version 19.1.6
Target: x86_64-w64-windows-gnu
Thread model: posix
InstalledDir: D:/local/msys64/clang64/bin
```
To reproduce,
1. install the `msys2` development environment locally,
2. Open up the MSYS2 CLANG64 Shell
3. Install clang:
```shell
pacman -S clang64/mingw-w64-clang-x86_64-clang
```
4. Compile the program
```shell
clang++ -o issue issue.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core` -g -Wl,--export-all-symbols -fexceptions -lclang-cpp
```
5. Run the program. Observe the difference between the two execution methods:
- `:EXECUTION-ENGINE` works fine, catches the exception
- `:INTERPRETER` crashes when exception is thrown
```shell
$ ./issue.exe
:EXECUTION-ENGINE
; ModuleID = 'direct-module'
source_filename = "direct-module"
target triple = "x86_64-w64-windows-gnu"
declare void @exception_throw()
define void @wrapper() {
entry:
call void @exception_throw()
ret void
}
:wrapper-calling...
:throwing-exception...
:exception-caught
:done
:INTERPRETER
; ModuleID = 'interpreter-module'
source_filename = "interpreter-module"
target triple = "x86_64-w64-windows-gnu"
declare void @exception_throw()
define void @wrapper() {
entry:
call void @exception_throw()
ret void
}
:wrapper-calling...
:throwing-exception...
;;; <program crashed>
```
Debugger trace:
```sh
$ lldb issue
(lldb) target create "issue"
Current executable set to 'issue.exe' (x86_64).
(lldb) run
(lldb) Process 49264 launched: 'issue.exe' (x86_64)
Process 49264 stopped
* thread #1, stop reason = Exception 0x20474343 encountered at address 0x7ffd04c2fb4c
frame #0: 0x00007ffd04c2fb4c KernelBase.dll`RaiseException + 108
KernelBase.dll`RaiseException:
-> 0x7ffd04c2fb4c <+108>: nopl (%rax,%rax)
0x7ffd04c2fb51 <+113>: movq 0xc0(%rsp), %rcx
0x7ffd04c2fb59 <+121>: xorq %rsp, %rcx
0x7ffd04c2fb5c <+124>: callq 0x7ffd04c80a40 ; SetProtectedPolicy + 112
(lldb) bt
* thread #1, stop reason = Exception 0x20474343 encountered at address 0x7ffd04c2fb4c
* frame #0: 0x00007ffd04c2fb4c KernelBase.dll`RaiseException + 108
frame #1: 0x00007ffc59ad2bf0 libc++.dll`_Unwind_RaiseException + 128
frame #2: 0x00007ffc59af70aa libc++.dll`__cxa_throw + 58
frame #3: 0x00007ff616ce13ff issue.exe`::exception_throw() at issue.cpp:19:5
frame #4: 0x000001bdb2e10010
frame #5: 0x00007ff616ce133c issue.exe`__tmainCRTStartup at crtexe.c:266:15
frame #6: 0x00007ff616ce1396 issue.exe`mainCRTStartup at crtexe.c:186:9
frame #7: 0x00007ffd0639259d kernel32.dll`BaseThreadInitThunk + 29
frame #8: 0x00007ffd078eaf38 ntdll.dll`RtlUserThreadStart + 40
(lldb)
```
On Linux, compiling and running the same program does not cause a crash:
```sh
$ clang --version
clang version 19.1.5
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /nix/store/wrkvgny73b9lbjbkvm21k34kqnj4qsrn-clang-19.1.5/bin
$ clang++ -o issue issue.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core` -g -fexceptions -lclang-cpp -Xlinker -export-dynamic
$ ./issue
:EXECUTION-ENGINE
; ModuleID = 'direct-module'
source_filename = "direct-module"
target triple = "x86_64-unknown-linux-gnu"
declare void @exception_throw()
define void @wrapper() {
entry:
call void @exception_throw()
ret void
}
:wrapper-calling...
:throwing-exception...
:exception-caught
:done
:INTERPRETER
; ModuleID = 'interpreter-module'
source_filename = "interpreter-module"
target triple = "x86_64-unknown-linux-gnu"
declare void @exception_throw()
define void @wrapper() {
entry:
call void @exception_throw()
ret void
}
:wrapper-calling...
:throwing-exception...
:exception-caught
:done
```
The full source code demonstrating the issue is below. It defines an IR module where a function `exception_throw()` throws an exception. The function is executed both via `llvm::ExecutionEngine` (which catches the exception) and `clang::Interpreter` (which crashes).
`issue.cpp`
```c++
#include <clang/Interpreter/Interpreter.h>
#include <clang/Frontend/CompilerInstance.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/ExecutionEngine/GenericValue.h>
#include <llvm/ExecutionEngine/Orc/LLJIT.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/IRBuilder.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/TargetParser/Host.h>
#include <iostream>
extern "C" {
void exception_throw() {
std::cout << ":throwing-exception...\n";
throw "issue";
}
}
std::unique_ptr<llvm::Module> moduleMake(llvm::LLVMContext& context, const std::string& moduleName) {
std::unique_ptr<llvm::Module> module = std::make_unique<llvm::Module>(moduleName, context);
llvm::IRBuilder<> builder(context);
module->setTargetTriple(llvm::sys::getDefaultTargetTriple());
auto const voidFnType(llvm::FunctionType::get(builder.getVoidTy(), {}, false));
auto excThrowFn(module->getOrInsertFunction("exception_throw", voidFnType));
auto excThrowFunc = llvm::cast<llvm::Function>(excThrowFn.getCallee());
llvm::Function *wrapperFunc = llvm::Function::Create(voidFnType, llvm::Function::ExternalLinkage, "wrapper", *module);
llvm::BasicBlock *wrapperBB = llvm::BasicBlock::Create(context, "entry", wrapperFunc);
builder.SetInsertPoint(wrapperBB);
builder.CreateCall(excThrowFunc);
builder.CreateRetVoid();
module->print(llvm::errs(), nullptr);
return module;
}
void runInterpreter() {
std::cout << "\n\n:INTERPRETER\n\n";
std::unique_ptr<llvm::LLVMContext> context = std::make_unique<llvm::LLVMContext>();
std::unique_ptr<llvm::Module> module = moduleMake(*context, "interpreter-module");
clang::IncrementalCompilerBuilder compilerBuilder;
std::vector<char const *> args{};
// std::vector<char const *> args{"-fexception", "-funwind-tables", "-g" "-lclang-cpp"};
// compilerBuilder.SetCompilerArgs(args);
std::unique_ptr<clang::CompilerInstance> compilerInstance(llvm::cantFail(compilerBuilder.CreateCpp()));
compilerInstance->LoadRequestedPlugins();
std::unique_ptr<clang::Interpreter> interpreter =
llvm::cantFail(clang::Interpreter::create(std::move(compilerInstance)));
llvm::orc::LLJIT& jit(interpreter->getExecutionEngine().get());
llvm::cantFail(jit.addIRModule(llvm::orc::ThreadSafeModule{ std::move(module), std::move(context) }));
llvm::cantFail(jit.initialize(jit.getMainJITDylib()));
auto sym = jit.lookup("wrapper");
auto funcPtr = sym->toPtr<void(*)()>();
assert(funcPtr);
try {
std::cout << ":wrapper-calling...\n";
funcPtr();
}
catch(...) {
std::cout << ":exception-caught\n";
}
std::cout << ":done\n";
}
void runExecutionEngine() {
std::cout << "\n\n:EXECUTION-ENGINE\n\n";
llvm::LLVMContext context;
std::unique_ptr<llvm::Module> module = moduleMake(context, "direct-module");
std::string errStr;
llvm::ExecutionEngine *engine = llvm::EngineBuilder(std::move(module)).setErrorStr(&errStr).create();
if (!engine) {
std::cerr << "Error: " << errStr << std::endl;
return;
}
llvm::Function* wrapperFunc = engine->FindFunctionNamed("wrapper");
assert(wrapperFunc);
std::vector<llvm::GenericValue> noArgs;
try {
std::cout << ":wrapper-calling...\n";
engine->runFunction(wrapperFunc, noArgs);
}
catch (...) {
std::cout << ":exception-caught\n";
}
std::cout << ":done\n";
}
int main() {
llvm::InitializeNativeTarget();
llvm::InitializeNativeTargetAsmPrinter();
runExecutionEngine();
runInterpreter();
return 0;
}
```
Thanks
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs