Skip to content

Commit 6c08649

Browse files
aaronj0mcbarton
authored andcommitted
Add llvm libunwind callback to suppress exceptions on apple silicon
See llvm/llvm-project#49036
1 parent ef2f0a1 commit 6c08649

File tree

3 files changed

+79
-2
lines changed

3 files changed

+79
-2
lines changed

lib/Interpreter/Compatibility.h

Lines changed: 2 additions & 0 deletions
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

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737

3838
#include <set>
3939
#include <sstream>
40+
#include <stack>
4041
#include <string>
4142

4243
// Stream redirect.
@@ -54,7 +55,43 @@
5455
#include <unistd.h>
5556
#endif // WIN32
5657

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

5996
namespace Cpp {
6097

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

77122
static compat::Interpreter& getInterp() {
@@ -2716,6 +2761,14 @@ namespace Cpp {
27162761
// FIXME: Enable this assert once we figure out how to fix the multiple
27172762
// calls to CreateInterpreter.
27182763
//assert(!sInterpreter && "Interpreter already set.");
2764+
#ifdef __APPLE__
2765+
// Add a handler to support exceptions from interpreted code.
2766+
// See llvm/llvm-project#49036
2767+
if (auto* unw_add_find_dynamic_unwind_sections = (int (*)(
2768+
unw_find_dynamic_unwind_sections find_dynamic_unwind_sections))
2769+
dlsym(RTLD_DEFAULT, "__unw_add_find_dynamic_unwind_sections"))
2770+
unw_add_find_dynamic_unwind_sections(find_dynamic_unwind_sections);
2771+
#endif // __APPLE__
27192772
sInterpreter = I;
27202773
return I;
27212774
}

unittests/CppInterOp/InterpreterTest.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,3 +230,25 @@ if (llvm::sys::RunningOnValgrind())
230230
delete ExtInterp;
231231
#endif
232232
}
233+
234+
TEST(InterpreterTest, InterpreterExceptions) {
235+
Cpp::CreateInterpreter();
236+
EXPECT_TRUE(Cpp::Declare("int f() { throw 1; return 2; }") == 0);
237+
EXPECT_TRUE(
238+
Cpp::Process(
239+
"int ex() { try { f(); return 0; } catch(...){return 1;} }") == 0);
240+
EXPECT_EQ(Cpp::Evaluate("ex()"), 1)
241+
<< "Failed to catch exceptions in interpreter";
242+
}
243+
244+
TEST(InterpreterTest, InterpreterExceptionsCompiledCode) {
245+
Cpp::CreateInterpreter();
246+
bool caught = false;
247+
try {
248+
EXPECT_TRUE(Cpp::Declare("int f() { throw 1; return 2; }") == 0);
249+
EXPECT_TRUE(Cpp::Process("int res = f();") == 0);
250+
} catch (...) {
251+
caught = true;
252+
}
253+
EXPECT_TRUE(caught) << "Unable to catch exception coming from interpreter";
254+
}

0 commit comments

Comments
 (0)