Skip to content

Commit 29cb7b1

Browse files
yoneymeta-codesync[bot]
authored andcommitted
Fix stack walking builds on macOS and Windows
Summary: Guard POSIX-only stack-walking code from Windows builds. On macOS, use <sys/ucontext.h>, Darwin-specific register accessors, and unqualified signalset macros to support modern Xcode SDKs and arm64e pointer authentication. Update the associated tests accordingly. Reviewed By: DinoV Differential Revision: D116973275 fbshipit-source-id: 8d713698d41d4a7dab0a67cbb52ff4dfc28f3566
1 parent f9cf751 commit 29cb7b1

3 files changed

Lines changed: 44 additions & 14 deletions

File tree

CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,12 @@ if (BUILD_RUNTIME_TESTS)
505505
list(REMOVE_ITEM RUNTIME_TESTS_SOURCES ${PROJECT_SOURCE_DIR}/RuntimeTests/util_test.cpp)
506506
endif()
507507

508+
# Stack walking is stubbed out on Windows and compile-only on macOS, where
509+
# sem_init() fails with ENOSYS.
510+
if (WINDOWS OR MACOS)
511+
list(REMOVE_ITEM RUNTIME_TESTS_SOURCES ${PROJECT_SOURCE_DIR}/RuntimeTests/stack_walk_test.cpp)
512+
endif()
513+
508514
add_executable(RuntimeTests ${RUNTIME_TESTS_SOURCES})
509515

