From 9383db265e70bfcdc120a698478d76c078744105 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Wed, 19 Aug 2026 12:34:28 +0200 Subject: [PATCH 1/6] test(crashpad): verify module CodeView UUID Parse module CodeView records from uploaded minidumps and assert the example module carries a non-zero UUID. --- tests/assertions.py | 22 +++++++++---- tests/test_integration_crashpad.py | 50 ++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 6 deletions(-) diff --git a/tests/assertions.py b/tests/assertions.py index b5cce57cbc..f30e181565 100644 --- a/tests/assertions.py +++ b/tests/assertions.py @@ -515,6 +515,7 @@ class CrashpadAttachments: view_hierarchy: dict cmake_cache: int bytes_bin: bytes = None + minidump: bytes = None def _unpack_breadcrumbs(payload): @@ -530,6 +531,7 @@ def _load_crashpad_attachments(msg): view_hierarchy = {} cmake_cache = -1 bytes_bin = None + minidump = None for part in msg.walk(): if part.get_filename() is not None: assert part.get("Content-Type") is None @@ -548,8 +550,20 @@ def _load_crashpad_attachments(msg): case "bytes.bin": bytes_bin = part.get_payload(decode=True) + if ( + part.get_param("name", header="content-disposition") + == "upload_file_minidump" + ): + minidump = part.get_payload(decode=True) + return CrashpadAttachments( - event, breadcrumb1, breadcrumb2, view_hierarchy, cmake_cache, bytes_bin + event, + breadcrumb1, + breadcrumb2, + view_hierarchy, + cmake_cache, + bytes_bin, + minidump, ) @@ -593,11 +607,7 @@ def assert_crashpad_upload(req, expect_attachment=False, expect_view_hierarchy=F assert attachments.bytes_bin == None if expect_view_hierarchy: assert_attachment_content_view_hierarchy(attachments.view_hierarchy) - assert any( - b'name="upload_file_minidump"' in part.as_bytes() - and b"\n\nMDMP" in part.as_bytes() - for part in msg.walk() - ) + assert attachments.minidump.startswith(b"MDMP") return attachments diff --git a/tests/test_integration_crashpad.py b/tests/test_integration_crashpad.py index 0773639f84..a411138f37 100644 --- a/tests/test_integration_crashpad.py +++ b/tests/test_integration_crashpad.py @@ -1,4 +1,5 @@ import os +import struct import subprocess import sys import time @@ -49,6 +50,28 @@ flushes_state = sys.platform != "darwin" +def _minidump_stream(minidump, stream_type): + stream_count, directory_rva = struct.unpack_from(" Date: Wed, 19 Aug 2026 12:44:32 +0200 Subject: [PATCH 2/6] test(crashpad): check shared library CodeView record Target the SDK shared library and accept both PDB70 and ELF build-ID record signatures. --- tests/test_integration_crashpad.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/test_integration_crashpad.py b/tests/test_integration_crashpad.py index a411138f37..a2e6e89bb7 100644 --- a/tests/test_integration_crashpad.py +++ b/tests/test_integration_crashpad.py @@ -108,10 +108,14 @@ def test_crashpad_codeview(cmake, httpserver): name.replace("\\", "/").rsplit("/", 1)[-1]: codeview for name, codeview in _minidump_modules(attachments.minidump) } - module_name = "sentry_example.exe" if sys.platform == "win32" else "sentry_example" + module_name = {"win32": "sentry.dll", "darwin": "libsentry.dylib"}.get( + sys.platform, "libsentry.so" + ) codeview = codeviews[module_name] - assert codeview[:4] == b"RSDS" - assert codeview[4:20] != bytes(16) + signature = codeview[:4] + identifier = codeview[4:20] if signature == b"RSDS" else codeview[4:] + assert signature in (b"RSDS", b"LEpB") + assert any(identifier) def _setup_crashpad_proxy_test(cmake, httpserver, proxy): From 6d6dbeb09f4768d2fa6a98398ab05ccfdfcdf3db Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Wed, 19 Aug 2026 12:59:23 +0200 Subject: [PATCH 3/6] fix review findings --- tests/__init__.py | 8 ++++++++ tests/assertions.py | 3 ++- tests/cmake.py | 9 +-------- tests/test_integration_crashpad.py | 15 +++++++++------ 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/tests/__init__.py b/tests/__init__.py index df299728d7..5b1dcccd6c 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -14,6 +14,14 @@ sourcedir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) +def lib_name(name): + if sys.platform == "win32": + return name + ".dll" + elif sys.platform == "darwin": + return "lib" + name + ".dylib" + return "lib" + name + ".so" + + def adb(*args, **kwargs): return subprocess.run( ["{}/platform-tools/adb".format(os.environ["ANDROID_HOME"]), *args], **kwargs diff --git a/tests/assertions.py b/tests/assertions.py index f30e181565..790a6feaf9 100644 --- a/tests/assertions.py +++ b/tests/assertions.py @@ -607,7 +607,8 @@ def assert_crashpad_upload(req, expect_attachment=False, expect_view_hierarchy=F assert attachments.bytes_bin == None if expect_view_hierarchy: assert_attachment_content_view_hierarchy(attachments.view_hierarchy) - assert attachments.minidump.startswith(b"MDMP") + assert attachments.minidump is not None, "minidump attachment missing" + assert attachments.minidump.startswith(b"MDMP"), "invalid minidump signature" return attachments diff --git a/tests/cmake.py b/tests/cmake.py index 305d784b5c..e91be3b7f0 100644 --- a/tests/cmake.py +++ b/tests/cmake.py @@ -8,7 +8,7 @@ import pytest -from . import adb +from . import adb, lib_name from .conditions import has_sccache from .build_config import ( get_android_config, @@ -76,13 +76,6 @@ def destroy(self): def exe_name(name): return name + ".exe" if sys.platform == "win32" else name - def lib_name(name): - if sys.platform == "win32": - return name + ".dll" - elif sys.platform == "darwin": - return "lib" + name + ".dylib" - return "lib" + name + ".so" - for i, (d, _) in enumerate(self.runs.values()): # first merge the raw profiling runs files = [f for f in os.listdir(d) if f.endswith(".profraw")] diff --git a/tests/test_integration_crashpad.py b/tests/test_integration_crashpad.py index a2e6e89bb7..e37ca5ca58 100644 --- a/tests/test_integration_crashpad.py +++ b/tests/test_integration_crashpad.py @@ -18,6 +18,7 @@ is_logs_envelope, is_feedback_envelope, is_replay_envelope, + lib_name, REPLAY_ID, ) from .conditions import has_crashpad, has_oom @@ -108,13 +109,15 @@ def test_crashpad_codeview(cmake, httpserver): name.replace("\\", "/").rsplit("/", 1)[-1]: codeview for name, codeview in _minidump_modules(attachments.minidump) } - module_name = {"win32": "sentry.dll", "darwin": "libsentry.dylib"}.get( - sys.platform, "libsentry.so" - ) - codeview = codeviews[module_name] + codeview = codeviews[lib_name("sentry")] signature = codeview[:4] - identifier = codeview[4:20] if signature == b"RSDS" else codeview[4:] - assert signature in (b"RSDS", b"LEpB") + if sys.platform == "linux": + assert signature == b"LEpB" + identifier = codeview[4:] + else: + assert signature == b"RSDS" + identifier = codeview[4:20] + assert any(identifier) From 44b1118334b6f0438048941d6a570b63053227c8 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Wed, 19 Aug 2026 13:30:59 +0200 Subject: [PATCH 4/6] Bump crashpad --- external/crashpad | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/crashpad b/external/crashpad index eb0cc3c7fa..bfe80ce620 160000 --- a/external/crashpad +++ b/external/crashpad @@ -1 +1 @@ -Subproject commit eb0cc3c7fac2bff0f8b79f080de66d5c3949e298 +Subproject commit bfe80ce620545c956379b990e319ebef19eb0e52 From 7b1345a8e49d9b27c9a653851196ced0a62bcdb3 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Wed, 19 Aug 2026 15:23:46 +0200 Subject: [PATCH 5/6] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98eacde709..fd8fbf3542 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - Native: store daemon logs, minidumps, crash envelopes, and scratch files in `.run` directories so they are cleaned up with the run instead of accumulating in the database root. Minidumps can still be retained with `cache_keep`, which stores `.dmp` sidecars alongside cached envelopes. ([#1976](https://github.com/getsentry/sentry-native/pull/1976)) - Linux/ARM32: prevent recursive crashes when libunwind receives an unmapped initial instruction pointer during crash handling. ([#1977](https://github.com/getsentry/sentry-native/pull/1977)) +- Crashpad/Windows: preserve module CodeView UUIDs for minimal PDB70 records with empty PDB filenames. ([#2003](https://github.com/getsentry/sentry-native/pull/2003)) ## 0.16.3 From 689e06757ebf70fda996985013d72604058a3d48 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Wed, 19 Aug 2026 16:47:48 +0200 Subject: [PATCH 6/6] fix lib_name for mingw --- tests/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/__init__.py b/tests/__init__.py index 5b1dcccd6c..7f279a3bc1 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -16,7 +16,8 @@ def lib_name(name): if sys.platform == "win32": - return name + ".dll" + prefix = "lib" if os.environ.get("TEST_MINGW") else "" + return prefix + name + ".dll" elif sys.platform == "darwin": return "lib" + name + ".dylib" return "lib" + name + ".so"