Fix LLVM object loader exceptions.

This commit is contained in:
losfair
2019-08-22 18:57:26 -07:00
parent dcb16a2ae9
commit 613e4de9fc
3 changed files with 61 additions and 38 deletions

View File

@ -253,6 +253,7 @@ fn get_llvm_cxxflags() -> String {
.split(&[' ', '\n'][..]) .split(&[' ', '\n'][..])
.filter(|word| !word.starts_with("-W")) .filter(|word| !word.starts_with("-W"))
.filter(|word| word != &"-fno-exceptions") .filter(|word| word != &"-fno-exceptions")
.filter(|word| word != &"-fno-rtti")
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(" ") .join(" ")
} }

View File

@ -27,7 +27,7 @@ struct UnwindPoint {
UnwindPoint *prev; UnwindPoint *prev;
jmp_buf stack; jmp_buf stack;
std::function<void()> *f; std::function<void()> *f;
std::unique_ptr<std::exception> exception; std::unique_ptr<WasmException> exception;
}; };
static thread_local UnwindPoint *unwind_state = nullptr; static thread_local UnwindPoint *unwind_state = nullptr;
@ -47,11 +47,11 @@ void catch_unwind(std::function<void()> &&f) {
unwind_state = current.prev; unwind_state = current.prev;
if (current.exception) { if (current.exception) {
throw *current.exception; throw std::move(current.exception);
} }
} }
void unsafe_unwind(std::exception *exception) { void unsafe_unwind(WasmException *exception) {
UnwindPoint *state = unwind_state; UnwindPoint *state = unwind_state;
if (state) { if (state) {
state->exception.reset(exception); state->exception.reset(exception);

View File

@ -5,6 +5,7 @@
#include <exception> #include <exception>
#include <functional> #include <functional>
#include <iostream> #include <iostream>
#include <memory>
#include <setjmp.h> #include <setjmp.h>
#include <sstream> #include <sstream>
@ -52,6 +53,17 @@ typedef struct {
size_t data, vtable; size_t data, vtable;
} box_any_t; } box_any_t;
enum WasmTrapType {
Unreachable = 0,
IncorrectCallIndirectSignature = 1,
MemoryOutOfBounds = 2,
CallIndirectOOB = 3,
IllegalArithmetic = 4,
Unknown,
};
extern "C" void callback_trampoline(void *, void *);
struct MemoryManager : llvm::RuntimeDyld::MemoryManager { struct MemoryManager : llvm::RuntimeDyld::MemoryManager {
public: public:
MemoryManager(callbacks_t callbacks) : callbacks(callbacks) {} MemoryManager(callbacks_t callbacks) : callbacks(callbacks) {}
@ -106,13 +118,26 @@ private:
size_t stack_map_size = 0; size_t stack_map_size = 0;
}; };
struct WasmErrorSink {
WasmTrapType *trap_out;
box_any_t *user_error;
};
struct WasmException : std::exception { struct WasmException : std::exception {
public: public:
virtual std::string description() const noexcept = 0; virtual std::string description() const noexcept { return "unknown"; }
virtual const char *what() const noexcept override {
return "wasm exception";
}
virtual void write_error(WasmErrorSink &out) const noexcept {
*out.trap_out = WasmTrapType::Unknown;
}
}; };
void catch_unwind(std::function<void()> &&f); void catch_unwind(std::function<void()> &&f);
[[noreturn]] void unsafe_unwind(std::exception *exception); [[noreturn]] void unsafe_unwind(WasmException *exception);
struct UncatchableException : WasmException { struct UncatchableException : WasmException {
public: public:
@ -131,6 +156,10 @@ public:
// The parts of a `Box<dyn Any>`. // The parts of a `Box<dyn Any>`.
box_any_t error_data; box_any_t error_data;
virtual void write_error(WasmErrorSink &out) const noexcept override {
*out.user_error = error_data;
}
}; };
struct BreakpointException : UncatchableException { struct BreakpointException : UncatchableException {
@ -142,6 +171,11 @@ public:
} }
uintptr_t callback; uintptr_t callback;
virtual void write_error(WasmErrorSink &out) const noexcept override {
puts("CB TRAMPOLINE");
callback_trampoline(out.user_error, (void *)callback);
}
}; };
struct WasmModule { struct WasmModule {
@ -165,16 +199,7 @@ private:
struct WasmTrap : UncatchableException { struct WasmTrap : UncatchableException {
public: public:
enum Type { WasmTrap(WasmTrapType type) : type(type) {}
Unreachable = 0,
IncorrectCallIndirectSignature = 1,
MemoryOutOfBounds = 2,
CallIndirectOOB = 3,
IllegalArithmetic = 4,
Unknown,
};
WasmTrap(Type type) : type(type) {}
virtual std::string description() const noexcept override { virtual std::string description() const noexcept override {
std::ostringstream ss; std::ostringstream ss;
@ -183,27 +208,31 @@ public:
return ss.str(); return ss.str();
} }
Type type; WasmTrapType type;
virtual void write_error(WasmErrorSink &out) const noexcept override {
*out.trap_out = type;
}
private: private:
friend std::ostream &operator<<(std::ostream &out, const Type &ty) { friend std::ostream &operator<<(std::ostream &out, const WasmTrapType &ty) {
switch (ty) { switch (ty) {
case Type::Unreachable: case WasmTrapType::Unreachable:
out << "unreachable"; out << "unreachable";
break; break;
case Type::IncorrectCallIndirectSignature: case WasmTrapType::IncorrectCallIndirectSignature:
out << "incorrect call_indirect signature"; out << "incorrect call_indirect signature";
break; break;
case Type::MemoryOutOfBounds: case WasmTrapType::MemoryOutOfBounds:
out << "memory access out-of-bounds"; out << "memory access out-of-bounds";
break; break;
case Type::CallIndirectOOB: case WasmTrapType::CallIndirectOOB:
out << "call_indirect out-of-bounds"; out << "call_indirect out-of-bounds";
break; break;
case Type::IllegalArithmetic: case WasmTrapType::IllegalArithmetic:
out << "illegal arithmetic operation"; out << "illegal arithmetic operation";
break; break;
case Type::Unknown: case WasmTrapType::Unknown:
default: default:
out << "unknown"; out << "unknown";
break; break;
@ -226,7 +255,6 @@ public:
}; };
extern "C" { extern "C" {
void callback_trampoline(void *, void *);
result_t module_load(const uint8_t *mem_ptr, size_t mem_size, result_t module_load(const uint8_t *mem_ptr, size_t mem_size,
callbacks_t callbacks, WasmModule **module_out) { callbacks_t callbacks, WasmModule **module_out) {
@ -239,7 +267,7 @@ result_t module_load(const uint8_t *mem_ptr, size_t mem_size,
return RESULT_OK; return RESULT_OK;
} }
[[noreturn]] void throw_trap(WasmTrap::Type ty) { [[noreturn]] void throw_trap(WasmTrapType ty) {
unsafe_unwind(new WasmTrap(ty)); unsafe_unwind(new WasmTrap(ty));
} }
@ -258,27 +286,21 @@ void module_delete(WasmModule *module) { delete module; }
} }
bool invoke_trampoline(trampoline_t trampoline, void *ctx, void *func, bool invoke_trampoline(trampoline_t trampoline, void *ctx, void *func,
void *params, void *results, WasmTrap::Type *trap_out, void *params, void *results, WasmTrapType *trap_out,
box_any_t *user_error, void *invoke_env) noexcept { box_any_t *user_error, void *invoke_env) noexcept {
try { try {
catch_unwind([trampoline, ctx, func, params, results]() { catch_unwind([trampoline, ctx, func, params, results]() {
trampoline(ctx, func, params, results); trampoline(ctx, func, params, results);
}); });
return true; return true;
} catch (const WasmTrap &e) { } catch (std::unique_ptr<WasmException> &e) {
*trap_out = e.type; WasmErrorSink sink;
return false; sink.trap_out = trap_out;
} catch (const UserException &e) { sink.user_error = user_error;
*user_error = e.error_data; e->write_error(sink);
return false;
} catch (const BreakpointException &e) {
callback_trampoline(user_error, (void *)e.callback);
return false;
} catch (const WasmException &e) {
*trap_out = WasmTrap::Type::Unknown;
return false; return false;
} catch (...) { } catch (...) {
*trap_out = WasmTrap::Type::Unknown; *trap_out = WasmTrapType::Unknown;
return false; return false;
} }
} }