From a5b395d30fc901619bcdeae25ea6b094d7313ff2 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Tue, 25 Aug 2026 14:50:39 +0200 Subject: [PATCH 1/7] fix!: align last-crash detection with other SDKs Cache the crash state and consume `/last_crash` during `sentry_init()` on non-Android platforms. This prevents the same crash from being reported on every later run when an embedding SDK does not call `sentry_clear_crashed_last_run()`. Keep the marker on Android, because sentry-java reads its timestamp to mark and end the previous native session, then deletes the marker. Removing it during native initialization would lose both the crash evidence and its timestamp: https://github.com/getsentry/sentry-java/blob/1321b401f62077a3f93f6b72d7728a1400d58e04/sentry/src/main/java/io/sentry/PreviousSessionFinalizer.java#L82-L121 Known getsentry downstream callers already clear the marker after initialization or after reading the cached state: - https://github.com/getsentry/sentry-dotnet/blob/44252011b7ec233c165e874a4998a94e83ab5341/src/Sentry/Platforms/Native/CFunctions.cs#L157-L161 - https://github.com/getsentry/sentry-unity/blob/3a8c5122ff02eb68be4c0de268ee04507bf2ddbd/src/Sentry.Unity.Native/SentryNativeBridge.cs#L142-L146 - https://github.com/getsentry/sentry-unreal/blob/5d255bce9185a7437ff5497281d2822b76dbe30b/plugin-dev/Source/Sentry/Private/GenericPlatform/GenericPlatformSentrySubsystem.cpp#L697-L703 Close: #1325 --- CHANGELOG.md | 6 ++++++ include/sentry.h | 9 +++++---- src/sentry_core.c | 6 ++++++ tests/assertions.py | 7 +++++-- tests/test_integration_crashpad.py | 6 +++++- tests/test_integration_http.py | 4 ++++ tests/test_integration_native.py | 5 +++++ tests/test_integration_stdout.py | 25 ++++++++++++------------- tests/unit/test_basic.c | 9 ++++++++- 9 files changed, 56 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f229833ef..6e141db38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## Unreleased +**Breaking / Important behavior changes**: + +- `sentry_init()` now consumes `/last_crash` after caching its value, except on Android. `sentry_clear_crashed_last_run()` is no longer required elsewhere. ([#1325](https://github.com/getsentry/sentry-native/issues/1325)) + +## Unreleased + **Features**: - Windows: report WINE and Proton metadata in a separate runtime context. ([#1995](https://github.com/getsentry/sentry-native/pull/1995)) diff --git a/include/sentry.h b/include/sentry.h index 9f345b50a..1ee5fe783 100644 --- a/include/sentry.h +++ b/include/sentry.h @@ -4209,7 +4209,8 @@ SENTRY_EXPERIMENTAL_API void sentry_transaction_iter_headers( * * Notes: * * The underlying value is set by sentry_init() - it must be called first. - * * Call sentry_clear_crashed_last_run() to reset for the next app run. + * * sentry_init() clears the persisted value for the next run except on + * Android, where it must be cleared explicitly. * * Possible return values: * 1 = the last run was a crash @@ -4219,9 +4220,9 @@ SENTRY_EXPERIMENTAL_API void sentry_transaction_iter_headers( SENTRY_EXPERIMENTAL_API int sentry_get_crashed_last_run(void); /** - * Clear the status of the "crashed-last-run". You should explicitly call - * this after sentry_init() if you're using sentry_get_crashed_last_run(). - * Otherwise, the same information is reported on any subsequent runs. + * Clear the persisted status of the "crashed-last-run". + * + * Calling this function is only required on Android. * * Notes: * * This doesn't change the value of sentry_get_crashed_last_run() yet. diff --git a/src/sentry_core.c b/src/sentry_core.c index 09d870aed..55929795a 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -238,6 +238,12 @@ sentry_init(sentry_options_t *options) } g_last_crash = sentry__has_crash_marker(options); + // Android SDK needs the marker timestamp for session finalization +#if !defined(SENTRY_PLATFORM_ANDROID) + if (g_last_crash) { + sentry__clear_crash_marker(options); + } +#endif g_options = options; // *after* setting the global options, trigger a scope and consent flush, diff --git a/tests/assertions.py b/tests/assertions.py index c78584633..7071aca90 100644 --- a/tests/assertions.py +++ b/tests/assertions.py @@ -477,14 +477,17 @@ def assert_native_crash(envelope, exception_code=None): def assert_crash_timestamp(has_files, tmp_path): - # The crash file should survive a `sentry_init` and should still be there - # even after restarts. if has_files: with open("{}/.sentry-native/last_crash".format(tmp_path)) as f: crash_timestamp = f.read() assert_timestamp(crash_timestamp) +def assert_no_crash_timestamp(has_files, tmp_path): + if has_files: + assert not (Path(tmp_path) / ".sentry-native" / "last_crash").exists() + + def assert_before_send(envelope): event = envelope.get_event() assert_matches(event, {"adapted_by": "before_send"}) diff --git a/tests/test_integration_crashpad.py b/tests/test_integration_crashpad.py index d08e7c344..348bb5004 100644 --- a/tests/test_integration_crashpad.py +++ b/tests/test_integration_crashpad.py @@ -21,7 +21,7 @@ lib_name, REPLAY_ID, ) -from .conditions import has_crashpad, has_oom +from .conditions import has_crashpad, has_files, has_oom from .proxy import ( setup_proxy_env_vars, cleanup_proxy_env_vars, @@ -30,6 +30,8 @@ ) from .assertions import ( assert_breadcrumb, + assert_crash_timestamp, + assert_no_crash_timestamp, assert_crashpad_upload, assert_meta, assert_minidump, @@ -100,6 +102,7 @@ def test_crashpad_on_crashed_last_run(cmake): stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) + assert_crash_timestamp(has_files, tmp_path) assert not list((tmp_path / ".sentry-native").glob("*.run/*.crash")) @@ -110,6 +113,7 @@ def test_crashpad_on_crashed_last_run(cmake): stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) + assert_no_crash_timestamp(has_files, tmp_path) callbacks = [ line for line in restarted.stdout.splitlines() diff --git a/tests/test_integration_http.py b/tests/test_integration_http.py index 5cad93f42..ab2cf6e4b 100644 --- a/tests/test_integration_http.py +++ b/tests/test_integration_http.py @@ -33,6 +33,8 @@ assert_user_report, assert_minidump, assert_breakpad_crash, + assert_crash_timestamp, + assert_no_crash_timestamp, assert_gzip_content_encoding, assert_gzip_file_header, assert_attachment_view_hierarchy, @@ -1078,6 +1080,7 @@ def test_on_crashed_last_run(cmake, backend): stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) + assert_crash_timestamp(has_files, tmp_path) run_dirs = list((tmp_path / ".sentry-native").glob("*.run")) assert len(run_dirs) == 1 @@ -1092,6 +1095,7 @@ def test_on_crashed_last_run(cmake, backend): stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) + assert_no_crash_timestamp(has_files, tmp_path) callbacks = [ line for line in restarted.stdout.splitlines() diff --git a/tests/test_integration_native.py b/tests/test_integration_native.py index 143e98fa7..983dcde8c 100644 --- a/tests/test_integration_native.py +++ b/tests/test_integration_native.py @@ -28,6 +28,8 @@ ) from .assertions import ( assert_breadcrumb, + assert_crash_timestamp, + assert_no_crash_timestamp, assert_debug_meta_images_do_not_overlap, assert_meta, assert_native_crash, @@ -38,6 +40,7 @@ wait_for_file, assert_user_feedback, ) +from .conditions import has_files from .conditions import has_native, has_oom, is_asan, is_tsan, is_qemu, is_wine pytestmark = pytest.mark.skipif( @@ -97,6 +100,7 @@ def test_native_on_crashed_last_run(cmake, httpserver): crash_envelope = Envelope.deserialize(httpserver.log[0][0].get_data()) assert_native_crash(crash_envelope) event_id = crash_envelope.headers["event_id"] + assert_crash_timestamp(has_files, tmp_path) db_dir = tmp_path / ".sentry-native" run_dirs = list(db_dir.glob("*.run")) @@ -114,6 +118,7 @@ def test_native_on_crashed_last_run(cmake, httpserver): stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) + assert_no_crash_timestamp(has_files, tmp_path) callbacks = [ line for line in restarted.stdout.splitlines() diff --git a/tests/test_integration_stdout.py b/tests/test_integration_stdout.py index ebb605b50..57d8a6b90 100644 --- a/tests/test_integration_stdout.py +++ b/tests/test_integration_stdout.py @@ -2,7 +2,6 @@ import shutil import subprocess import sys -from pathlib import Path import pytest @@ -17,7 +16,7 @@ assert_minidump, assert_before_send, assert_no_before_send, - assert_crash_timestamp, + assert_no_crash_timestamp, assert_breakpad_crash, assert_exception, wait_for, @@ -174,7 +173,7 @@ def test_inproc_crash_stdout(cmake): envelope = Envelope.deserialize(output) - assert_crash_timestamp(has_files, tmp_path) + assert_no_crash_timestamp(has_files, tmp_path) assert_meta(envelope, integration="inproc") assert_breadcrumb(envelope) assert_attachment(envelope) @@ -205,7 +204,7 @@ def test_abort_stdout(cmake, backend): envelope = Envelope.deserialize(output) - assert_crash_timestamp(has_files, tmp_path) + assert_no_crash_timestamp(has_files, tmp_path) assert_meta(envelope, integration=backend) assert_breadcrumb(envelope) assert_attachment(envelope) @@ -224,7 +223,7 @@ def test_inproc_crash_stdout_before_send(cmake): envelope = Envelope.deserialize(output) - assert_crash_timestamp(has_files, tmp_path) + assert_no_crash_timestamp(has_files, tmp_path) assert_meta(envelope, integration="inproc") assert_breadcrumb(envelope) assert_attachment(envelope) @@ -239,7 +238,7 @@ def test_inproc_crash_stdout_discarding_on_crash(cmake): # since the on_crash() handler discards further processing we expect an empty response assert len(output) == 0 - assert_crash_timestamp(has_files, tmp_path) + assert_no_crash_timestamp(has_files, tmp_path) def test_inproc_crash_stdout_before_send_and_on_crash(cmake): @@ -252,7 +251,7 @@ def test_inproc_crash_stdout_before_send_and_on_crash(cmake): # but we expect no event modification from before_send() since setting on_crash() disables before_send() assert_no_before_send(envelope) - assert_crash_timestamp(has_files, tmp_path) + assert_no_crash_timestamp(has_files, tmp_path) assert_meta(envelope, integration="inproc") assert_breadcrumb(envelope) assert_attachment(envelope) @@ -284,7 +283,7 @@ def test_inproc_stack_overflow_stdout(cmake, stack_size): envelope = Envelope.deserialize(output) - assert_crash_timestamp(has_files, tmp_path) + assert_no_crash_timestamp(has_files, tmp_path) assert_meta(envelope, integration="inproc") assert_breadcrumb(envelope) assert_attachment(envelope) @@ -297,7 +296,7 @@ def test_breakpad_crash_stdout(cmake): envelope = Envelope.deserialize(output) - assert_crash_timestamp(has_files, tmp_path) + assert_no_crash_timestamp(has_files, tmp_path) assert_meta(envelope, integration="breakpad") assert_breadcrumb(envelope) assert_attachment(envelope) @@ -311,7 +310,7 @@ def test_breakpad_crash_stdout_before_send(cmake): envelope = Envelope.deserialize(output) - assert_crash_timestamp(has_files, tmp_path) + assert_no_crash_timestamp(has_files, tmp_path) assert_meta(envelope, integration="breakpad") assert_breadcrumb(envelope) assert_attachment(envelope) @@ -327,7 +326,7 @@ def test_breakpad_crash_stdout_discarding_on_crash(cmake): # since the on_crash() handler discards further processing we expect an empty response assert len(output) == 0 - assert_crash_timestamp(has_files, tmp_path) + assert_no_crash_timestamp(has_files, tmp_path) @pytest.mark.skipif(not has_breakpad or is_qemu, reason="test needs breakpad backend") @@ -341,7 +340,7 @@ def test_breakpad_crash_stdout_before_send_and_on_crash(cmake): # but we expect no event modification from before_send() since setting on_crash() disables before_send() assert_no_before_send(envelope) - assert_crash_timestamp(has_files, tmp_path) + assert_no_crash_timestamp(has_files, tmp_path) assert_meta(envelope, integration="breakpad") assert_breadcrumb(envelope) assert_attachment(envelope) @@ -380,7 +379,7 @@ def test_breakpad_stack_overflow_stdout(cmake, stack_size): envelope = Envelope.deserialize(output) - assert_crash_timestamp(has_files, tmp_path) + assert_no_crash_timestamp(has_files, tmp_path) assert_meta(envelope, integration="breakpad") assert_breadcrumb(envelope) assert_attachment(envelope) diff --git a/tests/unit/test_basic.c b/tests/unit/test_basic.c index b08f2551a..e80df6650 100644 --- a/tests/unit/test_basic.c +++ b/tests/unit/test_basic.c @@ -230,7 +230,14 @@ SENTRY_TEST(crashed_last_run) TEST_CHECK_INT_EQUAL(sentry_get_crashed_last_run(), 1); - // clear the status and re-init +#ifdef SENTRY_PLATFORM_ANDROID + // Android preserves the marker for session finalization + TEST_CHECK(sentry__has_crash_marker(options)); +#else + // other platforms consume it automatically during initialization + TEST_CHECK(!sentry__has_crash_marker(options)); +#endif + // explicit clearing remains supported on all platforms TEST_CHECK_INT_EQUAL(sentry_clear_crashed_last_run(), 0); sentry_close(); From f5a6581e8481684c88e340819f3c80081695fca6 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Tue, 25 Aug 2026 15:01:01 +0200 Subject: [PATCH 2/7] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e141db38..c64208e96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ **Breaking / Important behavior changes**: -- `sentry_init()` now consumes `/last_crash` after caching its value, except on Android. `sentry_clear_crashed_last_run()` is no longer required elsewhere. ([#1325](https://github.com/getsentry/sentry-native/issues/1325)) +- `sentry_init()` now consumes `/last_crash` after caching its value, except on Android. `sentry_clear_crashed_last_run()` is no longer required elsewhere. ([#2023](https://github.com/getsentry/sentry-native/pull/2023)) ## Unreleased From 98a9f85fbd88ff6da5fa89cf7fa84330235366a9 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Tue, 25 Aug 2026 15:06:45 +0200 Subject: [PATCH 3/7] restore import --- tests/test_integration_stdout.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_integration_stdout.py b/tests/test_integration_stdout.py index 57d8a6b90..d978943d2 100644 --- a/tests/test_integration_stdout.py +++ b/tests/test_integration_stdout.py @@ -2,6 +2,7 @@ import shutil import subprocess import sys +from pathlib import Path import pytest From 4d31d10784da9b9d730ab97666cab6735591e07e Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Tue, 25 Aug 2026 15:45:13 +0200 Subject: [PATCH 4/7] crashpad: no first-chance handler nor crash marker on macos --- tests/test_integration_crashpad.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/test_integration_crashpad.py b/tests/test_integration_crashpad.py index 348bb5004..d3fde0234 100644 --- a/tests/test_integration_crashpad.py +++ b/tests/test_integration_crashpad.py @@ -102,7 +102,9 @@ def test_crashpad_on_crashed_last_run(cmake): stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) - assert_crash_timestamp(has_files, tmp_path) + # no first-chance handler nor crash marker on macOS + if sys.platform != "darwin": + assert_crash_timestamp(has_files, tmp_path) assert not list((tmp_path / ".sentry-native").glob("*.run/*.crash")) @@ -113,7 +115,9 @@ def test_crashpad_on_crashed_last_run(cmake): stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) - assert_no_crash_timestamp(has_files, tmp_path) + # no first-chance handler nor crash marker on macOS + if sys.platform != "darwin": + assert_no_crash_timestamp(has_files, tmp_path) callbacks = [ line for line in restarted.stdout.splitlines() From 73b72390763446c2918066a9e226a16e3f81e1a5 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Tue, 25 Aug 2026 16:39:52 +0200 Subject: [PATCH 5/7] ndk: sentry__retain_crash_marker --- CHANGELOG.md | 6 +++++- include/sentry.h | 6 ++---- ndk/lib/src/main/jni/sentry.c | 7 +++++++ src/sentry_core.c | 5 +---- src/sentry_database.c | 6 ++++++ src/sentry_database.h | 7 +++++++ src/sentry_options.h | 1 + tests/unit/test_basic.c | 27 ++++++++++++++++++--------- 8 files changed, 47 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c64208e96..a60aa7cfd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,11 @@ **Breaking / Important behavior changes**: -- `sentry_init()` now consumes `/last_crash` after caching its value, except on Android. `sentry_clear_crashed_last_run()` is no longer required elsewhere. ([#2023](https://github.com/getsentry/sentry-native/pull/2023)) +- `sentry_init()` now consumes `/last_crash` after caching its value, aligning crashed-last-run behavior with other Sentry SDKs. ([#2023](https://github.com/getsentry/sentry-native/pull/2023)) + +**Deprecations**: + +- Deprecate `sentry_clear_crashed_last_run()` because `sentry_init()` now consumes the marker automatically. ([#2023](https://github.com/getsentry/sentry-native/pull/2023)) ## Unreleased diff --git a/include/sentry.h b/include/sentry.h index 1ee5fe783..ac0f06138 100644 --- a/include/sentry.h +++ b/include/sentry.h @@ -4209,8 +4209,7 @@ SENTRY_EXPERIMENTAL_API void sentry_transaction_iter_headers( * * Notes: * * The underlying value is set by sentry_init() - it must be called first. - * * sentry_init() clears the persisted value for the next run except on - * Android, where it must be cleared explicitly. + * * sentry_init() clears the persisted value for the next run. * * Possible return values: * 1 = the last run was a crash @@ -4222,8 +4221,6 @@ SENTRY_EXPERIMENTAL_API int sentry_get_crashed_last_run(void); /** * Clear the persisted status of the "crashed-last-run". * - * Calling this function is only required on Android. - * * Notes: * * This doesn't change the value of sentry_get_crashed_last_run() yet. * However, if sentry_init() is called again, the value will change. @@ -4231,6 +4228,7 @@ SENTRY_EXPERIMENTAL_API int sentry_get_crashed_last_run(void); * * Returns 0 on success, 1 on error. */ +SENTRY_DEPRECATED("The crash marker is cleared by `sentry_init()`.") SENTRY_EXPERIMENTAL_API int sentry_clear_crashed_last_run(void); /** diff --git a/ndk/lib/src/main/jni/sentry.c b/ndk/lib/src/main/jni/sentry.c index 30ecb6d55..a3d6445ac 100644 --- a/ndk/lib/src/main/jni/sentry.c +++ b/ndk/lib/src/main/jni/sentry.c @@ -377,6 +377,9 @@ send_envelope(sentry_envelope_t *envelope, void *data) // sentry_backend.h extern void sentry__backend_preload(void); +// sentry_database.h +extern void sentry__retain_crash_marker(sentry_options_t *options); + JNIEXPORT void JNICALL Java_io_sentry_ndk_SentryNdk_preloadSentryNative(JNIEnv *env, jclass cls) { @@ -436,6 +439,10 @@ Java_io_sentry_ndk_SentryNdk_initSentryNative( options = sentry_options_new(); ENSURE_OR_FAIL(options); + // Android SDK needs to retain the marker timestamp for session finalization + // and cleans it up when appropriate + sentry__retain_crash_marker(options); + // session tracking is enabled by default, but the Android SDK already // handles it sentry_options_set_auto_session_tracking(options, 0); diff --git a/src/sentry_core.c b/src/sentry_core.c index 55929795a..8be6367b6 100644 --- a/src/sentry_core.c +++ b/src/sentry_core.c @@ -238,12 +238,9 @@ sentry_init(sentry_options_t *options) } g_last_crash = sentry__has_crash_marker(options); - // Android SDK needs the marker timestamp for session finalization -#if !defined(SENTRY_PLATFORM_ANDROID) - if (g_last_crash) { + if (g_last_crash && !options->retain_crash_marker) { sentry__clear_crash_marker(options); } -#endif g_options = options; // *after* setting the global options, trigger a scope and consent flush, diff --git a/src/sentry_database.c b/src/sentry_database.c index 39edcd750..351937fb9 100644 --- a/src/sentry_database.c +++ b/src/sentry_database.c @@ -1162,6 +1162,12 @@ sentry__has_crash_marker(const sentry_options_t *options) return result; } +void +sentry__retain_crash_marker(sentry_options_t *options) +{ + options->retain_crash_marker = true; +} + bool sentry__clear_crash_marker(const sentry_options_t *options) { diff --git a/src/sentry_database.h b/src/sentry_database.h index ccd85434d..967509212 100644 --- a/src/sentry_database.h +++ b/src/sentry_database.h @@ -220,6 +220,13 @@ bool sentry__write_crash_marker(const sentry_options_t *options); */ bool sentry__has_crash_marker(const sentry_options_t *options); +/** + * Prevents sentry_init() from clearing `/last_crash`. + * + * Exported for the Android NDK integration. + */ +SENTRY_API void sentry__retain_crash_marker(sentry_options_t *options); + /** * This will remove the `/last_crash` file. */ diff --git a/src/sentry_options.h b/src/sentry_options.h index c91af3dc1..4fd4f0658 100644 --- a/src/sentry_options.h +++ b/src/sentry_options.h @@ -102,6 +102,7 @@ struct sentry_options_s { sentry_session_t *session; sentry_integration_t **integrations; size_t num_integrations; + bool retain_crash_marker; long refcount; uint64_t shutdown_timeout; diff --git a/tests/unit/test_basic.c b/tests/unit/test_basic.c index e80df6650..d53500e6d 100644 --- a/tests/unit/test_basic.c +++ b/tests/unit/test_basic.c @@ -229,16 +229,7 @@ SENTRY_TEST(crashed_last_run) TEST_CHECK_INT_EQUAL(sentry_init(options), 0); TEST_CHECK_INT_EQUAL(sentry_get_crashed_last_run(), 1); - -#ifdef SENTRY_PLATFORM_ANDROID - // Android preserves the marker for session finalization - TEST_CHECK(sentry__has_crash_marker(options)); -#else - // other platforms consume it automatically during initialization TEST_CHECK(!sentry__has_crash_marker(options)); -#endif - // explicit clearing remains supported on all platforms - TEST_CHECK_INT_EQUAL(sentry_clear_crashed_last_run(), 0); sentry_close(); @@ -246,6 +237,24 @@ SENTRY_TEST(crashed_last_run) TEST_CHECK_INT_EQUAL(sentry_get_crashed_last_run(), 1); } + { + SENTRY_TEST_OPTIONS_NEW(options); + sentry_options_set_dsn_n(options, dsn, sizeof(dsn)); + + // simulate a crash + TEST_CHECK(sentry__write_crash_marker(options)); + + sentry__retain_crash_marker(options); + TEST_CHECK_INT_EQUAL(sentry_init(options), 0); + + TEST_CHECK_INT_EQUAL(sentry_get_crashed_last_run(), 1); + TEST_CHECK(sentry__has_crash_marker(options)); + // explicit clearing remains supported on all platforms + TEST_CHECK_INT_EQUAL(sentry_clear_crashed_last_run(), 0); + + sentry_close(); + } + { SENTRY_TEST_OPTIONS_NEW(options); sentry_options_set_dsn_n(options, dsn, sizeof(dsn)); From 17b9dc03fd94a289f74868b5e5d3c480d5c8808f Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Tue, 25 Aug 2026 17:57:40 +0200 Subject: [PATCH 6/7] suppress --- tests/unit/test_basic.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/unit/test_basic.c b/tests/unit/test_basic.c index d53500e6d..176227d54 100644 --- a/tests/unit/test_basic.c +++ b/tests/unit/test_basic.c @@ -195,7 +195,8 @@ SENTRY_TEST(crash_marker) SENTRY_TEST(crashed_last_run) { // fails before init() is called - TEST_CHECK_INT_EQUAL(sentry_clear_crashed_last_run(), 1); + SENTRY_TEST_DEPRECATED( + TEST_CHECK_INT_EQUAL(sentry_clear_crashed_last_run(), 1)); // clear any leftover from previous test runs { @@ -250,7 +251,8 @@ SENTRY_TEST(crashed_last_run) TEST_CHECK_INT_EQUAL(sentry_get_crashed_last_run(), 1); TEST_CHECK(sentry__has_crash_marker(options)); // explicit clearing remains supported on all platforms - TEST_CHECK_INT_EQUAL(sentry_clear_crashed_last_run(), 0); + SENTRY_TEST_DEPRECATED( + TEST_CHECK_INT_EQUAL(sentry_clear_crashed_last_run(), 0)); sentry_close(); } From a8230244ea9b65b760aae1cf47ab69742f18e0b2 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Tue, 1 Sep 2026 18:01:24 +0200 Subject: [PATCH 7/7] Update CHANGELOG.md --- CHANGELOG.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2414e2e34..fae4610d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,16 +6,14 @@ - `sentry_init()` now consumes `/last_crash` after caching its value, aligning crashed-last-run behavior with other Sentry SDKs. ([#2023](https://github.com/getsentry/sentry-native/pull/2023)) -**Deprecations**: - -- Deprecate `sentry_clear_crashed_last_run()` because `sentry_init()` now consumes the marker automatically. ([#2023](https://github.com/getsentry/sentry-native/pull/2023)) - -## Unreleased - **Features**: - Add `sentry_event_set_level` for setting the level of an individual event. ([#2038](https://github.com/getsentry/sentry-native/pull/2038)) +**Deprecations**: + +- Deprecate `sentry_clear_crashed_last_run()` because `sentry_init()` now consumes the marker automatically. ([#2023](https://github.com/getsentry/sentry-native/pull/2023)) + ## 0.16.5 **Important behavior changes**: