Skip to content

Commit e20f5df

Browse files
aaronj0vgvassilev
authored andcommitted
Add llvm libunwind callback to suppress exceptions on apple silicon
See llvm/llvm-project#49036
1 parent 3ec1452 commit e20f5df

File tree

3 files changed

+79
-2
lines changed

3 files changed

+79
-2
lines changed

lib/Interpreter/Compatibility.h

+2
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,11 @@ static inline char* GetEnv(const char* Var_Name) {
7272
#include "llvm/ADT/SmallString.h"
7373
#include "llvm/ADT/StringRef.h"
7474
#include "llvm/ADT/Twine.h"
75+
#include "llvm/BinaryFormat/MachO.h"
7576
#include "llvm/Config/llvm-config.h"
7677
#include "llvm/ExecutionEngine/JITSymbol.h"
7778
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
79+
#include "llvm/Object/MachO.h"
7880
#include "llvm/Support/Casting.h"
7981
#include "llvm/Support/Path.h"
8082

lib/Interpreter/CppInterOp.cpp

+55-2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636

3737
#include <set>
3838
#include <sstream>
39+
#include <stack>
3940
#include <string>
4041

4142
// Stream redirect.
@@ -53,7 +54,43 @@
5354
#include <unistd.h>
5455
#endif // WIN32
5556

56-
#include <stack>
57+
#ifdef __APPLE__
58+
// Define a minimal mach header for JIT'd code, to support exceptions on osx 14
59+
// and later. See llvm/llvm-project#49036
60+
static llvm::MachO::mach_header_64 fake_mach_header = {
61+
.magic = llvm::MachO::MH_MAGIC_64,
62+
.cputype = llvm::MachO::CPU_TYPE_ARM64,
63+
.cpusubtype = llvm::MachO::CPU_SUBTYPE_ARM64_ALL,
64+
.filetype = llvm::MachO::MH_DYLIB,
65+
.ncmds = 0,
66+
.sizeofcmds = 0,
67+
.flags = 0,
68+
.reserved = 0};
69+
70+
// Declare libunwind SPI types and functions.
71+
struct unw_dynamic_unwind_sections {
72+
uintptr_t dso_base;
73+
uintptr_t dwarf_section;
74+
size_t dwarf_section_length;
75+
uintptr_t compact_unwind_section;
76+
size_t compact_unwind_section_length;
77+
};
78+
79+
int find_dynamic_unwind_sections(uintptr_t addr,
80+
unw_dynamic_unwind_sections* info) {
81+
info->dso_base = (uintptr_t)&fake_mach_header;
82+
info->dwarf_section = 0;
83+
info->dwarf_section_length = 0;
84+
info->compact_unwind_section = 0;
85+
info->compact_unwind_section_length = 0;
86+
return 1;
87+
}
88+
89+
// Typedef for callback above.
90+
typedef int (*unw_find_dynamic_unwind_sections)(
91+
uintptr_t addr, struct unw_dynamic_unwind_sections* info);
92+
93+
#endif // __APPLE__
5794

5895
namespace Cpp {
5996

@@ -70,7 +107,15 @@ namespace Cpp {
70107
// This might fix the issue https://reviews.llvm.org/D107087
71108
// FIXME: For now we just leak the Interpreter.
72109
struct InterpDeleter {
73-
~InterpDeleter() = default;
110+
~InterpDeleter() {
111+
#ifdef __APPLE__
112+
if (auto* unw_remove_find_dynamic_unwind_sections = (int (*)(
113+
unw_find_dynamic_unwind_sections find_dynamic_unwind_sections))
114+
dlsym(RTLD_DEFAULT, "__unw_remove_find_dynamic_unwind_sections"))
115+
unw_remove_find_dynamic_unwind_sections(find_dynamic_unwind_sections);
116+
#endif
117+
// sInterpreter.release();
118+
}
74119
} Deleter;
75120

76121
static compat::Interpreter& getInterp() {
@@ -2711,6 +2756,14 @@ namespace Cpp {
27112756
// FIXME: Enable this assert once we figure out how to fix the multiple
27122757
// calls to CreateInterpreter.
27132758
//assert(!sInterpreter && "Interpreter already set.");
2759+
#ifdef __APPLE__
2760+
// Add a handler to support exceptions from interpreted code.
2761+
// See llvm/llvm-project#49036
2762+
if (auto* unw_add_find_dynamic_unwind_sections = (int (*)(
2763+
unw_find_dynamic_unwind_sections find_dynamic_unwind_sections))
2764+
dlsym(RTLD_DEFAULT, "__unw_add_find_dynamic_unwind_sections"))
2765+
unw_add_find_dynamic_unwind_sections(find_dynamic_unwind_sections);
2766+
#endif // __APPLE__
27142767
sInterpreter = I;
27152768
return I;
27162769
}

unittests/CppInterOp/InterpreterTest.cpp

+22
Original file line numberDiff line numberDiff line change
@@ -210,3 +210,25 @@ TEST(InterpreterTest, ExternalInterpreterTest) {
210210
delete ExtInterp;
211211
#endif
212212
}
213+
214+
TEST(InterpreterTest, InterpreterExceptions) {
215+
Cpp::CreateInterpreter();
216+
EXPECT_TRUE(Cpp::Declare("int f() { throw 1; return 2; }") == 0);
217+
EXPECT_TRUE(
218+
Cpp::Process(
219+
"int ex() { try { f(); return 0; } catch(...){return 1;} }") == 0);
220+
EXPECT_EQ(Cpp::Evaluate("ex()"), 1)
221+
<< "Failed to catch exceptions in interpreter";
222+
}
223+
224+
TEST(InterpreterTest, InterpreterExceptionsCompiledCode) {
225+
Cpp::CreateInterpreter();
226+
bool caught = false;
227+
try {
228+
EXPECT_TRUE(Cpp::Declare("int f() { throw 1; return 2; }") == 0);
229+
EXPECT_TRUE(Cpp::Process("int res = f();") == 0);
230+
} catch (...) {
231+
caught = true;
232+
}
233+
EXPECT_TRUE(caught) << "Unable to catch exception coming from interpreter";
234+
}

0 commit comments

Comments
 (0)