Skip to content

Clang Interpreter (clang::IncrementalCompilerBuilder) Crashes on MinGW-w64 When Executing Exception-Throwing IR Function #126365

Open
@ikappaki

Description

@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:
pacman -S clang64/mingw-w64-clang-x86_64-clang
  1. Compile the issue.cpp program posted at the end of the issue
clang++ -o issue issue.cpp `llvm-config --cxxflags --ldflags --system-libs --libs core` -g -Wl,--export-all-symbols -fexceptions -lclang-cpp
  1. Run the program. Observe the difference between the two execution methods:
  • :EXECUTION-ENGINE works fine, catches the exception
  • :INTERPRETER crashes when exception is thrown
$ ./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:

$ 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:

$ 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

#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

Metadata

Metadata

Assignees

No one assigned

    Labels

    clang-tools-extracrashPrefer [crash-on-valid] or [crash-on-invalid]

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions