From 073490f74d90bc7cb2d569cfe910d789a9ce3a16 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 3 Aug 2026 11:53:27 +0200 Subject: [PATCH 1/8] test: early init Call sentry_init() before other static initializers to catch initialization-order regressions across all backends. See also: - #1930 --- CMakeLists.txt | 1 + tests/fixtures/early_init/CMakeLists.txt | 5 +++++ tests/fixtures/early_init/early_init.cpp | 22 ++++++++++++++++++++ tests/test_integration_crashpad.py | 14 +++++++++++++ tests/test_integration_http.py | 26 ++++++++++++++++++++++++ tests/test_integration_native.py | 14 +++++++++++++ 6 files changed, 82 insertions(+) create mode 100644 tests/fixtures/early_init/CMakeLists.txt create mode 100644 tests/fixtures/early_init/early_init.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 0713824d4..12597597e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1003,6 +1003,7 @@ endif() if(SENTRY_BUILD_TESTS) add_subdirectory(tests/unit) add_subdirectory(tests/fixtures/crash_reporter) + add_subdirectory(tests/fixtures/early_init) add_subdirectory(tests/fixtures/screenshot) if(WIN32 AND NOT XBOX) add_subdirectory(tests/fixtures/appx) diff --git a/tests/fixtures/early_init/CMakeLists.txt b/tests/fixtures/early_init/CMakeLists.txt new file mode 100644 index 000000000..b8047f680 --- /dev/null +++ b/tests/fixtures/early_init/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.10) +project(sentry_early_init LANGUAGES CXX) + +add_executable(sentry_early_init early_init.cpp) +target_link_libraries(sentry_early_init PRIVATE sentry) diff --git a/tests/fixtures/early_init/early_init.cpp b/tests/fixtures/early_init/early_init.cpp new file mode 100644 index 000000000..fd16300ac --- /dev/null +++ b/tests/fixtures/early_init/early_init.cpp @@ -0,0 +1,22 @@ +#include + +static int +do_early_init() +{ + sentry_options_t *options = sentry_options_new(); + sentry_options_set_debug(options, true); + return sentry_init(options); +} + +#if defined(_MSC_VER) +// call sentry_init() as early as possible, before other static initializers +# pragma init_seg(lib) +#endif +static int early_init = do_early_init(); + +int +main() +{ + sentry_close(); + return early_init; +} diff --git a/tests/test_integration_crashpad.py b/tests/test_integration_crashpad.py index ac1c50f41..ea1d6ee76 100644 --- a/tests/test_integration_crashpad.py +++ b/tests/test_integration_crashpad.py @@ -1134,3 +1134,17 @@ def test_crashpad_restart_on_crash(cmake, httpserver): assert len(httpserver.log) == 2 for req in httpserver.log: assert_crashpad_upload(req[0]) + + +def test_crashpad_early_init(cmake): + tmp_path = cmake( + ["sentry_early_init"], + {"SENTRY_BACKEND": "crashpad", "SENTRY_BUILD_SHARED_LIBS": "OFF"}, + ) + + result = run( + tmp_path, + "sentry_early_init", + [], + ) + assert result.returncode == 0 diff --git a/tests/test_integration_http.py b/tests/test_integration_http.py index 2aab22131..c17aab708 100644 --- a/tests/test_integration_http.py +++ b/tests/test_integration_http.py @@ -1431,3 +1431,29 @@ def test_restart_on_crash(cmake, httpserver, backend): assert_breakpad_crash(envelope) else: assert False + + +@pytest.mark.parametrize( + "backend", + [ + "inproc", + pytest.param( + "breakpad", + marks=pytest.mark.skipif( + not has_breakpad, reason="breakpad backend not available" + ), + ), + ], +) +def test_early_init(cmake, backend): + tmp_path = cmake( + ["sentry_early_init"], + { + "SENTRY_BACKEND": backend, + "SENTRY_BUILD_SHARED_LIBS": "OFF", + "SENTRY_TRANSPORT": "none", + }, + ) + + result = run(tmp_path, "sentry_early_init", []) + assert result.returncode == 0 diff --git a/tests/test_integration_native.py b/tests/test_integration_native.py index 92b29c185..b7600dae5 100644 --- a/tests/test_integration_native.py +++ b/tests/test_integration_native.py @@ -1193,3 +1193,17 @@ def test_native_replay_orphan_not_flushed(cmake, httpserver): assert not is_replay_envelope(req.get_data()) assert (replays / f"replay-{REPLAY_ID}.mp4").exists() assert (replays / f"replay-{REPLAY_ID}.json").exists() + + +def test_native_early_init(cmake): + tmp_path = cmake( + ["sentry_early_init"], + {"SENTRY_BACKEND": "native", "SENTRY_BUILD_SHARED_LIBS": "OFF"}, + ) + + result = run( + tmp_path, + "sentry_early_init", + [], + ) + assert result.returncode == 0 From fb977aefacabe09de4b8d1666e15d8b786e7afa3 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 3 Aug 2026 12:18:59 +0200 Subject: [PATCH 2/8] try init_priority for gcc & clang --- tests/fixtures/early_init/early_init.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/fixtures/early_init/early_init.cpp b/tests/fixtures/early_init/early_init.cpp index fd16300ac..9052455b5 100644 --- a/tests/fixtures/early_init/early_init.cpp +++ b/tests/fixtures/early_init/early_init.cpp @@ -8,15 +8,21 @@ do_early_init() return sentry_init(options); } +struct EarlyInit { + int result = do_early_init(); +}; + #if defined(_MSC_VER) // call sentry_init() as early as possible, before other static initializers # pragma init_seg(lib) +#elif defined(__GNUC__) || defined(__clang__) +__attribute__((init_priority(101))) #endif -static int early_init = do_early_init(); +static EarlyInit early_init; int main() { sentry_close(); - return early_init; + return early_init.result; } From 41037f275b753c02d2ac05cae38c745c78927273 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 3 Aug 2026 12:42:31 +0200 Subject: [PATCH 3/8] Bump crashpad & mini_chromium --- external/crashpad | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/crashpad b/external/crashpad index aae505d3d..a9027eb01 160000 --- a/external/crashpad +++ b/external/crashpad @@ -1 +1 @@ -Subproject commit aae505d3daf73e8a48136ccc7398663f16096712 +Subproject commit a9027eb01627c949cdf9b2ab121a9a4d6df32921 From 6a479ec11a109d65594a76546da9a90a6cf3ae96 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 3 Aug 2026 12:48:54 +0200 Subject: [PATCH 4/8] SENTRY_TRANSPORT=none --- tests/test_integration_crashpad.py | 6 +++++- tests/test_integration_native.py | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/test_integration_crashpad.py b/tests/test_integration_crashpad.py index ea1d6ee76..2fb5823af 100644 --- a/tests/test_integration_crashpad.py +++ b/tests/test_integration_crashpad.py @@ -1139,7 +1139,11 @@ def test_crashpad_restart_on_crash(cmake, httpserver): def test_crashpad_early_init(cmake): tmp_path = cmake( ["sentry_early_init"], - {"SENTRY_BACKEND": "crashpad", "SENTRY_BUILD_SHARED_LIBS": "OFF"}, + { + "SENTRY_BACKEND": "crashpad", + "SENTRY_BUILD_SHARED_LIBS": "OFF", + "SENTRY_TRANSPORT": "none", + }, ) result = run( diff --git a/tests/test_integration_native.py b/tests/test_integration_native.py index b7600dae5..868b1c260 100644 --- a/tests/test_integration_native.py +++ b/tests/test_integration_native.py @@ -1198,7 +1198,11 @@ def test_native_replay_orphan_not_flushed(cmake, httpserver): def test_native_early_init(cmake): tmp_path = cmake( ["sentry_early_init"], - {"SENTRY_BACKEND": "native", "SENTRY_BUILD_SHARED_LIBS": "OFF"}, + { + "SENTRY_BACKEND": "native", + "SENTRY_BUILD_SHARED_LIBS": "OFF", + "SENTRY_TRANSPORT": "none", + }, ) result = run( From 6f20054e112a24cb1adfc7cf7132d92d9a3d1a95 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 3 Aug 2026 14:48:43 +0200 Subject: [PATCH 5/8] BUILD_SHARED_LIBS --- tests/test_integration_crashpad.py | 2 +- tests/test_integration_http.py | 2 +- tests/test_integration_native.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_integration_crashpad.py b/tests/test_integration_crashpad.py index 2fb5823af..422b58f40 100644 --- a/tests/test_integration_crashpad.py +++ b/tests/test_integration_crashpad.py @@ -1141,8 +1141,8 @@ def test_crashpad_early_init(cmake): ["sentry_early_init"], { "SENTRY_BACKEND": "crashpad", - "SENTRY_BUILD_SHARED_LIBS": "OFF", "SENTRY_TRANSPORT": "none", + "BUILD_SHARED_LIBS": "OFF", }, ) diff --git a/tests/test_integration_http.py b/tests/test_integration_http.py index c17aab708..d923e1177 100644 --- a/tests/test_integration_http.py +++ b/tests/test_integration_http.py @@ -1450,8 +1450,8 @@ def test_early_init(cmake, backend): ["sentry_early_init"], { "SENTRY_BACKEND": backend, - "SENTRY_BUILD_SHARED_LIBS": "OFF", "SENTRY_TRANSPORT": "none", + "BUILD_SHARED_LIBS": "OFF", }, ) diff --git a/tests/test_integration_native.py b/tests/test_integration_native.py index 868b1c260..4eb25c96c 100644 --- a/tests/test_integration_native.py +++ b/tests/test_integration_native.py @@ -1200,8 +1200,8 @@ def test_native_early_init(cmake): ["sentry_early_init"], { "SENTRY_BACKEND": "native", - "SENTRY_BUILD_SHARED_LIBS": "OFF", "SENTRY_TRANSPORT": "none", + "BUILD_SHARED_LIBS": "OFF", }, ) From 7b666c9dfef89d50a496fd9cf4576eef2aad96c4 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 3 Aug 2026 14:48:59 +0200 Subject: [PATCH 6/8] allowlist sentry_early_init --- tests/cmake.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cmake.py b/tests/cmake.py index 5d6287f17..c462af116 100644 --- a/tests/cmake.py +++ b/tests/cmake.py @@ -94,6 +94,7 @@ def destroy(self): "sentry_test_unit", "libsentry.dylib" if sys.platform == "darwin" else "libsentry.so", "sentry-crash", + "sentry_early_init", ] cmd = [ os.environ.get("LLVM_COV", "llvm-cov"), From cc8de7e1d79b6be93692c5224c8c40b2b113c271 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 3 Aug 2026 18:03:08 +0200 Subject: [PATCH 7/8] bump crashpad & mini_chromium --- external/crashpad | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/crashpad b/external/crashpad index a9027eb01..46b01fd75 160000 --- a/external/crashpad +++ b/external/crashpad @@ -1 +1 @@ -Subproject commit a9027eb01627c949cdf9b2ab121a9a4d6df32921 +Subproject commit 46b01fd750285a3b85bd1d4d98b606321f788069 From cab3734f5303749b04fccb07109b8eaaeceb638a Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 3 Aug 2026 18:08:27 +0200 Subject: [PATCH 8/8] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c74092ca7..354890e33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ - Add `sentry_scope_remove_fingerprint` to remove a fingerprint set on a scope, matching the global `sentry_remove_fingerprint`. ([#1932](https://github.com/getsentry/sentry-native/pull/1932)) +**Fixes**: + +- Crashpad: fix a crash when calling `sentry_init` before C++ dynamic initializers have run. ([#1930](https://github.com/getsentry/sentry-native/issues/1930), [mini_chromium#8](https://github.com/getsentry/mini_chromium/pull/8)) + ## 0.16.1 **Features**: