From 2c4ee9cc4c084232219b77ffeb556bfe7888724f Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 21 Aug 2026 15:35:32 +0200 Subject: [PATCH 01/14] feat: Add intentional crash API Expose sentry_crash for verifying native crash reporting integrations and use it across existing crash test fixtures. --- CHANGELOG.md | 1 + examples/example.c | 34 ++----------------- include/sentry.h | 11 ++++++ src/sentry_core.c | 33 ++++++++++++++++++ tests/fixtures/dotnet_signal/Program.cs | 6 ++-- tests/fixtures/dotnet_signal/crash.c | 4 --- .../fixtures/inproc_stress/concurrent_crash.c | 7 ++-- tests/fixtures/inproc_stress/main.c | 12 ++----- tests/fixtures/screenshot/screenshot_win32.c | 11 +----- 9 files changed, 57 insertions(+), 62 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc36e05135..51a71a98c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - Add `on_crashed_last_run` callback for inspecting crash envelopes from previous runs. ([#1985](https://github.com/getsentry/sentry-native/pull/1985)) - Add `sentry_get_last_event_id` and `sentry_scope_get_last_event_id` for retrieving the last event ID captured with the global or given scope, respectively. ([#1992](https://github.com/getsentry/sentry-native/pull/1992)) - Native/Unix: The native crash daemon now loads `libcurl` dynamically at runtime by default when `SENTRY_LINK_CURL=AUTO`, avoiding `libcurl` linker work during process startup and significantly speeding up startup time. Explicitly set `SENTRY_LINK_CURL=ON` to link it directly. ([#1955](https://github.com/getsentry/sentry-native/pull/1955)) +- Add `sentry_crash` for deliberately crashing the current process to test its crash reporting configuration. ([#913](https://github.com/getsentry/sentry-native/issues/913)) **Deprecations**: diff --git a/examples/example.c b/examples/example.c index 9d166c8d36..e0ead509f3 100644 --- a/examples/example.c +++ b/examples/example.c @@ -504,36 +504,6 @@ trigger_fastfail_crash() #endif -#ifdef SENTRY_PLATFORM_AIX -// AIX has a null page mapped to the bottom of memory, which means null derefs -// don't segfault. try dereferencing the top of memory instead; the top nibble -// seems to be unusable. -static void *invalid_mem = (void *)0xFFFFFFFFFFFFFF9B; // -100 for memset -#else -static void *invalid_mem = (void *)1; -#endif - -// Detect Address Sanitizer (works for both GCC and Clang) -#if defined(__SANITIZE_ADDRESS__) -# define SENTRY_ASAN_ACTIVE 1 -#elif defined(__has_feature) -# if __has_feature(address_sanitizer) -# define SENTRY_ASAN_ACTIVE 1 -# endif -#endif - -static void -trigger_crash() -{ -#ifdef SENTRY_ASAN_ACTIVE - // Under ASAN, raise signal directly to bypass ASAN's memory interception. - // ASAN intercepts memset and would abort before our signal handler runs. - raise(SIGSEGV); -#else - memset((char *)invalid_mem, 1, 100); -#endif -} - static void trigger_stack_overflow() { @@ -1313,7 +1283,7 @@ main(int argc, char **argv) } if (has_arg(argc, argv, "crash")) { - trigger_crash(); + sentry_crash(); } if (has_arg(argc, argv, "stack-overflow")) { trigger_stack_overflow(); @@ -1522,7 +1492,7 @@ main(int argc, char **argv) } if (has_arg(argc, argv, "crash-after-shutdown")) { - trigger_crash(); + sentry_crash(); } return EXIT_SUCCESS; diff --git a/include/sentry.h b/include/sentry.h index 991f1e1840..647344afcb 100644 --- a/include/sentry.h +++ b/include/sentry.h @@ -2520,6 +2520,17 @@ SENTRY_API sentry_uuid_t sentry_capture_minidumpw_n( SENTRY_EXPERIMENTAL_API void sentry_handle_exception( const sentry_ucontext_t *uctx); +/** + * Deliberately crashes the current process. + * + * This is intended for testing that crash reporting is correctly configured. + * To capture the crash, call this only after `sentry_init` returns + * successfully. + * + * This function does not return and must not be used in production. + */ +SENTRY_EXPERIMENTAL_API void sentry_crash(void); + /** * Type of the `before_breadcrumb` callback. * diff --git a/src/sentry_core.c b/src/sentry_core.c index b87e36c599..4285d070c6 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -1,6 +1,8 @@ #include "sentry_boot.h" +#include #include +#include #include #include "sentry_app_hang_latch.h" @@ -929,6 +931,37 @@ sentry_handle_exception(const sentry_ucontext_t *uctx) } } +// Detect Address Sanitizer (works for both GCC and Clang). +#if defined(__SANITIZE_ADDRESS__) +# define SENTRY_ASAN_ACTIVE 1 +#elif defined(__has_feature) +# if __has_feature(address_sanitizer) +# define SENTRY_ASAN_ACTIVE 1 +# endif +#endif + +void +sentry_crash(void) +{ +#ifdef SENTRY_ASAN_ACTIVE + // ASAN intercepts memory writes and would abort before the crash handler + // runs, so bypass its memory instrumentation. + raise(SIGSEGV); +#else +# ifdef SENTRY_PLATFORM_AIX + // AIX maps its null page, so use an address near the top of memory. + void *volatile invalid_mem = (void *)0xFFFFFFFFFFFFFF9B; +# else + void *volatile invalid_mem = (void *)1; +# endif + memset((char *)invalid_mem, 1, 100); +#endif + + // A user-installed signal or exception handler could allow execution to + // continue. Ensure this API never returns in that case. + abort(); +} + sentry_uuid_t sentry__new_event_id(void) { diff --git a/tests/fixtures/dotnet_signal/Program.cs b/tests/fixtures/dotnet_signal/Program.cs index cf526d45c4..8334ede9b5 100644 --- a/tests/fixtures/dotnet_signal/Program.cs +++ b/tests/fixtures/dotnet_signal/Program.cs @@ -5,8 +5,8 @@ namespace dotnet_signal; class Program { - [DllImport("crash", EntryPoint = "native_crash")] - static extern void native_crash(); + [DllImport("sentry", EntryPoint = "sentry_crash")] + static extern void sentry_crash(); [DllImport("crash", EntryPoint = "enable_sigaltstack")] static extern void enable_sigaltstack(); @@ -72,7 +72,7 @@ public static void RunTest(string[] args, string? databasePath = null) if (args.Contains("native-crash")) { - native_crash(); + sentry_crash(); } else if (args.Contains("managed-exception")) { diff --git a/tests/fixtures/dotnet_signal/crash.c b/tests/fixtures/dotnet_signal/crash.c index c76fd1a4f8..3dead10d0c 100644 --- a/tests/fixtures/dotnet_signal/crash.c +++ b/tests/fixtures/dotnet_signal/crash.c @@ -1,9 +1,5 @@ #include #include -void native_crash(void) -{ - *(int *)10 = 100; -} void enable_sigaltstack(void) { diff --git a/tests/fixtures/inproc_stress/concurrent_crash.c b/tests/fixtures/inproc_stress/concurrent_crash.c index ebf621b3da..a423672618 100644 --- a/tests/fixtures/inproc_stress/concurrent_crash.c +++ b/tests/fixtures/inproc_stress/concurrent_crash.c @@ -5,9 +5,10 @@ * race conditions in the signal handler / handler thread synchronization. */ +#include + #include #include -#include #ifndef _WIN32 # include @@ -21,8 +22,6 @@ #define CRASH_THREADS 20 -static void *invalid_mem = (void *)1; - // Barrier for synchronizing threads #ifndef _WIN32 static volatile int g_barrier = 0; @@ -40,7 +39,7 @@ __declspec(noinline) void do_crash(void) { - memset((char *)invalid_mem, 1, 100); + sentry_crash(); } static void diff --git a/tests/fixtures/inproc_stress/main.c b/tests/fixtures/inproc_stress/main.c index 2ab4b0734a..00e596cdae 100644 --- a/tests/fixtures/inproc_stress/main.c +++ b/tests/fixtures/inproc_stress/main.c @@ -270,12 +270,6 @@ test_concurrent_crash(PATH_TYPE database_path) return 1; } -static void -trigger_crash(void) -{ - memset((char *)invalid_mem, 1, 100); -} - static int setup_sentry_with_crashing_on_crash(PATH_TYPE database_path) { @@ -330,7 +324,7 @@ test_handler_thread_crash(PATH_TYPE database_path) // This will crash, trigger the handler thread, which will call // on_crash callback, which will crash the handler thread. // The fallback should then process in the signal handler. - trigger_crash(); + sentry_crash(); fprintf(stderr, "ERROR: Should have crashed\n"); sentry_close(); @@ -352,7 +346,7 @@ test_handler_abort_crash(PATH_TYPE database_path) // This will crash, trigger the handler thread, which will call // on_crash callback, which will call abort(). abort() resets the // signal mask, so this tests a different code path. - trigger_crash(); + sentry_crash(); fprintf(stderr, "ERROR: Should have crashed\n"); sentry_close(); @@ -418,7 +412,7 @@ test_simple_crash(PATH_TYPE database_path) fprintf(stderr, "Starting simple crash test\n"); fflush(stderr); - trigger_crash(); + sentry_crash(); fprintf(stderr, "ERROR: Should have crashed\n"); sentry_close(); diff --git a/tests/fixtures/screenshot/screenshot_win32.c b/tests/fixtures/screenshot/screenshot_win32.c index d8ded11a39..cef9dc6e8f 100644 --- a/tests/fixtures/screenshot/screenshot_win32.c +++ b/tests/fixtures/screenshot/screenshot_win32.c @@ -4,7 +4,6 @@ #include #include #include -#include enum { IDT_TIMER_CRASH = 1, @@ -23,14 +22,6 @@ has_arg(int argc, LPWSTR *argv, LPCWSTR arg) return false; } -static void *invalid_mem = (void *)1; - -static void -trigger_crash() -{ - memset((char *)invalid_mem, 1, 100); -} - static void trigger_stack_overflow() { @@ -61,7 +52,7 @@ wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) case WM_TIMER: switch (wParam) { case IDT_TIMER_CRASH: - trigger_crash(); + sentry_crash(); break; case IDT_TIMER_STACK_OVERFLOW: trigger_stack_overflow(); From 3ee37d955f4a5836111a21ee54427ba60cfeeb33 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 21 Aug 2026 15:43:59 +0200 Subject: [PATCH 02/14] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 51a71a98c9..fcd1de3a5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ - Add `on_crashed_last_run` callback for inspecting crash envelopes from previous runs. ([#1985](https://github.com/getsentry/sentry-native/pull/1985)) - Add `sentry_get_last_event_id` and `sentry_scope_get_last_event_id` for retrieving the last event ID captured with the global or given scope, respectively. ([#1992](https://github.com/getsentry/sentry-native/pull/1992)) - Native/Unix: The native crash daemon now loads `libcurl` dynamically at runtime by default when `SENTRY_LINK_CURL=AUTO`, avoiding `libcurl` linker work during process startup and significantly speeding up startup time. Explicitly set `SENTRY_LINK_CURL=ON` to link it directly. ([#1955](https://github.com/getsentry/sentry-native/pull/1955)) -- Add `sentry_crash` for deliberately crashing the current process to test its crash reporting configuration. ([#913](https://github.com/getsentry/sentry-native/issues/913)) +- Add `sentry_crash` for deliberately crashing the current process to test its crash reporting configuration. ([#2013](https://github.com/getsentry/sentry-native/pull/2013)) **Deprecations**: From c3099b0a2c4b4cd3a0c24cebe18e6b624bcb1ef6 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Sun, 23 Aug 2026 10:32:37 +0200 Subject: [PATCH 03/14] SENTRY_NORETURN --- include/sentry.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/sentry.h b/include/sentry.h index 647344afcb..c13b3ec2b1 100644 --- a/include/sentry.h +++ b/include/sentry.h @@ -144,16 +144,19 @@ extern "C" { #endif #if defined(__GNUC__) || defined(__clang__) +# define SENTRY_NORETURN __attribute__((noreturn)) # define SENTRY_SUPPRESS_DEPRECATED \ _Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") # define SENTRY_RESTORE_DEPRECATED _Pragma("GCC diagnostic pop") #elif defined(_MSC_VER) +# define SENTRY_NORETURN __declspec(noreturn) # define SENTRY_SUPPRESS_DEPRECATED \ __pragma(warning(push)); \ __pragma(warning(disable : 4996)) # define SENTRY_RESTORE_DEPRECATED __pragma(warning(pop)) #else +# define SENTRY_NORETURN # define SENTRY_SUPPRESS_DEPRECATED # define SENTRY_RESTORE_DEPRECATED #endif @@ -2529,7 +2532,7 @@ SENTRY_EXPERIMENTAL_API void sentry_handle_exception( * * This function does not return and must not be used in production. */ -SENTRY_EXPERIMENTAL_API void sentry_crash(void); +SENTRY_EXPERIMENTAL_API SENTRY_NORETURN void sentry_crash(void); /** * Type of the `before_breadcrumb` callback. From 58045851d7de722a630c4a0187e80b367308e87e Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 24 Aug 2026 12:09:39 +0200 Subject: [PATCH 04/14] ps --- src/sentry_core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/sentry_core.c b/src/sentry_core.c index 4285d070c6..81f522b3c3 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -1,6 +1,8 @@ #include "sentry_boot.h" -#include +#ifndef SENTRY_PLATFORM_PS +# include +#endif #include #include #include From 64da8b796e9b97eaea26f01c654c2e18f0ab8f1d Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 24 Aug 2026 13:34:39 +0200 Subject: [PATCH 05/14] drop abort --- include/sentry.h | 7 +------ src/sentry_core.c | 5 ----- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/include/sentry.h b/include/sentry.h index 32f49bda29..bdb8cc2f19 100644 --- a/include/sentry.h +++ b/include/sentry.h @@ -144,19 +144,16 @@ extern "C" { #endif #if defined(__GNUC__) || defined(__clang__) -# define SENTRY_NORETURN __attribute__((noreturn)) # define SENTRY_SUPPRESS_DEPRECATED \ _Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") # define SENTRY_RESTORE_DEPRECATED _Pragma("GCC diagnostic pop") #elif defined(_MSC_VER) -# define SENTRY_NORETURN __declspec(noreturn) # define SENTRY_SUPPRESS_DEPRECATED \ __pragma(warning(push)); \ __pragma(warning(disable : 4996)) # define SENTRY_RESTORE_DEPRECATED __pragma(warning(pop)) #else -# define SENTRY_NORETURN # define SENTRY_SUPPRESS_DEPRECATED # define SENTRY_RESTORE_DEPRECATED #endif @@ -2529,10 +2526,8 @@ SENTRY_EXPERIMENTAL_API void sentry_handle_exception( * This is intended for testing that crash reporting is correctly configured. * To capture the crash, call this only after `sentry_init` returns * successfully. - * - * This function does not return and must not be used in production. */ -SENTRY_EXPERIMENTAL_API SENTRY_NORETURN void sentry_crash(void); +SENTRY_EXPERIMENTAL_API void sentry_crash(void); /** * Type of the `before_breadcrumb` callback. diff --git a/src/sentry_core.c b/src/sentry_core.c index 9ce8f42410..3163b2b993 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -4,7 +4,6 @@ # include #endif #include -#include #include #include "sentry_app_hang_latch.h" @@ -958,10 +957,6 @@ sentry_crash(void) # endif memset((char *)invalid_mem, 1, 100); #endif - - // A user-installed signal or exception handler could allow execution to - // continue. Ensure this API never returns in that case. - abort(); } sentry_uuid_t From 1a01ae3221036048aceeb1eae263be4964b4a88e Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 24 Aug 2026 13:46:38 +0200 Subject: [PATCH 06/14] revert unintional changes --- src/sentry_core.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/sentry_core.c b/src/sentry_core.c index 3163b2b993..84ba626d4a 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -932,7 +932,7 @@ sentry_handle_exception(const sentry_ucontext_t *uctx) } } -// Detect Address Sanitizer (works for both GCC and Clang). +// Detect Address Sanitizer (works for both GCC and Clang) #if defined(__SANITIZE_ADDRESS__) # define SENTRY_ASAN_ACTIVE 1 #elif defined(__has_feature) @@ -945,12 +945,14 @@ void sentry_crash(void) { #ifdef SENTRY_ASAN_ACTIVE - // ASAN intercepts memory writes and would abort before the crash handler - // runs, so bypass its memory instrumentation. + // Under ASAN, raise signal directly to bypass ASAN's memory interception. + // ASAN intercepts memset and would abort before our signal handler runs. raise(SIGSEGV); #else # ifdef SENTRY_PLATFORM_AIX - // AIX maps its null page, so use an address near the top of memory. + // AIX has a null page mapped to the bottom of memory, which means null + // derefs don't segfault. try dereferencing the top of memory instead; the + // top nibble seems to be unusable. void *volatile invalid_mem = (void *)0xFFFFFFFFFFFFFF9B; # else void *volatile invalid_mem = (void *)1; From bd1d302d878611df6be15a7bc70a8583e258349e Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 24 Aug 2026 14:04:41 +0200 Subject: [PATCH 07/14] restore globals --- src/sentry_core.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/sentry_core.c b/src/sentry_core.c index 84ba626d4a..1c9f64a5b2 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -932,6 +932,15 @@ sentry_handle_exception(const sentry_ucontext_t *uctx) } } +#ifdef SENTRY_PLATFORM_AIX +// AIX has a null page mapped to the bottom of memory, which means null derefs +// don't segfault. try dereferencing the top of memory instead; the top nibble +// seems to be unusable. +static void *invalid_mem = (void *)0xFFFFFFFFFFFFFF9B; // -100 for memset +#else +static void *invalid_mem = (void *)1; +#endif + // Detect Address Sanitizer (works for both GCC and Clang) #if defined(__SANITIZE_ADDRESS__) # define SENTRY_ASAN_ACTIVE 1 @@ -949,14 +958,6 @@ sentry_crash(void) // ASAN intercepts memset and would abort before our signal handler runs. raise(SIGSEGV); #else -# ifdef SENTRY_PLATFORM_AIX - // AIX has a null page mapped to the bottom of memory, which means null - // derefs don't segfault. try dereferencing the top of memory instead; the - // top nibble seems to be unusable. - void *volatile invalid_mem = (void *)0xFFFFFFFFFFFFFF9B; -# else - void *volatile invalid_mem = (void *)1; -# endif memset((char *)invalid_mem, 1, 100); #endif } From 859f7792752880f706e067085331c69ecc53c7ac Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 24 Aug 2026 14:12:57 +0200 Subject: [PATCH 08/14] volatile --- src/sentry_core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sentry_core.c b/src/sentry_core.c index 1c9f64a5b2..ad44ba285d 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -936,9 +936,10 @@ sentry_handle_exception(const sentry_ucontext_t *uctx) // AIX has a null page mapped to the bottom of memory, which means null derefs // don't segfault. try dereferencing the top of memory instead; the top nibble // seems to be unusable. -static void *invalid_mem = (void *)0xFFFFFFFFFFFFFF9B; // -100 for memset +static void *volatile invalid_mem + = (void *)0xFFFFFFFFFFFFFF9B; // -100 for memset #else -static void *invalid_mem = (void *)1; +static void *volatile invalid_mem = (void *)1; #endif // Detect Address Sanitizer (works for both GCC and Clang) From 6511ccd2e056208703eea5969c01696e014851e9 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 24 Aug 2026 15:47:51 +0200 Subject: [PATCH 09/14] noinline --- src/sentry_core.c | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/src/sentry_core.c b/src/sentry_core.c index ad44ba285d..67c0c93d59 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -932,16 +932,6 @@ sentry_handle_exception(const sentry_ucontext_t *uctx) } } -#ifdef SENTRY_PLATFORM_AIX -// AIX has a null page mapped to the bottom of memory, which means null derefs -// don't segfault. try dereferencing the top of memory instead; the top nibble -// seems to be unusable. -static void *volatile invalid_mem - = (void *)0xFFFFFFFFFFFFFF9B; // -100 for memset -#else -static void *volatile invalid_mem = (void *)1; -#endif - // Detect Address Sanitizer (works for both GCC and Clang) #if defined(__SANITIZE_ADDRESS__) # define SENTRY_ASAN_ACTIVE 1 @@ -951,7 +941,18 @@ static void *volatile invalid_mem = (void *)1; # endif #endif -void +#if defined(__clang__) +# define SENTRY_CRASH_ATTRIBUTES __attribute__((noinline, optnone)) +#elif defined(__GNUC__) +# define SENTRY_CRASH_ATTRIBUTES __attribute__((noinline, optimize("O0"))) +#elif defined(_MSC_VER) +# define SENTRY_CRASH_ATTRIBUTES __declspec(noinline) +# pragma optimize("", off) +#else +# define SENTRY_CRASH_ATTRIBUTES +#endif + +SENTRY_CRASH_ATTRIBUTES void sentry_crash(void) { #ifdef SENTRY_ASAN_ACTIVE @@ -959,10 +960,23 @@ sentry_crash(void) // ASAN intercepts memset and would abort before our signal handler runs. raise(SIGSEGV); #else +# ifdef SENTRY_PLATFORM_AIX + // AIX has a null page mapped to the bottom of memory, which means null + // derefs don't segfault. try dereferencing the top of memory instead; the + // top nibble seems to be unusable. + void *volatile invalid_mem = (void *)0xFFFFFFFFFFFFFF9B; +# else + void *volatile invalid_mem = (void *)1; +# endif memset((char *)invalid_mem, 1, 100); #endif } +#ifdef _MSC_VER +# pragma optimize("", on) +#endif +#undef SENTRY_CRASH_ATTRIBUTES + sentry_uuid_t sentry__new_event_id(void) { From 7817bf2671864441eba670a40b1c662824194828 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 24 Aug 2026 16:05:24 +0200 Subject: [PATCH 10/14] comments --- src/sentry_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sentry_core.c b/src/sentry_core.c index 67c0c93d59..afee8e1207 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -941,6 +941,7 @@ sentry_handle_exception(const sentry_ucontext_t *uctx) # endif #endif +// Preserve an unwindable stack frame for crash reporting. #if defined(__clang__) # define SENTRY_CRASH_ATTRIBUTES __attribute__((noinline, optnone)) #elif defined(__GNUC__) @@ -964,7 +965,7 @@ sentry_crash(void) // AIX has a null page mapped to the bottom of memory, which means null // derefs don't segfault. try dereferencing the top of memory instead; the // top nibble seems to be unusable. - void *volatile invalid_mem = (void *)0xFFFFFFFFFFFFFF9B; + void *volatile invalid_mem = (void *)0xFFFFFFFFFFFFFF9B; // -100 for memset # else void *volatile invalid_mem = (void *)1; # endif From ef9b3f0c99b34de5439ef11c499bb5651978eb4d Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 24 Aug 2026 16:28:00 +0200 Subject: [PATCH 11/14] SENTRY_NOINLINE --- src/sentry_core.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/sentry_core.c b/src/sentry_core.c index afee8e1207..d4af3707e3 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -941,19 +941,23 @@ sentry_handle_exception(const sentry_ucontext_t *uctx) # endif #endif -// Preserve an unwindable stack frame for crash reporting. -#if defined(__clang__) -# define SENTRY_CRASH_ATTRIBUTES __attribute__((noinline, optnone)) -#elif defined(__GNUC__) -# define SENTRY_CRASH_ATTRIBUTES __attribute__((noinline, optimize("O0"))) -#elif defined(_MSC_VER) -# define SENTRY_CRASH_ATTRIBUTES __declspec(noinline) -# pragma optimize("", off) -#else -# define SENTRY_CRASH_ATTRIBUTES +// Preserve an unwindable stack frame for crash reporting +#if defined(__has_attribute) +# if __has_attribute(noinline) && __has_attribute(optnone) +# define SENTRY_NOINLINE __attribute__((noinline, optnone)) +# elif __has_attribute(noinline) && __has_attribute(optimize) +# define SENTRY_NOINLINE __attribute__((noinline, optimize("O0"))) +# endif +#endif +#ifndef SENTRY_NOINLINE +# if defined(_MSC_VER) +# define SENTRY_NOINLINE __declspec(noinline) +# else +# define SENTRY_NOINLINE +# endif #endif -SENTRY_CRASH_ATTRIBUTES void +SENTRY_NOINLINE void sentry_crash(void) { #ifdef SENTRY_ASAN_ACTIVE @@ -973,10 +977,7 @@ sentry_crash(void) #endif } -#ifdef _MSC_VER -# pragma optimize("", on) -#endif -#undef SENTRY_CRASH_ATTRIBUTES +#undef SENTRY_NOINLINE sentry_uuid_t sentry__new_event_id(void) From eb7b996c478b429479496bd68b75181f6e98f042 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 24 Aug 2026 16:39:11 +0200 Subject: [PATCH 12/14] pragma optimize --- src/sentry_core.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/sentry_core.c b/src/sentry_core.c index d4af3707e3..1d69e78901 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -942,7 +942,10 @@ sentry_handle_exception(const sentry_ucontext_t *uctx) #endif // Preserve an unwindable stack frame for crash reporting -#if defined(__has_attribute) +#if defined(_MSC_VER) +# define SENTRY_NOINLINE __declspec(noinline) +# pragma optimize("", off) +#elif defined(__has_attribute) # if __has_attribute(noinline) && __has_attribute(optnone) # define SENTRY_NOINLINE __attribute__((noinline, optnone)) # elif __has_attribute(noinline) && __has_attribute(optimize) @@ -950,11 +953,7 @@ sentry_handle_exception(const sentry_ucontext_t *uctx) # endif #endif #ifndef SENTRY_NOINLINE -# if defined(_MSC_VER) -# define SENTRY_NOINLINE __declspec(noinline) -# else -# define SENTRY_NOINLINE -# endif +# define SENTRY_NOINLINE #endif SENTRY_NOINLINE void @@ -977,6 +976,9 @@ sentry_crash(void) #endif } +#if defined(_MSC_VER) +# pragma optimize("", on) +#endif #undef SENTRY_NOINLINE sentry_uuid_t From dd226c861421ebce40a9c8203727ce1fad2026c6 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 24 Aug 2026 17:40:16 +0200 Subject: [PATCH 13/14] musl --- src/sentry_core.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/sentry_core.c b/src/sentry_core.c index 1d69e78901..1e73ef83da 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -941,15 +941,20 @@ sentry_handle_exception(const sentry_ucontext_t *uctx) # endif #endif -// Preserve an unwindable stack frame for crash reporting +// Preserve `sentry_crash` as an unwindable stack frame. Use `optnone` only on +// macOS because on musl it leaves the fault inside stripped `memset`, producing +// an unsymbolicated stack trace. #if defined(_MSC_VER) # define SENTRY_NOINLINE __declspec(noinline) # pragma optimize("", off) #elif defined(__has_attribute) -# if __has_attribute(noinline) && __has_attribute(optnone) +# if defined(SENTRY_PLATFORM_MACOS) && __has_attribute(noinline) \ + && __has_attribute(optnone) # define SENTRY_NOINLINE __attribute__((noinline, optnone)) # elif __has_attribute(noinline) && __has_attribute(optimize) # define SENTRY_NOINLINE __attribute__((noinline, optimize("O0"))) +# elif __has_attribute(noinline) +# define SENTRY_NOINLINE __attribute__((noinline)) # endif #endif #ifndef SENTRY_NOINLINE From d4f73e534f8d94b241ce2637b07a10af624bf77f Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 24 Aug 2026 17:49:39 +0200 Subject: [PATCH 14/14] comment --- src/sentry_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sentry_core.c b/src/sentry_core.c index 1e73ef83da..72a382f0f5 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -941,9 +941,9 @@ sentry_handle_exception(const sentry_ucontext_t *uctx) # endif #endif -// Preserve `sentry_crash` as an unwindable stack frame. Use `optnone` only on -// macOS because on musl it leaves the fault inside stripped `memset`, producing -// an unsymbolicated stack trace. +// Preserve `sentry_crash` as an unwindable stack frame. Clang's `optnone` is +// needed on macOS, but on musl it leaves the fault inside stripped `memset`, +// producing an unsymbolicated stack trace. #if defined(_MSC_VER) # define SENTRY_NOINLINE __declspec(noinline) # pragma optimize("", off)