Skip to content

Commit 3a6db23

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

File tree

3 files changed

+79
-1
lines changed

3 files changed

+79
-1
lines changed

lib/Interpreter/Compatibility.h

+2
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@
2323
#include "llvm/ADT/SmallString.h"
2424
#include "llvm/ADT/StringRef.h"
2525
#include "llvm/ADT/Twine.h"
26+
#include "llvm/BinaryFormat/MachO.h"
2627
#include "llvm/Config/llvm-config.h"
2728
#include "llvm/ExecutionEngine/JITSymbol.h"
2829
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
30+
#include "llvm/Object/MachO.h"
2931
#include "llvm/Support/Casting.h"
3032
#include "llvm/Support/Path.h"
3133

lib/Interpreter/CppInterOp.cpp

+55-1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,44 @@
4949
#include <unistd.h>
5050
#endif // WIN32
5151

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

5492
using namespace clang;
@@ -62,7 +100,15 @@ namespace Cpp {
62100
// This might fix the issue https://reviews.llvm.org/D107087
63101
// FIXME: For now we just leak the Interpreter.
64102
struct InterpDeleter {
65-
~InterpDeleter() { sInterpreter.release(); }
103+
~InterpDeleter() {
104+
#ifdef __APPLE__
105+
if (auto* unw_remove_find_dynamic_unwind_sections = (int (*)(
106+
unw_find_dynamic_unwind_sections find_dynamic_unwind_sections))
107+
dlsym(RTLD_DEFAULT, "__unw_remove_find_dynamic_unwind_sections"))
108+
unw_remove_find_dynamic_unwind_sections(find_dynamic_unwind_sections);
109+
#endif
110+
sInterpreter.release();
111+
}
66112
} Deleter;
67113

68114
static compat::Interpreter& getInterp() {
@@ -2612,6 +2658,14 @@ namespace Cpp {
26122658
// FIXME: Enable this assert once we figure out how to fix the multiple
26132659
// calls to CreateInterpreter.
26142660
//assert(!sInterpreter && "Interpreter already set.");
2661+
#ifdef __APPLE__
2662+
// Add a handler to support exceptions from interpreted code.
2663+
// See llvm/llvm-project#49036
2664+
if (auto* unw_add_find_dynamic_unwind_sections = (int (*)(
2665+
unw_find_dynamic_unwind_sections find_dynamic_unwind_sections))
2666+
dlsym(RTLD_DEFAULT, "__unw_add_find_dynamic_unwind_sections"))
2667+
unw_add_find_dynamic_unwind_sections(find_dynamic_unwind_sections);
2668+
#endif // __APPLE__
26152669
sInterpreter.reset(I);
26162670
return I;
26172671
}

unittests/CppInterOp/InterpreterTest.cpp

+22
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,25 @@ TEST(InterpreterTest, CodeCompletion) {
132132
GTEST_SKIP();
133133
#endif
134134
}
135+
136+
TEST(InterpreterTest, InterpreterExceptions) {
137+
Cpp::CreateInterpreter();
138+
EXPECT_TRUE(Cpp::Declare("int f() { throw 1; return 2; }") == 0);
139+
EXPECT_TRUE(
140+
Cpp::Process(
141+
"int ex() { try { f(); return 0; } catch(...){return 1;} }") == 0);
142+
EXPECT_EQ(Cpp::Evaluate("ex()"), 1)
143+
<< "Failed to catch exceptions in interpreter";
144+
}
145+
146+
TEST(InterpreterTest, InterpreterExceptionsCompiledCode) {
147+
Cpp::CreateInterpreter();
148+
bool caught = false;
149+
try {
150+
EXPECT_TRUE(Cpp::Declare("int f() { throw 1; return 2; }") == 0);
151+
EXPECT_TRUE(Cpp::Process("int res = f();") == 0);
152+
} catch (...) {
153+
caught = true;
154+
}
155+
EXPECT_TRUE(caught) << "Unable to catch exception coming from interpreter";
156+
}

0 commit comments

Comments
 (0)