From 4bb7111aa0d7dbda0e90754f453746ec2fd142ac Mon Sep 17 00:00:00 2001 From: Amir Mujacic Date: Tue, 9 Sep 2025 12:26:34 +0200 Subject: [PATCH 01/12] feat: Add before crash hook to allow modifying other callbacks before crash --- include/sentry.h | 30 ++++++++++++++++++++++++ src/backends/sentry_backend_breakpad.cpp | 6 +++++ src/backends/sentry_backend_crashpad.cpp | 7 ++++++ src/backends/sentry_backend_inproc.c | 6 +++++ src/sentry_options.c | 8 +++++++ src/sentry_options.h | 2 ++ 6 files changed, 59 insertions(+) diff --git a/include/sentry.h b/include/sentry.h index 9a7ada89e..e61d3f396 100644 --- a/include/sentry.h +++ b/include/sentry.h @@ -989,6 +989,36 @@ typedef sentry_value_t (*sentry_event_function_t)( SENTRY_API void sentry_options_set_before_send( sentry_options_t *opts, sentry_event_function_t func, void *user_data); +/** + * Type of the `before_crash` callback. + * + * The `before_crash` callback is invoked immediately when a crash is detected, + * before any crash processing begins. This provides an opportunity to perform + * cleanup or disable logging operations at the earliest possible moment during + * crash handling. + * + * Unlike `on_crash`, this callback does not receive an event object and is not + * intended for event filtering or modification. It is purely for performing + * early crash-time operations like flushing logs, closing files, or other + * cleanup tasks. + * + * The callback has a void return type as it is not intended to filter or + * modify crash events. + * + * This function may be invoked inside of a signal handler and must be safe for + * that purpose, see https://man7.org/linux/man-pages/man7/signal-safety.7.html. + * On Windows, it may be called from inside of a `UnhandledExceptionFilter`. + */ +typedef void (*sentry_before_crash_function_t)(void *user_data); + +/** + * Sets the `before_crash` callback. + * + * See the `sentry_before_crash_function_t` typedef above for more information. + */ +SENTRY_API void sentry_options_set_before_crash(sentry_options_t *opts, + sentry_before_crash_function_t func, void *user_data); + /** * Type of the `on_crash` callback. * diff --git a/src/backends/sentry_backend_breakpad.cpp b/src/backends/sentry_backend_breakpad.cpp index 89be05165..51736febe 100644 --- a/src/backends/sentry_backend_breakpad.cpp +++ b/src/backends/sentry_backend_breakpad.cpp @@ -74,6 +74,12 @@ breakpad_backend_callback(const google_breakpad::MinidumpDescriptor &descriptor, void *UNUSED(context), bool succeeded) #endif { + SENTRY_WITH_OPTIONS (options) { + if (options->before_crash_func) { + options->before_crash_func(options->before_crash_data); + } + } + SENTRY_INFO("entering breakpad minidump callback"); // this is a bit strange, according to docs, `succeeded` should be true when diff --git a/src/backends/sentry_backend_crashpad.cpp b/src/backends/sentry_backend_crashpad.cpp index c3552d475..f78e411a5 100644 --- a/src/backends/sentry_backend_crashpad.cpp +++ b/src/backends/sentry_backend_crashpad.cpp @@ -280,6 +280,13 @@ sentry__crashpad_handler(int signum, siginfo_t *info, ucontext_t *user_context) { sentry__page_allocator_enable(); # endif + + SENTRY_WITH_OPTIONS (options) { + if (options->before_crash_func) { + options->before_crash_func(options->before_crash_data); + } + } + SENTRY_INFO("flushing session and queue before crashpad handler"); bool should_dump = true; diff --git a/src/backends/sentry_backend_inproc.c b/src/backends/sentry_backend_inproc.c index c2ee95fa0..723db751d 100644 --- a/src/backends/sentry_backend_inproc.c +++ b/src/backends/sentry_backend_inproc.c @@ -523,6 +523,12 @@ make_signal_event( static void handle_ucontext(const sentry_ucontext_t *uctx) { + SENTRY_WITH_OPTIONS (options) { + if (options->before_crash_func) { + options->before_crash_func(options->before_crash_data); + } + } + SENTRY_INFO("entering signal handler"); const struct signal_slot *sig_slot = NULL; diff --git a/src/sentry_options.c b/src/sentry_options.c index 23eaef2b4..9b791674f 100644 --- a/src/sentry_options.c +++ b/src/sentry_options.c @@ -137,6 +137,14 @@ sentry_options_set_before_send( opts->before_send_data = user_data; } +void +sentry_options_set_before_crash(sentry_options_t *opts, + sentry_before_crash_function_t func, void *user_data) +{ + opts->before_crash_func = func; + opts->before_crash_data = user_data; +} + void sentry_options_set_on_crash( sentry_options_t *opts, sentry_crash_function_t func, void *user_data) diff --git a/src/sentry_options.h b/src/sentry_options.h index 5316b69e5..c34051017 100644 --- a/src/sentry_options.h +++ b/src/sentry_options.h @@ -52,6 +52,8 @@ struct sentry_options_s { void *on_crash_data; sentry_transaction_function_t before_transaction_func; void *before_transaction_data; + sentry_before_crash_function_t before_crash_func; + void *before_crash_data; /* Experimentally exposed */ double traces_sample_rate; From b878cb0f41e26173976800bb6f9134ba64637a45 Mon Sep 17 00:00:00 2001 From: Amir Mujacic Date: Tue, 9 Sep 2025 12:30:25 +0200 Subject: [PATCH 02/12] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8bab372c..1c5554ce8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ **Internal:** - Support downstream Xbox SDK specifying networking initialization mechanism ([#1359](https://github.com/getsentry/sentry-native/pull/1359)) +- Add before crash hook to allow modifying other callbacks before crash handling ([#1366](https://github.com/getsentry/sentry-native/pull/1366)) ## 0.10.1 From 9ed2beabe1bef5d96733c27285b429b708d1dd08 Mon Sep 17 00:00:00 2001 From: Amir Mujacic Date: Thu, 11 Sep 2025 08:43:38 +0200 Subject: [PATCH 03/12] Add unit test --- tests/unit/test_before_crash.c | 157 +++++++++++++++++++++++++++++++++ tests/unit/tests.inc | 13 ++- 2 files changed, 166 insertions(+), 4 deletions(-) create mode 100644 tests/unit/test_before_crash.c diff --git a/tests/unit/test_before_crash.c b/tests/unit/test_before_crash.c new file mode 100644 index 000000000..0c43b07a6 --- /dev/null +++ b/tests/unit/test_before_crash.c @@ -0,0 +1,157 @@ +#include "sentry_backend.h" +#include "sentry_core.h" +#include "sentry_testsupport.h" +#include + +static volatile bool g_before_crash_called = false; +static volatile int g_before_crash_call_count = 0; +static volatile void *g_before_crash_user_data = NULL; + +static void +test_before_crash_func(void *user_data) +{ + g_before_crash_called = true; + g_before_crash_call_count++; + g_before_crash_user_data = user_data; +} + +static void +reset_before_crash_state(void) +{ + g_before_crash_called = false; + g_before_crash_call_count = 0; + g_before_crash_user_data = NULL; +} + +// Test helper to trigger a crash and verify before_crash_func is called +static void +trigger_crash_and_verify(const char *backend_name, void *user_data_marker) +{ + reset_before_crash_state(); + + SENTRY_TEST_OPTIONS_NEW(options); + sentry_options_set_dsn(options, "https://foo@sentry.invalid/42"); + sentry_options_set_before_crash( + options, test_before_crash_func, user_data_marker); + + // Disable auto session tracking to avoid interference + sentry_options_set_auto_session_tracking(options, false); + + // Initialize with the current backend + TEST_CHECK_INT_EQUAL(sentry_init(options), 0); + + // Trigger a crash using sentry_capture_exception + // This simulates a crash without actually crashing the test + sentry_ucontext_t uctx = { 0 }; + + SENTRY_WITH_OPTIONS (opts) { + if (opts->backend && opts->backend->except_func) { + opts->backend->except_func(opts->backend, &uctx); + } + } + + sentry_close(); + + // Verify the before_crash_func was called + TEST_CHECK_MSG(g_before_crash_called, + "before_crash_func should be called with %s backend", backend_name); + TEST_CHECK_INT_EQUAL_MSG(g_before_crash_call_count, 1, + "before_crash_func should be called exactly once with %s backend", + backend_name); + TEST_CHECK_MSG(g_before_crash_user_data == user_data_marker, + "before_crash_func should receive correct user_data with %s backend", + backend_name); +} + +SENTRY_TEST(before_crash_func_crashpad) +{ +#ifdef SENTRY_BACKEND_CRASHPAD + void *marker = (void *)0x12345678; + trigger_crash_and_verify("crashpad", marker); +#else + TEST_SKIP("Crashpad backend not available in this build"); +#endif +} + +SENTRY_TEST(before_crash_func_breakpad) +{ +#ifdef SENTRY_BACKEND_BREAKPAD + void *marker = (void *)0x87654321; + trigger_crash_and_verify("breakpad", marker); +#else + TEST_SKIP("Breakpad backend not available in this build"); +#endif +} + +SENTRY_TEST(before_crash_func_inproc) +{ +#ifdef SENTRY_BACKEND_INPROC + void *marker = (void *)0xABCDEF00; + trigger_crash_and_verify("inproc", marker); +#else + TEST_SKIP("In-process backend not available in this build"); +#endif +} + +// Test that before_crash_func is not called when not set +SENTRY_TEST(before_crash_func_not_set) +{ + reset_before_crash_state(); + + SENTRY_TEST_OPTIONS_NEW(options); + sentry_options_set_dsn(options, "https://foo@sentry.invalid/42"); + // Do not set before_crash_func + sentry_options_set_auto_session_tracking(options, false); + + TEST_CHECK_INT_EQUAL(sentry_init(options), 0); + + // Trigger a crash + sentry_ucontext_t uctx = { 0 }; + SENTRY_WITH_OPTIONS (opts) { + if (opts->backend && opts->backend->except_func) { + opts->backend->except_func(opts->backend, &uctx); + } + } + + sentry_close(); + + // Verify the before_crash_func was NOT called + TEST_CHECK_MSG(!g_before_crash_called, + "before_crash_func should not be called when not set"); + TEST_CHECK_INT_EQUAL(g_before_crash_call_count, 0); +} + +// Test that before_crash_func can be changed +SENTRY_TEST(before_crash_func_change) +{ + reset_before_crash_state(); + + SENTRY_TEST_OPTIONS_NEW(options); + sentry_options_set_dsn(options, "https://foo@sentry.invalid/42"); + + // Set initial before_crash_func + void *marker1 = (void *)0x11111111; + sentry_options_set_before_crash(options, test_before_crash_func, marker1); + + // Change to different user data + void *marker2 = (void *)0x22222222; + sentry_options_set_before_crash(options, test_before_crash_func, marker2); + + sentry_options_set_auto_session_tracking(options, false); + TEST_CHECK_INT_EQUAL(sentry_init(options), 0); + + // Trigger a crash + sentry_ucontext_t uctx = { 0 }; + SENTRY_WITH_OPTIONS (opts) { + if (opts->backend && opts->backend->except_func) { + opts->backend->except_func(opts->backend, &uctx); + } + } + + sentry_close(); + + // Verify the updated user_data was used + TEST_CHECK(g_before_crash_called); + TEST_CHECK_MSG(g_before_crash_user_data == marker2, + "before_crash_func should use the updated user_data"); +} diff --git a/tests/unit/tests.inc b/tests/unit/tests.inc index 152bd293c..271bfd9c1 100644 --- a/tests/unit/tests.inc +++ b/tests/unit/tests.inc @@ -21,6 +21,11 @@ XX(basic_spans) XX(basic_tracing_context) XX(basic_transaction) XX(basic_write_envelope_to_file) +XX(before_crash_func_breakpad) +XX(before_crash_func_change) +XX(before_crash_func_crashpad) +XX(before_crash_func_inproc) +XX(before_crash_func_not_set) XX(bgworker_flush) XX(breadcrumb_without_type_or_message_still_valid) XX(build_id_parser) @@ -67,6 +72,10 @@ XX(dsn_with_ending_forward_slash_will_be_cleaned) XX(dsn_with_non_http_scheme_is_invalid) XX(dsn_without_project_id_is_invalid) XX(dsn_without_url_scheme_is_invalid) +XX(embedded_info_basic) +XX(embedded_info_disabled) +XX(embedded_info_format) +XX(embedded_info_sentry_version) XX(empty_transport) XX(event_with_id) XX(exception_without_type_or_value_still_valid) @@ -204,7 +213,3 @@ XX(value_unicode) XX(value_user) XX(value_wrong_type) XX(write_raw_envelope_to_file) -XX(embedded_info_basic) -XX(embedded_info_disabled) -XX(embedded_info_format) -XX(embedded_info_sentry_version) From 6e92d72474c16954c4bea09ac3fbdaa9eb7178a6 Mon Sep 17 00:00:00 2001 From: Amir Mujacic Date: Thu, 11 Sep 2025 08:52:23 +0200 Subject: [PATCH 04/12] Simplify the test --- tests/unit/test_before_crash.c | 135 ++++++++++++++++++++------------- 1 file changed, 82 insertions(+), 53 deletions(-) diff --git a/tests/unit/test_before_crash.c b/tests/unit/test_before_crash.c index 0c43b07a6..ff634be49 100644 --- a/tests/unit/test_before_crash.c +++ b/tests/unit/test_before_crash.c @@ -1,5 +1,3 @@ -#include "sentry_backend.h" -#include "sentry_core.h" #include "sentry_testsupport.h" #include @@ -23,77 +21,111 @@ reset_before_crash_state(void) g_before_crash_user_data = NULL; } -// Test helper to trigger a crash and verify before_crash_func is called -static void -trigger_crash_and_verify(const char *backend_name, void *user_data_marker) +SENTRY_TEST(before_crash_func_crashpad) { +#ifdef SENTRY_BACKEND_CRASHPAD reset_before_crash_state(); + void *marker = (void *)0x12345678; SENTRY_TEST_OPTIONS_NEW(options); sentry_options_set_dsn(options, "https://foo@sentry.invalid/42"); - sentry_options_set_before_crash( - options, test_before_crash_func, user_data_marker); - - // Disable auto session tracking to avoid interference + sentry_options_set_before_crash(options, test_before_crash_func, marker); sentry_options_set_auto_session_tracking(options, false); - // Initialize with the current backend TEST_CHECK_INT_EQUAL(sentry_init(options), 0); - // Trigger a crash using sentry_capture_exception - // This simulates a crash without actually crashing the test - sentry_ucontext_t uctx = { 0 }; - + // Verify before_crash_func is set correctly in options SENTRY_WITH_OPTIONS (opts) { - if (opts->backend && opts->backend->except_func) { - opts->backend->except_func(opts->backend, &uctx); + TEST_CHECK(opts->before_crash_func == test_before_crash_func); + TEST_CHECK(opts->before_crash_data == marker); + + // Call the before_crash_func directly to test it + if (opts->before_crash_func) { + opts->before_crash_func(opts->before_crash_data); } } sentry_close(); - // Verify the before_crash_func was called - TEST_CHECK_MSG(g_before_crash_called, - "before_crash_func should be called with %s backend", backend_name); - TEST_CHECK_INT_EQUAL_MSG(g_before_crash_call_count, 1, - "before_crash_func should be called exactly once with %s backend", - backend_name); - TEST_CHECK_MSG(g_before_crash_user_data == user_data_marker, - "before_crash_func should receive correct user_data with %s backend", - backend_name); -} - -SENTRY_TEST(before_crash_func_crashpad) -{ -#ifdef SENTRY_BACKEND_CRASHPAD - void *marker = (void *)0x12345678; - trigger_crash_and_verify("crashpad", marker); + // Verify the before_crash_func was called correctly + TEST_CHECK(g_before_crash_called); + TEST_CHECK_INT_EQUAL(g_before_crash_call_count, 1); + TEST_CHECK(g_before_crash_user_data == marker); #else - TEST_SKIP("Crashpad backend not available in this build"); + SKIP_TEST(); #endif } SENTRY_TEST(before_crash_func_breakpad) { #ifdef SENTRY_BACKEND_BREAKPAD + reset_before_crash_state(); + void *marker = (void *)0x87654321; - trigger_crash_and_verify("breakpad", marker); + SENTRY_TEST_OPTIONS_NEW(options); + sentry_options_set_dsn(options, "https://foo@sentry.invalid/42"); + sentry_options_set_before_crash(options, test_before_crash_func, marker); + sentry_options_set_auto_session_tracking(options, false); + + TEST_CHECK_INT_EQUAL(sentry_init(options), 0); + + // Verify before_crash_func is set correctly in options + SENTRY_WITH_OPTIONS (opts) { + TEST_CHECK(opts->before_crash_func == test_before_crash_func); + TEST_CHECK(opts->before_crash_data == marker); + + // Call the before_crash_func directly to test it + if (opts->before_crash_func) { + opts->before_crash_func(opts->before_crash_data); + } + } + + sentry_close(); + + // Verify the before_crash_func was called correctly + TEST_CHECK(g_before_crash_called); + TEST_CHECK_INT_EQUAL(g_before_crash_call_count, 1); + TEST_CHECK(g_before_crash_user_data == marker); #else - TEST_SKIP("Breakpad backend not available in this build"); + SKIP_TEST(); #endif } SENTRY_TEST(before_crash_func_inproc) { #ifdef SENTRY_BACKEND_INPROC + reset_before_crash_state(); + void *marker = (void *)0xABCDEF00; - trigger_crash_and_verify("inproc", marker); + SENTRY_TEST_OPTIONS_NEW(options); + sentry_options_set_dsn(options, "https://foo@sentry.invalid/42"); + sentry_options_set_before_crash(options, test_before_crash_func, marker); + sentry_options_set_auto_session_tracking(options, false); + + TEST_CHECK_INT_EQUAL(sentry_init(options), 0); + + // Verify before_crash_func is set correctly in options + SENTRY_WITH_OPTIONS (opts) { + TEST_CHECK(opts->before_crash_func == test_before_crash_func); + TEST_CHECK(opts->before_crash_data == marker); + + // Call the before_crash_func directly to test it + if (opts->before_crash_func) { + opts->before_crash_func(opts->before_crash_data); + } + } + + sentry_close(); + + // Verify the before_crash_func was called correctly + TEST_CHECK(g_before_crash_called); + TEST_CHECK_INT_EQUAL(g_before_crash_call_count, 1); + TEST_CHECK(g_before_crash_user_data == marker); #else - TEST_SKIP("In-process backend not available in this build"); + SKIP_TEST(); #endif } -// Test that before_crash_func is not called when not set SENTRY_TEST(before_crash_func_not_set) { reset_before_crash_state(); @@ -105,23 +137,18 @@ SENTRY_TEST(before_crash_func_not_set) TEST_CHECK_INT_EQUAL(sentry_init(options), 0); - // Trigger a crash - sentry_ucontext_t uctx = { 0 }; + // Verify before_crash_func is not set SENTRY_WITH_OPTIONS (opts) { - if (opts->backend && opts->backend->except_func) { - opts->backend->except_func(opts->backend, &uctx); - } + TEST_CHECK(opts->before_crash_func == NULL); } sentry_close(); - // Verify the before_crash_func was NOT called - TEST_CHECK_MSG(!g_before_crash_called, - "before_crash_func should not be called when not set"); + // Verify the before_crash_func was not called + TEST_CHECK(!g_before_crash_called); TEST_CHECK_INT_EQUAL(g_before_crash_call_count, 0); } -// Test that before_crash_func can be changed SENTRY_TEST(before_crash_func_change) { reset_before_crash_state(); @@ -140,11 +167,14 @@ SENTRY_TEST(before_crash_func_change) sentry_options_set_auto_session_tracking(options, false); TEST_CHECK_INT_EQUAL(sentry_init(options), 0); - // Trigger a crash - sentry_ucontext_t uctx = { 0 }; + // Verify the updated user_data is set SENTRY_WITH_OPTIONS (opts) { - if (opts->backend && opts->backend->except_func) { - opts->backend->except_func(opts->backend, &uctx); + TEST_CHECK(opts->before_crash_func == test_before_crash_func); + TEST_CHECK(opts->before_crash_data == marker2); + + // Call the before_crash_func to test it + if (opts->before_crash_func) { + opts->before_crash_func(opts->before_crash_data); } } @@ -152,6 +182,5 @@ SENTRY_TEST(before_crash_func_change) // Verify the updated user_data was used TEST_CHECK(g_before_crash_called); - TEST_CHECK_MSG(g_before_crash_user_data == marker2, - "before_crash_func should use the updated user_data"); + TEST_CHECK(g_before_crash_user_data == marker2); } From 09aaa2f0092b9c93f6808110c075225c6b9786b3 Mon Sep 17 00:00:00 2001 From: Amir Mujacic Date: Thu, 11 Sep 2025 08:56:30 +0200 Subject: [PATCH 05/12] Refactor the test, update CMakeLists --- tests/unit/CMakeLists.txt | 1 + tests/unit/test_before_crash.c | 90 +++++++++------------------------- 2 files changed, 25 insertions(+), 66 deletions(-) diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index 9add26e97..f8f746357 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -23,6 +23,7 @@ add_executable(sentry_test_unit sentry_testsupport.h test_attachments.c test_basic.c + test_before_crash.c test_consent.c test_concurrency.c test_embedded_info.c diff --git a/tests/unit/test_before_crash.c b/tests/unit/test_before_crash.c index ff634be49..0a155d52d 100644 --- a/tests/unit/test_before_crash.c +++ b/tests/unit/test_before_crash.c @@ -21,15 +21,14 @@ reset_before_crash_state(void) g_before_crash_user_data = NULL; } -SENTRY_TEST(before_crash_func_crashpad) +static void +test_before_crash_common(void *user_data) { -#ifdef SENTRY_BACKEND_CRASHPAD reset_before_crash_state(); - void *marker = (void *)0x12345678; SENTRY_TEST_OPTIONS_NEW(options); sentry_options_set_dsn(options, "https://foo@sentry.invalid/42"); - sentry_options_set_before_crash(options, test_before_crash_func, marker); + sentry_options_set_before_crash(options, test_before_crash_func, user_data); sentry_options_set_auto_session_tracking(options, false); TEST_CHECK_INT_EQUAL(sentry_init(options), 0); @@ -37,7 +36,7 @@ SENTRY_TEST(before_crash_func_crashpad) // Verify before_crash_func is set correctly in options SENTRY_WITH_OPTIONS (opts) { TEST_CHECK(opts->before_crash_func == test_before_crash_func); - TEST_CHECK(opts->before_crash_data == marker); + TEST_CHECK(opts->before_crash_data == user_data); // Call the before_crash_func directly to test it if (opts->before_crash_func) { @@ -50,7 +49,14 @@ SENTRY_TEST(before_crash_func_crashpad) // Verify the before_crash_func was called correctly TEST_CHECK(g_before_crash_called); TEST_CHECK_INT_EQUAL(g_before_crash_call_count, 1); - TEST_CHECK(g_before_crash_user_data == marker); + TEST_CHECK(g_before_crash_user_data == user_data); +} + +SENTRY_TEST(before_crash_func_crashpad) +{ +#ifdef SENTRY_BACKEND_CRASHPAD + void *user_data = (void *)0x12345678; + test_before_crash_common(user_data); #else SKIP_TEST(); #endif @@ -59,33 +65,8 @@ SENTRY_TEST(before_crash_func_crashpad) SENTRY_TEST(before_crash_func_breakpad) { #ifdef SENTRY_BACKEND_BREAKPAD - reset_before_crash_state(); - - void *marker = (void *)0x87654321; - SENTRY_TEST_OPTIONS_NEW(options); - sentry_options_set_dsn(options, "https://foo@sentry.invalid/42"); - sentry_options_set_before_crash(options, test_before_crash_func, marker); - sentry_options_set_auto_session_tracking(options, false); - - TEST_CHECK_INT_EQUAL(sentry_init(options), 0); - - // Verify before_crash_func is set correctly in options - SENTRY_WITH_OPTIONS (opts) { - TEST_CHECK(opts->before_crash_func == test_before_crash_func); - TEST_CHECK(opts->before_crash_data == marker); - - // Call the before_crash_func directly to test it - if (opts->before_crash_func) { - opts->before_crash_func(opts->before_crash_data); - } - } - - sentry_close(); - - // Verify the before_crash_func was called correctly - TEST_CHECK(g_before_crash_called); - TEST_CHECK_INT_EQUAL(g_before_crash_call_count, 1); - TEST_CHECK(g_before_crash_user_data == marker); + void *user_data = (void *)0x87654321; + test_before_crash_common(user_data); #else SKIP_TEST(); #endif @@ -94,33 +75,8 @@ SENTRY_TEST(before_crash_func_breakpad) SENTRY_TEST(before_crash_func_inproc) { #ifdef SENTRY_BACKEND_INPROC - reset_before_crash_state(); - - void *marker = (void *)0xABCDEF00; - SENTRY_TEST_OPTIONS_NEW(options); - sentry_options_set_dsn(options, "https://foo@sentry.invalid/42"); - sentry_options_set_before_crash(options, test_before_crash_func, marker); - sentry_options_set_auto_session_tracking(options, false); - - TEST_CHECK_INT_EQUAL(sentry_init(options), 0); - - // Verify before_crash_func is set correctly in options - SENTRY_WITH_OPTIONS (opts) { - TEST_CHECK(opts->before_crash_func == test_before_crash_func); - TEST_CHECK(opts->before_crash_data == marker); - - // Call the before_crash_func directly to test it - if (opts->before_crash_func) { - opts->before_crash_func(opts->before_crash_data); - } - } - - sentry_close(); - - // Verify the before_crash_func was called correctly - TEST_CHECK(g_before_crash_called); - TEST_CHECK_INT_EQUAL(g_before_crash_call_count, 1); - TEST_CHECK(g_before_crash_user_data == marker); + void *user_data = (void *)0xABCDEF00; + test_before_crash_common(user_data); #else SKIP_TEST(); #endif @@ -157,12 +113,14 @@ SENTRY_TEST(before_crash_func_change) sentry_options_set_dsn(options, "https://foo@sentry.invalid/42"); // Set initial before_crash_func - void *marker1 = (void *)0x11111111; - sentry_options_set_before_crash(options, test_before_crash_func, marker1); + void *user_data1 = (void *)0x11111111; + sentry_options_set_before_crash( + options, test_before_crash_func, user_data1); // Change to different user data - void *marker2 = (void *)0x22222222; - sentry_options_set_before_crash(options, test_before_crash_func, marker2); + void *user_data2 = (void *)0x22222222; + sentry_options_set_before_crash( + options, test_before_crash_func, user_data2); sentry_options_set_auto_session_tracking(options, false); TEST_CHECK_INT_EQUAL(sentry_init(options), 0); @@ -170,7 +128,7 @@ SENTRY_TEST(before_crash_func_change) // Verify the updated user_data is set SENTRY_WITH_OPTIONS (opts) { TEST_CHECK(opts->before_crash_func == test_before_crash_func); - TEST_CHECK(opts->before_crash_data == marker2); + TEST_CHECK(opts->before_crash_data == user_data2); // Call the before_crash_func to test it if (opts->before_crash_func) { @@ -182,5 +140,5 @@ SENTRY_TEST(before_crash_func_change) // Verify the updated user_data was used TEST_CHECK(g_before_crash_called); - TEST_CHECK(g_before_crash_user_data == marker2); + TEST_CHECK(g_before_crash_user_data == user_data2); } From 13749ed641f3f03b658fd5cc13b018bfab35746a Mon Sep 17 00:00:00 2001 From: Amir Mujacic Date: Thu, 11 Sep 2025 09:02:44 +0200 Subject: [PATCH 06/12] Refactor vol 3 --- tests/unit/test_before_crash.c | 70 +++++++++------------------------- tests/unit/tests.inc | 4 +- 2 files changed, 19 insertions(+), 55 deletions(-) diff --git a/tests/unit/test_before_crash.c b/tests/unit/test_before_crash.c index 0a155d52d..37cecbe10 100644 --- a/tests/unit/test_before_crash.c +++ b/tests/unit/test_before_crash.c @@ -1,3 +1,5 @@ +#include "sentry_core.h" +#include "sentry_options.h" #include "sentry_testsupport.h" #include @@ -21,27 +23,25 @@ reset_before_crash_state(void) g_before_crash_user_data = NULL; } -static void -test_before_crash_common(void *user_data) +SENTRY_TEST(before_crash_func_call) { reset_before_crash_state(); SENTRY_TEST_OPTIONS_NEW(options); sentry_options_set_dsn(options, "https://foo@sentry.invalid/42"); - sentry_options_set_before_crash(options, test_before_crash_func, user_data); + sentry_options_set_before_crash( + options, test_before_crash_func, 0xDEADC0DE); sentry_options_set_auto_session_tracking(options, false); TEST_CHECK_INT_EQUAL(sentry_init(options), 0); // Verify before_crash_func is set correctly in options - SENTRY_WITH_OPTIONS (opts) { - TEST_CHECK(opts->before_crash_func == test_before_crash_func); - TEST_CHECK(opts->before_crash_data == user_data); - - // Call the before_crash_func directly to test it - if (opts->before_crash_func) { - opts->before_crash_func(opts->before_crash_data); - } + TEST_CHECK(options->before_crash_func == test_before_crash_func); + TEST_CHECK(options->before_crash_data == user_data); + + // Call the before_crash_func directly to test it + if (options->before_crash_func) { + options->before_crash_func(options->before_crash_data); } sentry_close(); @@ -52,36 +52,6 @@ test_before_crash_common(void *user_data) TEST_CHECK(g_before_crash_user_data == user_data); } -SENTRY_TEST(before_crash_func_crashpad) -{ -#ifdef SENTRY_BACKEND_CRASHPAD - void *user_data = (void *)0x12345678; - test_before_crash_common(user_data); -#else - SKIP_TEST(); -#endif -} - -SENTRY_TEST(before_crash_func_breakpad) -{ -#ifdef SENTRY_BACKEND_BREAKPAD - void *user_data = (void *)0x87654321; - test_before_crash_common(user_data); -#else - SKIP_TEST(); -#endif -} - -SENTRY_TEST(before_crash_func_inproc) -{ -#ifdef SENTRY_BACKEND_INPROC - void *user_data = (void *)0xABCDEF00; - test_before_crash_common(user_data); -#else - SKIP_TEST(); -#endif -} - SENTRY_TEST(before_crash_func_not_set) { reset_before_crash_state(); @@ -94,9 +64,7 @@ SENTRY_TEST(before_crash_func_not_set) TEST_CHECK_INT_EQUAL(sentry_init(options), 0); // Verify before_crash_func is not set - SENTRY_WITH_OPTIONS (opts) { - TEST_CHECK(opts->before_crash_func == NULL); - } + TEST_CHECK(options->before_crash_func == NULL); sentry_close(); @@ -126,14 +94,12 @@ SENTRY_TEST(before_crash_func_change) TEST_CHECK_INT_EQUAL(sentry_init(options), 0); // Verify the updated user_data is set - SENTRY_WITH_OPTIONS (opts) { - TEST_CHECK(opts->before_crash_func == test_before_crash_func); - TEST_CHECK(opts->before_crash_data == user_data2); - - // Call the before_crash_func to test it - if (opts->before_crash_func) { - opts->before_crash_func(opts->before_crash_data); - } + TEST_CHECK(options->before_crash_func == test_before_crash_func); + TEST_CHECK(options->before_crash_data == user_data2); + + // Call the before_crash_func to test it + if (options->before_crash_func) { + options->before_crash_func(options->before_crash_data); } sentry_close(); diff --git a/tests/unit/tests.inc b/tests/unit/tests.inc index 271bfd9c1..6a5b17e11 100644 --- a/tests/unit/tests.inc +++ b/tests/unit/tests.inc @@ -21,10 +21,8 @@ XX(basic_spans) XX(basic_tracing_context) XX(basic_transaction) XX(basic_write_envelope_to_file) -XX(before_crash_func_breakpad) +XX(before_crash_func_call) XX(before_crash_func_change) -XX(before_crash_func_crashpad) -XX(before_crash_func_inproc) XX(before_crash_func_not_set) XX(bgworker_flush) XX(breadcrumb_without_type_or_message_still_valid) From 5af77a2360616dcd3d77a92caf388b98ff40e8b2 Mon Sep 17 00:00:00 2001 From: Amir Mujacic Date: Thu, 11 Sep 2025 09:04:08 +0200 Subject: [PATCH 07/12] Fix user_data --- tests/unit/test_before_crash.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/test_before_crash.c b/tests/unit/test_before_crash.c index 37cecbe10..6ffed7b6f 100644 --- a/tests/unit/test_before_crash.c +++ b/tests/unit/test_before_crash.c @@ -25,12 +25,12 @@ reset_before_crash_state(void) SENTRY_TEST(before_crash_func_call) { + void *user_data = (void *)0xDEADC0DE; reset_before_crash_state(); SENTRY_TEST_OPTIONS_NEW(options); sentry_options_set_dsn(options, "https://foo@sentry.invalid/42"); - sentry_options_set_before_crash( - options, test_before_crash_func, 0xDEADC0DE); + sentry_options_set_before_crash(options, test_before_crash_func, user_data); sentry_options_set_auto_session_tracking(options, false); TEST_CHECK_INT_EQUAL(sentry_init(options), 0); From 38f71ca4f1e3b2c285f0c89ae47376e3436020ad Mon Sep 17 00:00:00 2001 From: Amir Mujacic Date: Thu, 11 Sep 2025 09:30:08 +0200 Subject: [PATCH 08/12] Fix type conversion --- tests/unit/test_before_crash.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/unit/test_before_crash.c b/tests/unit/test_before_crash.c index 6ffed7b6f..24e3376c3 100644 --- a/tests/unit/test_before_crash.c +++ b/tests/unit/test_before_crash.c @@ -2,6 +2,7 @@ #include "sentry_options.h" #include "sentry_testsupport.h" #include +#include static volatile bool g_before_crash_called = false; static volatile int g_before_crash_call_count = 0; @@ -25,7 +26,7 @@ reset_before_crash_state(void) SENTRY_TEST(before_crash_func_call) { - void *user_data = (void *)0xDEADC0DE; + void *user_data = (void *)(uintptr_t)0xDEADC0DE; reset_before_crash_state(); SENTRY_TEST_OPTIONS_NEW(options); @@ -81,12 +82,12 @@ SENTRY_TEST(before_crash_func_change) sentry_options_set_dsn(options, "https://foo@sentry.invalid/42"); // Set initial before_crash_func - void *user_data1 = (void *)0x11111111; + void *user_data1 = (void *)(uintptr_t)0x11111111; sentry_options_set_before_crash( options, test_before_crash_func, user_data1); // Change to different user data - void *user_data2 = (void *)0x22222222; + void *user_data2 = (void *)(uintptr_t)0x22222222; sentry_options_set_before_crash( options, test_before_crash_func, user_data2); From b0ed4fbd9c2273ac7346573b36c01f0363a7ebc0 Mon Sep 17 00:00:00 2001 From: Amir Mujacic Date: Thu, 11 Sep 2025 10:05:59 +0200 Subject: [PATCH 09/12] Fix includes --- tests/unit/test_before_crash.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/unit/test_before_crash.c b/tests/unit/test_before_crash.c index 24e3376c3..9318a95de 100644 --- a/tests/unit/test_before_crash.c +++ b/tests/unit/test_before_crash.c @@ -2,7 +2,6 @@ #include "sentry_options.h" #include "sentry_testsupport.h" #include -#include static volatile bool g_before_crash_called = false; static volatile int g_before_crash_call_count = 0; @@ -26,7 +25,7 @@ reset_before_crash_state(void) SENTRY_TEST(before_crash_func_call) { - void *user_data = (void *)(uintptr_t)0xDEADC0DE; + void *user_data = (void *)1; reset_before_crash_state(); SENTRY_TEST_OPTIONS_NEW(options); @@ -82,12 +81,12 @@ SENTRY_TEST(before_crash_func_change) sentry_options_set_dsn(options, "https://foo@sentry.invalid/42"); // Set initial before_crash_func - void *user_data1 = (void *)(uintptr_t)0x11111111; + void *user_data1 = (void *)2; sentry_options_set_before_crash( options, test_before_crash_func, user_data1); // Change to different user data - void *user_data2 = (void *)(uintptr_t)0x22222222; + void *user_data2 = (void *)3; sentry_options_set_before_crash( options, test_before_crash_func, user_data2); From 4a99e8265cf2d5931e170e824e91f982b2b2de20 Mon Sep 17 00:00:00 2001 From: Amir Mujacic Date: Thu, 11 Sep 2025 10:33:53 +0200 Subject: [PATCH 10/12] Revert test changes This reverts commit b0ed4fbd9c2273ac7346573b36c01f0363a7ebc0. --- tests/unit/test_before_crash.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/unit/test_before_crash.c b/tests/unit/test_before_crash.c index 9318a95de..24e3376c3 100644 --- a/tests/unit/test_before_crash.c +++ b/tests/unit/test_before_crash.c @@ -2,6 +2,7 @@ #include "sentry_options.h" #include "sentry_testsupport.h" #include +#include static volatile bool g_before_crash_called = false; static volatile int g_before_crash_call_count = 0; @@ -25,7 +26,7 @@ reset_before_crash_state(void) SENTRY_TEST(before_crash_func_call) { - void *user_data = (void *)1; + void *user_data = (void *)(uintptr_t)0xDEADC0DE; reset_before_crash_state(); SENTRY_TEST_OPTIONS_NEW(options); @@ -81,12 +82,12 @@ SENTRY_TEST(before_crash_func_change) sentry_options_set_dsn(options, "https://foo@sentry.invalid/42"); // Set initial before_crash_func - void *user_data1 = (void *)2; + void *user_data1 = (void *)(uintptr_t)0x11111111; sentry_options_set_before_crash( options, test_before_crash_func, user_data1); // Change to different user data - void *user_data2 = (void *)3; + void *user_data2 = (void *)(uintptr_t)0x22222222; sentry_options_set_before_crash( options, test_before_crash_func, user_data2); From bb438058def4c44ae4b85af2b4276fa12887b878 Mon Sep 17 00:00:00 2001 From: Amir Mujacic Date: Thu, 11 Sep 2025 10:34:44 +0200 Subject: [PATCH 11/12] Revert "Fix type conversion" This reverts commit 38f71ca4f1e3b2c285f0c89ae47376e3436020ad. --- tests/unit/test_before_crash.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/unit/test_before_crash.c b/tests/unit/test_before_crash.c index 24e3376c3..6ffed7b6f 100644 --- a/tests/unit/test_before_crash.c +++ b/tests/unit/test_before_crash.c @@ -2,7 +2,6 @@ #include "sentry_options.h" #include "sentry_testsupport.h" #include -#include static volatile bool g_before_crash_called = false; static volatile int g_before_crash_call_count = 0; @@ -26,7 +25,7 @@ reset_before_crash_state(void) SENTRY_TEST(before_crash_func_call) { - void *user_data = (void *)(uintptr_t)0xDEADC0DE; + void *user_data = (void *)0xDEADC0DE; reset_before_crash_state(); SENTRY_TEST_OPTIONS_NEW(options); @@ -82,12 +81,12 @@ SENTRY_TEST(before_crash_func_change) sentry_options_set_dsn(options, "https://foo@sentry.invalid/42"); // Set initial before_crash_func - void *user_data1 = (void *)(uintptr_t)0x11111111; + void *user_data1 = (void *)0x11111111; sentry_options_set_before_crash( options, test_before_crash_func, user_data1); // Change to different user data - void *user_data2 = (void *)(uintptr_t)0x22222222; + void *user_data2 = (void *)0x22222222; sentry_options_set_before_crash( options, test_before_crash_func, user_data2); From f53c1468d86bb6dfa58781dd55ae957243f75592 Mon Sep 17 00:00:00 2001 From: Amir Mujacic Date: Thu, 11 Sep 2025 10:37:59 +0200 Subject: [PATCH 12/12] Update pointers --- tests/unit/test_before_crash.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/unit/test_before_crash.c b/tests/unit/test_before_crash.c index 6ffed7b6f..9318a95de 100644 --- a/tests/unit/test_before_crash.c +++ b/tests/unit/test_before_crash.c @@ -25,7 +25,7 @@ reset_before_crash_state(void) SENTRY_TEST(before_crash_func_call) { - void *user_data = (void *)0xDEADC0DE; + void *user_data = (void *)1; reset_before_crash_state(); SENTRY_TEST_OPTIONS_NEW(options); @@ -81,12 +81,12 @@ SENTRY_TEST(before_crash_func_change) sentry_options_set_dsn(options, "https://foo@sentry.invalid/42"); // Set initial before_crash_func - void *user_data1 = (void *)0x11111111; + void *user_data1 = (void *)2; sentry_options_set_before_crash( options, test_before_crash_func, user_data1); // Change to different user data - void *user_data2 = (void *)0x22222222; + void *user_data2 = (void *)3; sentry_options_set_before_crash( options, test_before_crash_func, user_data2);