Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/CppInterOp/Compatibility.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,11 @@ static inline char* GetEnv(const char* Var_Name) {
#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"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: included header MachO.h is not used directly [misc-include-cleaner]

Suggested change
#include "llvm/Config/llvm-config.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"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: included header MachO.h is not used directly [misc-include-cleaner]

Suggested change
#include "llvm/Support/Casting.h"
#include "llvm/Support/Casting.h"

#include "llvm/Support/Path.h"

Expand Down
58 changes: 57 additions & 1 deletion lib/CppInterOp/CppInterOp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,44 @@

#include <stack>

#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);

#endif // __APPLE__

namespace Cpp {

using namespace clang;
Expand All @@ -88,7 +126,15 @@ static compat::Interpreter* sInterpreter = nullptr;
// This might fix the issue https://reviews.llvm.org/D107087
// FIXME: For now we just leak the Interpreter.
struct InterpDeleter {
~InterpDeleter() = default;
~InterpDeleter() {
#ifdef __APPLE__
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
// sInterpreter.release();
}
} Deleter;

static compat::Interpreter& getInterp() {
Expand Down Expand Up @@ -2865,6 +2911,8 @@ TInterp_t CreateInterpreter(const std::vector<const char*>& Args /*={}*/,
#ifdef _WIN32
// FIXME : Workaround Sema::PushDeclContext assert on windows
ClingArgv.push_back("-fno-delayed-template-parsing");
#elif __APPLE__
ClingArgv.push_back("-fforce-dwarf-frame");
#endif
ClingArgv.insert(ClingArgv.end(), Args.begin(), Args.end());
// To keep the Interpreter creation interface between cling and clang-repl
Expand Down Expand Up @@ -2923,6 +2971,14 @@ TInterp_t CreateInterpreter(const std::vector<const char*>& Args /*={}*/,
// FIXME: Enable this assert once we figure out how to fix the multiple
// calls to CreateInterpreter.
// assert(!sInterpreter && "Interpreter already set.");
#ifdef __APPLE__
// Add a handler to support exceptions from interpreted code.
// See llvm/llvm-project#49036
if (auto* unw_add_find_dynamic_unwind_sections = (int (*)(
unw_find_dynamic_unwind_sections find_dynamic_unwind_sections))
dlsym(RTLD_DEFAULT, "__unw_add_find_dynamic_unwind_sections"))
unw_add_find_dynamic_unwind_sections(find_dynamic_unwind_sections);
#endif // __APPLE__
sInterpreter = I;
return I;
}
Expand Down
22 changes: 22 additions & 0 deletions unittests/CppInterOp/InterpreterTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,3 +311,25 @@ if (llvm::sys::RunningOnValgrind())
delete ExtInterp;
#endif
}

TEST(InterpreterTest, InterpreterExceptions) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: function 'TEST' can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage]

Suggested change
TEST(InterpreterTest, InterpreterExceptions) {
TESTstatic (InterpreterTest, InterpreterExceptions) {

Cpp::CreateInterpreter();
EXPECT_TRUE(Cpp::Declare("int f() { throw 1; return 2; }") == 0);
EXPECT_TRUE(
Cpp::Process(
"int ex() { try { f(); return 0; } catch(...){return 1;} }") == 0);
EXPECT_EQ(Cpp::Evaluate("ex()"), 1)
<< "Failed to catch exceptions in interpreter";
}

TEST(InterpreterTest, InterpreterExceptionsCompiledCode) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: function 'TEST' can be made static or moved into an anonymous namespace to enforce internal linkage [misc-use-internal-linkage]

Suggested change
TEST(InterpreterTest, InterpreterExceptionsCompiledCode) {
TESTstatic (InterpreterTest, InterpreterExceptionsCompiledCode) {

Cpp::CreateInterpreter();
bool caught = false;
try {
EXPECT_TRUE(Cpp::Declare("int f() { throw 1; return 2; }") == 0);
EXPECT_TRUE(Cpp::Process("int res = f();") == 0);
} catch (...) {
caught = true;
}
EXPECT_TRUE(caught) << "Unable to catch exception coming from interpreter";
}
Loading