510516
target_link_libraries(

cinderx/Jit/stack_walk.cpp

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,16 @@
22

33
#include "cinderx/Jit/stack_walk.h"
44

5+
#if defined(__APPLE__) || defined(__linux__)
6+
57
#include <fmt/format.h>
68
#include <sys/syscall.h>
79
#include <sys/uio.h>
10+
#ifdef __APPLE__
11+
#include <sys/ucontext.h>
12+
#else
813
#include <ucontext.h>
14+
#endif
915
#include <unistd.h>
1016

1117
#include <atomic>
@@ -17,10 +23,11 @@
1723
#include <cstring>
1824
#include <ctime>
1925
#include <mutex>
26+
#include <stdexcept>
27+
#include <system_error>
2028

2129
namespace cinderx {
2230

23-
#if defined(__APPLE__) || defined(__linux__)
2431
namespace {
2532

2633
// How far above the previous record a caller's record may sit when the stack's
@@ -393,7 +400,9 @@ static std::atomic<StackWalk*> s_active;
393400
bool StackWalk::installHandler(int signum, struct sigaction* prev) {
394401
struct sigaction action = {};
395402
action.sa_sigaction = handleSignal;
396-
::sigemptyset(&action.sa_mask);
403+
// Darwin exposes the signal-set helpers as macros, so they cannot be
404+
// namespace-qualified.
405+
sigemptyset(&action.sa_mask);
397406
action.sa_flags = SA_SIGINFO | SA_RESTART;
398407
return ::sigaction(signum, &action, prev) == 0;
399408
}
@@ -420,7 +429,7 @@ bool StackWalk::handlerIsOurs(int signum) {
420429
// terminates the process.
421430
int StackWalk::claimSignum() {
422431
sigset_t blocked;
423-
::sigemptyset(&blocked);
432+
sigemptyset(&blocked);
424433
::pthread_sigmask(SIG_BLOCK, nullptr, &blocked);
425434

426435
auto claim = [&blocked](int signum) {
@@ -429,7 +438,7 @@ int StackWalk::claimSignum() {
429438
// it reads as unclaimed below and taking it would be undetectable - but a
430439
// thread that waits on a signal has to block it first, and the convention
431440
// is to block it in every thread before any of them start.
432-
if (::sigismember(&blocked, signum) == 1) {
441+
if (sigismember(&blocked, signum) == 1) {
433442
return false;
434443
}
435444
// Already carrying this class's handler, which means an earlier scan
@@ -516,7 +525,7 @@ void StackWalk::resetSignumCache() {
516525
if (signum > 0 && handlerIsOurs(signum)) {
517526
struct sigaction action = {};
518527
action.sa_handler = SIG_DFL;
519-
::sigemptyset(&action.sa_mask);
528+
sigemptyset(&action.sa_mask);
520529
::sigaction(signum, &action, nullptr);
521530
}
522531
}
@@ -837,12 +846,22 @@ StackWalk::Publish StackWalk::publishBatch(size_t count) {
837846
void StackWalk::captureFrames(const void* ucontext) {
838847
auto uc = static_cast<const ucontext_t*>(ucontext);
839848

840-
#if defined(__x86_64__)
849+
#if defined(__APPLE__) && defined(__aarch64__)
850+
// StackWalk is compile-only on macOS because sem_init() is unsupported and
851+
// its constructor always throws. The context extraction still has to build
852+
// as part of the JIT library.
853+
const auto& state = uc->uc_mcontext->__ss;
854+
auto frame = reinterpret_cast<const StackFrame*>(
855+
__darwin_arm_thread_state64_get_fp(state));
856+
auto pc =
857+
reinterpret_cast<const void*>(__darwin_arm_thread_state64_get_pc(state));
858+
auto sp = static_cast<uintptr_t>(__darwin_arm_thread_state64_get_sp(state));
859+
#elif defined(__linux__) && defined(__x86_64__)
841860
auto frame =
842861
reinterpret_cast<const StackFrame*>(uc->uc_mcontext.gregs[REG_RBP]);
843862
auto pc = reinterpret_cast<const void*>(uc->uc_mcontext.gregs[REG_RIP]);
844863
auto sp = static_cast<uintptr_t>(uc->uc_mcontext.gregs[REG_RSP]);
845-
#elif defined(__aarch64__)
864+
#elif defined(__linux__) && defined(__aarch64__)
846865
auto frame = reinterpret_cast<const StackFrame*>(uc->uc_mcontext.regs[29]);
847866
auto pc = reinterpret_cast<const void*>(uc->uc_mcontext.pc);
848867
auto sp = static_cast<uintptr_t>(uc->uc_mcontext.sp);
@@ -907,5 +926,6 @@ void StackWalk::captureFrames(const void* ucontext) {
907926
::sem_post(&handler_exited_);
908927
}
909928
}
910-
#endif
911929
} // namespace cinderx
930+
931+
#endif

cinderx/RuntimeTests/stack_walk_test.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@
77
#include <pthread.h>
88
#include <semaphore.h>
99
#include <sys/mman.h>
10+
#ifdef __APPLE__
11+
#include <sys/ucontext.h>
12+
#else
1013
#include <ucontext.h>
14+
#endif
1115
#include <unistd.h>
1216

1317
#include <algorithm>
@@ -148,17 +152,17 @@ class SpinningThread {
148152
// which signals as soon as the thread is up cannot beat it.
149153
if (deaf_to != 0) {
150154
sigset_t deaf;
151-
::sigemptyset(&deaf);
152-
::sigaddset(&deaf, deaf_to);
155+
sigemptyset(&deaf);
156+
sigaddset(&deaf, deaf_to);
153157
::pthread_sigmask(SIG_BLOCK, &deaf, nullptr);
154158
}
155159
ready_.store(true, std::memory_order_release);
156160
while (!stop_.load(std::memory_order_acquire)) {
157161
if (deaf_to != 0 && !listening_.load(std::memory_order_relaxed) &&
158162
listen_.load(std::memory_order_acquire)) {
159163
sigset_t deaf;
160-
::sigemptyset(&deaf);
161-
::sigaddset(&deaf, deaf_to);
164+
sigemptyset(&deaf);
165+
sigaddset(&deaf, deaf_to);
162166
::pthread_sigmask(SIG_UNBLOCK, &deaf, nullptr);
163167
listening_.store(true, std::memory_order_release);
164168
}
@@ -866,7 +870,7 @@ class OccupiedSignals {
866870
OccupiedSignals(const std::vector<int>& signums, void (*handler)(int)) {
867871
struct sigaction action = {};
868872
action.sa_handler = handler;
869-
::sigemptyset(&action.sa_mask);
873+
sigemptyset(&action.sa_mask);
870874
for (int signum : signums) {
871875
struct sigaction prev = {};
872876
if (::sigaction(signum, &action, &prev) == 0) {
@@ -1081,7 +1085,7 @@ TEST(StackWalkSignalDiscoveryTest, AWalkerRescansAfterItsSignalIsTakenOver) {
10811085

10821086
struct sigaction action = {};
10831087
action.sa_handler = &occupyingHandler;
1084-
::sigemptyset(&action.sa_mask);
1088+
sigemptyset(&action.sa_mask);
10851089
ASSERT_EQ(::sigaction(taken, &action, nullptr), 0);
10861090

10871091
size_t frames = 0;

0 commit comments

Comments
 (0)