diff --git a/lib/Interpreter/Compatibility.h b/lib/Interpreter/Compatibility.h index ded7cbde3..40a41d880 100644 --- a/lib/Interpreter/Compatibility.h +++ b/lib/Interpreter/Compatibility.h @@ -13,9 +13,11 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Config/llvm-config.h" #include "llvm/ExecutionEngine/JITSymbol.h" #include "llvm/ExecutionEngine/Orc/LLJIT.h" +#include "llvm/Object/MachO.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Path.h" diff --git a/lib/Interpreter/CppInterOp.cpp b/lib/Interpreter/CppInterOp.cpp index eab23c818..150df29b3 100644 --- a/lib/Interpreter/CppInterOp.cpp +++ b/lib/Interpreter/CppInterOp.cpp @@ -49,6 +49,51 @@ #include #endif // WIN32 +#ifdef __APPLE__ +// Define a minimal mach header for JIT'd code, to support exceptions on osx 14 +// and later. See llvm/llvm-project#49036 +static llvm::MachO::mach_header_64 fake_mach_header = { + .magic = llvm::MachO::MH_MAGIC_64, + .cputype = llvm::MachO::CPU_TYPE_ARM64, + .cpusubtype = llvm::MachO::CPU_SUBTYPE_ARM64_ALL, + .filetype = llvm::MachO::MH_DYLIB, + .ncmds = 0, + .sizeofcmds = 0, + .flags = 0, + .reserved = 0}; + +// Declare libunwind SPI types and functions. +struct unw_dynamic_unwind_sections { + uintptr_t dso_base; + uintptr_t dwarf_section; + size_t dwarf_section_length; + uintptr_t compact_unwind_section; + size_t compact_unwind_section_length; +}; + +int find_dynamic_unwind_sections(uintptr_t addr, + unw_dynamic_unwind_sections* info) { + info->dso_base = (uintptr_t)&fake_mach_header; + info->dwarf_section = 0; + info->dwarf_section_length = 0; + info->compact_unwind_section = 0; + info->compact_unwind_section_length = 0; + return 1; +} + +// Typedef for callback above. +typedef int (*unw_find_dynamic_unwind_sections)( + uintptr_t addr, struct unw_dynamic_unwind_sections* info); + +void removeFindDynamicUnwindSections() { + if (auto* unw_remove_find_dynamic_unwind_sections = (int (*)( + unw_find_dynamic_unwind_sections find_dynamic_unwind_sections)) + dlsym(RTLD_DEFAULT, "__unw_remove_find_dynamic_unwind_sections")) + unw_remove_find_dynamic_unwind_sections(find_dynamic_unwind_sections); +} + +#endif // __APPLE__ + namespace Cpp { using namespace clang; @@ -62,7 +107,12 @@ namespace Cpp { // This might fix the issue https://reviews.llvm.org/D107087 // FIXME: For now we just leak the Interpreter. struct InterpDeleter { - ~InterpDeleter() { sInterpreter.release(); } + ~InterpDeleter() { +#ifdef __APPLE__ + removeFindDynamicUnwindSections(); +#endif + sInterpreter.release(); + } } Deleter; static compat::Interpreter& getInterp() { diff --git a/unittests/CppInterOp/InterpreterTest.cpp b/unittests/CppInterOp/InterpreterTest.cpp index 19cc1bf11..8b348c087 100644 --- a/unittests/CppInterOp/InterpreterTest.cpp +++ b/unittests/CppInterOp/InterpreterTest.cpp @@ -103,3 +103,15 @@ TEST(InterpreterTest, DetectSystemCompilerIncludePaths) { Cpp::DetectSystemCompilerIncludePaths(includes); EXPECT_FALSE(includes.empty()); } + +TEST(InterpreterTest, InterpreterExceptions) { + Cpp::CreateInterpreter(); + bool caught = false; + try { + EXPECT_TRUE(Cpp::Declare("int f() { throw; return 1; }") == 0); + EXPECT_TRUE(Cpp::Process("int res = f();") == 0); + } catch (...) { + caught = true; + } + EXPECT_TRUE(caught) << "Unable to catch exception coming from interpreter"; +}