[LLVMdev] Throwing an exception from JITed code, and catching in C++

Vapor Nide vaporanide at live.com
Wed Dec 26 16:25:06 PST 2012



Hi everyone,

I am writing an application that uses LLVM JIT and I would like to throw an exception from the JIT and catch it in the C++ code that invokes the JIT.
This does not seem to work.
I've written what is hopefully a super simple demonstration to reproduce this.
I would appreciate any help with this.

Thank you

The demonstration is composed of:
1) thrower.cpp - a source file that contains a single function, throwInt(), that throws an int. This is compiled to thrower.s with clang and then to thrower.s.bc with llvm-as.
2) catcher.cpp - a source file that contains a main() that JITs thrower.s.bc and then calls throwInt(). This is compiled using g++.

When I run catcher it just prints this:
terminate called after throwing an instance of 'int'

I am using LLVM and CLANG 3.0, and gcc 4.7.2.

Here are all of the files needed to reproduce this:
1) thrower.cpp
2) catcher.cpp
3) Makefile

This is how I run the test:
make LLVM_BIN=path/to/llvm-3.0.src/Release/bin/

$ cat thrower.cpp ################
void throwInt()
{
    throw 1;
}

$ cat thrower.s ################
; ModuleID = 'thrower.cpp'
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

@_ZTIi = external constant i8*

define void @_Z8throwIntv() uwtable {
  %1 = call i8* @__cxa_allocate_exception(i64 4) nounwind
  %2 = bitcast i8* %1 to i32*
  store i32 1, i32* %2
  call void @__cxa_throw(i8* %1, i8* bitcast (i8** @_ZTIi to i8*), i8* null) noreturn
  unreachable
                                                  ; No predecessors!
  ret void
}

declare i8* @__cxa_allocate_exception(i64)

declare void @__cxa_throw(i8*, i8*, i8*)

$ cat catcher.cpp ################
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/Support/IRReader.h"
#include "llvm/Support/TargetSelect.h"
#include

using namespace llvm;

int main(int, char**)
{
    LLVMContext& context = getGlobalContext();
    InitializeNativeTarget();
    SMDiagnostic error;
    Module* m = ParseIRFile("./thrower.s.bc", error, context);
    if (!m)
    {
        printf("could not load module\n");
        return 1;
    }

    ExecutionEngine* ee = ExecutionEngine::create(m);
    if (!ee)
    {
        printf("could not create execution engine\n");
        return 1;
    }

    Function* throwsIntFunction = ee->FindFunctionNamed("_Z8throwIntv");
    if (!throwsIntFunction)
    {
        printf("could not find function\n");
        return 1;
    }

    typedef void (*throwsIntType)();
    throwsIntType throwsInt = reinterpret_cast(ee->getPointerToFunction(throwsIntFunction));
    if (!throwsInt)
    {
        printf("could not get pointer to function\n");
        return 1;
    }

    try
    {
        throwsInt();
    }
    catch (int ex)
    {
        printf("caught an int\n");
    }
}

$ cat Makefile ################
LLVM_CXX_FLAGS=$(shell $(LLVM_BIN)/llvm-config --cxxflags)
LLVM_LIBS=$(shell $(LLVM_BIN)/llvm-config --libs)
LLVM_LD_FLAGS=$(shell $(LLVM_BIN)/llvm-config --ldflags)

all : tested

.PHONY: clean
clean:
    rm thrower.s thrower.s.bc catcher tested

thrower.s : thrower.cpp Makefile
    $(LLVM_BIN)/clang -S -emit-llvm thrower.cpp

thrower.s.bc : thrower.s Makefile
    $(LLVM_BIN)/llvm-as thrower.s

catcher : catcher.cpp Makefile
    g++ -g catcher.cpp -o catcher $(LLVM_CXX_FLAGS) $(LLVM_LIBS) $(LLVM_LD_FLAGS) -Wno-cast-qual -fexceptions -O0

tested : thrower.s.bc catcher Makefile
    ./catcher
    touch tested

 		 	   		  



More information about the llvm-dev mailing list