How to properly use exceptions with LLVM JIT?

Going through the llvm tutorial I implemented JIT and found that my REPL crashes unexpectedly with segfault. The debugger shows that the statement call invokes this segfault. But a crash occurs only if some code was compiled with JIT before an exception is thrown. The code from this answer with some changes can be used to reproduce the problem:

#include <string> #include <vector> #include <iostream> #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Verifier.h" #include "llvm/ADT/iterator_range.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/ExecutionEngine/RTDyldMemoryManager.h" #include "llvm/ExecutionEngine/RuntimeDyld.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/ExecutionEngine/Orc/CompileUtils.h" #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" #include "llvm/ExecutionEngine/Orc/LambdaResolver.h" #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" #include "llvm/ExecutionEngine/JITSymbol.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Mangler.h" #include "llvm/Support/DynamicLibrary.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/TargetSelect.h" using namespace llvm; typedef orc::ObjectLinkingLayer<> ObjLayerT; typedef orc::IRCompileLayer<ObjLayerT> CompileLayerT; static LLVMContext Context; static auto MyModule = make_unique<Module>("my compiler", Context); Function *createFunc(IRBuilder<> &Builder, std::string Name) { std::vector<Type*> Integers(2, Builder.getInt32Ty()); auto *funcType = FunctionType::get(Builder.getInt32Ty(), Integers, false); auto *fooFunc = Function::Create(funcType, Function::ExternalLinkage, Name, MyModule.get()); return fooFunc; }; void updateBody(Function *fooFunc, IRBuilder<> &Builder) { auto *entry = BasicBlock::Create(Context, "entry", fooFunc); Builder.SetInsertPoint(entry); auto args = fooFunc->arg_begin(); Value *arg1 = &(*args); args = std::next(args); Value *arg2 = &(*args); auto *sum = Builder.CreateAdd(arg1, arg2, "tmp"); Builder.CreateRet(sum); }; int main(int argc, char* argv[]) { // Prepare the module static IRBuilder<> Builder(Context); auto *fooFunc = createFunc(Builder, "sum"); updateBody(fooFunc, Builder); verifyFunction(*fooFunc); // Initilaze native target InitializeNativeTarget(); InitializeNativeTargetAsmPrinter(); InitializeNativeTargetAsmParser(); // Prepare jit layer ObjLayerT ObjectLayer; std::unique_ptr<TargetMachine> TM(EngineBuilder().selectTarget()); DataLayout DL(TM->createDataLayout()); CompileLayerT CompileLayer(ObjectLayer, orc::SimpleCompiler(*TM)); auto Resolver = orc::createLambdaResolver( [&](const std::string &Name) { if (auto Sym = CompileLayer.findSymbol(Name, false)) return Sym; return JITSymbol(nullptr); }, [](const std::string &S) { return nullptr; } ); // Add MyModule to the jit layer std::vector<std::unique_ptr<Module>> Modules; Modules.push_back(std::move(MyModule)); auto handle = CompileLayer.addModuleSet(std::move(Modules), make_unique<SectionMemoryManager>(), std::move(Resolver)); // Retrieve the foo symbol std::string MangledName; raw_string_ostream MangledNameStream(MangledName); Mangler::getNameWithPrefix(MangledNameStream, "sum", DL); auto Sym = CompileLayer.findSymbol(MangledNameStream.str(), true); // Cast to function auto func = (int(*)(int, int))Sym.getAddress(); // Try it std::cout << func(5, 7) << std::endl; CompileLayer.removeModuleSet(handle); try { throw std::runtime_error("Whoops!"); } catch (const std::runtime_error& e) { std::cout << "Exception: " << e.what() << '\n'; } return 0; } 

Compiled with

 $ clang++ -std=c++11 -lLLVM code.cpp -o jittest 

Provides the following result:

 $ ./jittest 12 Segmentation fault (core dumped) 
+5
source share

Source: https://habr.com/ru/post/1267195/


All Articles