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 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 diff --git a/tests/__init__.py b/tests/__init__.py index df299728d7..7f279a3bc1 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -14,6 +14,15 @@ sourcedir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) +def lib_name(name): + if sys.platform == "win32": + 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" + + 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 b5cce57cbc..790a6feaf9 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,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 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 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 0773639f84..e37ca5ca58 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 @@ -17,6 +18,7 @@ is_logs_envelope, is_feedback_envelope, is_replay_envelope, + lib_name, REPLAY_ID, ) from .conditions import has_crashpad, has_oom @@ -49,6 +51,28 @@ flushes_state = sys.platform != "darwin" +def _minidump_stream(minidump, stream_type): + stream_count, directory_rva = struct.unpack_from("