Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- Windows: fix HTTP rate limit response header parsing. ([#1732](https://github.com/getsentry/sentry-native/pull/1732))
- POSIX: prevent condition-variable timeout overflow from busy-spinning flush and shutdown waits. ([#1731](https://github.com/getsentry/sentry-native/pull/1731))
- Native/macOS: fix thread stack descriptor. ([#1726](https://github.com/getsentry/sentry-native/pull/1726))
- Native/macOS: honor the system crash reporter forwarding option. ([#1743](https://github.com/getsentry/sentry-native/pull/1743))

## 0.14.2

Expand Down
8 changes: 4 additions & 4 deletions include/sentry.h
Original file line number Diff line number Diff line change
Expand Up @@ -1836,10 +1836,10 @@ SENTRY_EXPERIMENTAL_API int sentry_set_thread_stack_guarantee(
/**
* Enables forwarding to the system crash reporter. Disabled by default.
*
* This setting only has an effect when using Crashpad on macOS. If enabled,
* Crashpad forwards crashes to the macOS system crash reporter. Depending
* on the crash, this may impact the crash time. Even if enabled, Crashpad
* may choose not to forward certain crashes.
* This setting only has an effect when using the crashpad or native backend on
* macOS. If enabled, the crash handler forwards crashes to the macOS system
* crash reporter. Depending on the crash, this may impact the crash time. Even
* if enabled, the crash handler may choose not to forward certain crashes.
*/
SENTRY_API void sentry_options_set_system_crash_reporter_enabled(
sentry_options_t *opts, int enabled);
Expand Down
1 change: 1 addition & 0 deletions src/backends/native/sentry_crash_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ typedef struct {
bool enable_large_attachments;
bool http_retry;
uint64_t shutdown_timeout;
bool system_crash_reporter_enabled;

// Atomic user consent (sentry_user_consent_t), updated whenever user
// consent changes so the daemon can honor it at crash time.
Expand Down
77 changes: 63 additions & 14 deletions src/backends/native/sentry_crash_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,47 @@ static sentry_crash_ipc_t *g_crash_ipc = NULL;
static struct sigaction g_previous_handlers[16];
static stack_t g_signal_stack = { 0 };

static void
reset_signal_handlers(void)
{
for (size_t i = 0; i < g_crash_signal_count; i++) {
sigaction(g_crash_signals[i], &g_previous_handlers[i], NULL);
}
}

static void
reraise_signal(int signum)
{
signal(signum, SIG_DFL);
raise(signum);
}

static void
invoke_previous_signal_handler(int signum, siginfo_t *info, void *context)
{
// Re-enable previous signal handlers before re-raising to prevent loops
reset_signal_handlers();

for (size_t i = 0; i < g_crash_signal_count; i++) {
if (g_crash_signals[i] != signum) {
continue;
}

struct sigaction *handler = &g_previous_handlers[i];
if (handler->sa_handler == SIG_DFL || handler->sa_handler == SIG_IGN) {
return;
}

if (handler->sa_flags & SA_SIGINFO) {
handler->sa_sigaction(signum, info, context);
} else {
handler->sa_handler(signum);
}

return;
}
}

/**
* Get current thread ID (signal-safe)
*/
Expand Down Expand Up @@ -251,23 +292,22 @@ safe_build_stack_path(
static void
crash_signal_handler(int signum, siginfo_t *info, void *context)
{
sentry_crash_ipc_t *ipc = g_crash_ipc;
if (!ipc || !ipc->shmem) {
// No IPC available, forward to the previous handler
invoke_previous_signal_handler(signum, info, context);
// The previous handler returned, fall back to default termination
reraise_signal(signum);
return;
}

// Only handle crash once - check if already processing
static volatile long handling_crash = 0;
if (!sentry__atomic_compare_swap(&handling_crash, 0, 1)) {
// Already handling a crash, just exit immediately
_exit(1);
}

// Re-enable signal to prevent loops
signal(signum, SIG_DFL);

sentry_crash_ipc_t *ipc = g_crash_ipc;
if (!ipc || !ipc->shmem) {
// No IPC available, just re-raise
raise(signum);
return;
}

sentry_crash_context_t *ctx = ipc->shmem;
ucontext_t *uctx = (ucontext_t *)context;

Expand Down Expand Up @@ -762,7 +802,18 @@ crash_signal_handler(int signum, siginfo_t *info, void *context)
}
}

raise(signum);
invoke_previous_signal_handler(signum, info, context);

# if defined(SENTRY_PLATFORM_MACOS)
if (!ctx->system_crash_reporter_enabled) {
// By convention, use the 128 + signal exit code without re-raising
// and invoking the macOS system crash reporter
_exit(128 + signum);
}
# endif

// The previous handler returned, fall back to default termination
reraise_signal(signum);
}

int
Expand Down Expand Up @@ -855,9 +906,7 @@ void
sentry__crash_handler_shutdown(void)
{
// Restore previous signal handlers
for (size_t i = 0; i < g_crash_signal_count; i++) {
sigaction(g_crash_signals[i], &g_previous_handlers[i], NULL);
}
reset_signal_handlers();

// Clean up signal stack
if (g_signal_stack.ss_sp) {
Expand Down
1 change: 1 addition & 0 deletions src/backends/sentry_backend_native.c
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ native_backend_startup(

// Set crash reporting mode from options
ctx->crash_reporting_mode = options->crash_reporting_mode;
ctx->system_crash_reporter_enabled = options->system_crash_reporter_enabled;

// Pass debug logging setting to daemon
ctx->debug_enabled = options->debug;
Expand Down
3 changes: 3 additions & 0 deletions tests/unit/test_native_backend.c
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,7 @@ SENTRY_TEST(crash_context_options_propagation)
sentry_options_set_ca_certs(options, "/path/to/ca-bundle.crt");
sentry_options_set_proxy(options, "http://myproxy:3128");
sentry_options_set_shutdown_timeout(options, 12345);
sentry_options_set_system_crash_reporter_enabled(options, true);

// Verify options were set correctly
TEST_CHECK_STRING_EQUAL(
Expand Down Expand Up @@ -417,13 +418,15 @@ SENTRY_TEST(crash_context_options_propagation)
ctx->user_agent[sizeof(ctx->user_agent) - 1] = '\0';
}
ctx->shutdown_timeout = options->shutdown_timeout;
ctx->system_crash_reporter_enabled = options->system_crash_reporter_enabled;

// Verify crash context received the values
TEST_CHECK_STRING_EQUAL(ctx->ca_certs, "/path/to/ca-bundle.crt");
TEST_CHECK_STRING_EQUAL(ctx->proxy, "http://myproxy:3128");
// user_agent should have the default SDK user agent
TEST_CHECK(ctx->user_agent[0] != '\0');
TEST_CHECK_UINT64_EQUAL(ctx->shutdown_timeout, 12345);
TEST_CHECK(ctx->system_crash_reporter_enabled);

sentry_free(ctx);
sentry_options_free(options);
Expand Down
Loading