Skip to content

Commit c0db33d

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

File tree

3 files changed

+81
-1
lines changed

3 files changed

+81
-1
lines changed

lib/CppInterOp/Compatibility.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,11 @@ static inline char* GetEnv(const char* Var_Name) {
7171
#include "llvm/ADT/SmallString.h"
7272
#include "llvm/ADT/StringRef.h"
7373
#include "llvm/ADT/Twine.h"
74+
#include "llvm/BinaryFormat/MachO.h"
7475
#include "llvm/Config/llvm-config.h"
7576
#include "llvm/ExecutionEngine/JITSymbol.h"
7677
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
78+
#include "llvm/Object/MachO.h"
7779
#include "llvm/Support/Casting.h"
7880
#include "llvm/Support/Path.h"
7981

lib/CppInterOp/CppInterOp.cpp

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,44 @@
7373

7474
#include <stack>
7575

76+
#ifdef __APPLE__
77+
// Define a minimal mach header for JIT'd code, to support exceptions on osx 14
78+
// and later. See llvm/llvm-project#49036
79+
static llvm::MachO::mach_header_64 fake_mach_header = {
80+
.magic = llvm::MachO::MH_MAGIC_64,
81+
.cputype = llvm::MachO::CPU_TYPE_ARM64,
82+
.cpusubtype = llvm::MachO::CPU_SUBTYPE_ARM64_ALL,
83+
.filetype = llvm::MachO::MH_DYLIB,
84+
.ncmds = 0,
85+
.sizeofcmds = 0,
86+
.flags = 0,
87+
.reserved = 0};
88+
89+
// Declare libunwind SPI types and functions.
90+
struct unw_dynamic_unwind_sections {
91+
uintptr_t dso_base;
92+
uintptr_t dwarf_section;
93+
size_t dwarf_section_length;
94+
uintptr_t compact_unwind_section;
95+
size_t compact_unwind_section_length;
96+
};
97+
98+
int find_dynamic_unwind_sections(uintptr_t addr,
99+
unw_dynamic_unwind_sections* info) {
100+
info->dso_base = (uintptr_t)&fake_mach_header;
101+
info->dwarf_section = 0;
102+
info->dwarf_section_length = 0;
103+
info->compact_unwind_section = 0;
104+
info->compact_unwind_section_length = 0;
105+
return 1;
106+
}
107+
108+
// Typedef for callback above.
109+
typedef int (*unw_find_dynamic_unwind_sections)(
110+
uintptr_t addr, struct unw_dynamic_unwind_sections* info);
111+
112+
#endif // __APPLE__
113+
76114
namespace Cpp {
77115

78116
using namespace clang;
@@ -88,7 +126,15 @@ static compat::Interpreter* sInterpreter = nullptr;
88126
// This might fix the issue https://reviews.llvm.org/D107087
89127
// FIXME: For now we just leak the Interpreter.
90128
struct InterpDeleter {
91-
~InterpDeleter() = default;
129+
~InterpDeleter() {
130+
#ifdef __APPLE__
131+
if (auto* unw_remove_find_dynamic_unwind_sections = (int (*)(
132+
unw_find_dynamic_unwind_sections find_dynamic_unwind_sections))
133+
dlsym(RTLD_DEFAULT, "__unw_remove_find_dynamic_unwind_sections"))
134+
unw_remove_find_dynamic_unwind_sections(find_dynamic_unwind_sections);
135+
#endif
136+
// sInterpreter.release();
137+
}
92138
} Deleter;
93139

94140
static compat::Interpreter& getInterp() {
@@ -2865,6 +2911,8 @@ TInterp_t CreateInterpreter(const std::vector<const char*>& Args /*={}*/,
28652911
#ifdef _WIN32
28662912
// FIXME : Workaround Sema::PushDeclContext assert on windows
28672913
ClingArgv.push_back("-fno-delayed-template-parsing");
2914+
#elif __APPLE__
2915+
ClingArgv.push_back("-fforce-dwarf-frame");
28682916
#endif
28692917
ClingArgv.insert(ClingArgv.end(), Args.begin(), Args.end());
28702918
// To keep the Interpreter creation interface between cling and clang-repl
@@ -2923,6 +2971,14 @@ TInterp_t CreateInterpreter(const std::vector<const char*>& Args /*={}*/,
29232971
// FIXME: Enable this assert once we figure out how to fix the multiple
29242972
// calls to CreateInterpreter.
29252973
// assert(!sInterpreter && "Interpreter already set.");
2974+
#ifdef __APPLE__
2975+
// Add a handler to support exceptions from interpreted code.
2976+
// See llvm/llvm-project#49036
2977+
if (auto* unw_add_find_dynamic_unwind_sections = (int (*)(
2978+
unw_find_dynamic_unwind_sections find_dynamic_unwind_sections))
2979+
dlsym(RTLD_DEFAULT, "__unw_add_find_dynamic_unwind_sections"))
2980+
unw_add_find_dynamic_unwind_sections(find_dynamic_unwind_sections);
2981+
#endif // __APPLE__
29262982
sInterpreter = I;
29272983
return I;
29282984
}

unittests/CppInterOp/InterpreterTest.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,3 +311,25 @@ if (llvm::sys::RunningOnValgrind())
311311
delete ExtInterp;
312312
#endif
313313
}
314+
315+
TEST(InterpreterTest, InterpreterExceptions) {
316+
Cpp::CreateInterpreter();
317+
EXPECT_TRUE(Cpp::Declare("int f() { throw 1; return 2; }") == 0);
318+
EXPECT_TRUE(
319+
Cpp::Process(
320+
"int ex() { try { f(); return 0; } catch(...){return 1;} }") == 0);
321+
EXPECT_EQ(Cpp::Evaluate("ex()"), 1)
322+
<< "Failed to catch exceptions in interpreter";
323+
}
324+
325+
TEST(InterpreterTest, InterpreterExceptionsCompiledCode) {
326+
Cpp::CreateInterpreter();
327+
bool caught = false;
328+
try {
329+
EXPECT_TRUE(Cpp::Declare("int f() { throw 1; return 2; }") == 0);
330+
EXPECT_TRUE(Cpp::Process("int res = f();") == 0);
331+
} catch (...) {
332+
caught = true;
333+
}
334+
EXPECT_TRUE(caught) << "Unable to catch exception coming from interpreter";
335+
}

0 commit comments

Comments
 (0)