From 3a65dffaf94d61149d663ff2d703f41dbef9c981 Mon Sep 17 00:00:00 2001 From: Amir Mujacic Date: Wed, 15 Apr 2026 15:04:51 +0200 Subject: [PATCH 1/5] fix(native): int32 size and endians on mac --- .../native/minidump/sentry_minidump_macos.c | 16 +++++++++++++++- src/backends/native/sentry_crash_daemon.c | 4 ++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/backends/native/minidump/sentry_minidump_macos.c b/src/backends/native/minidump/sentry_minidump_macos.c index ee28419305..e693e4a35f 100644 --- a/src/backends/native/minidump/sentry_minidump_macos.c +++ b/src/backends/native/minidump/sentry_minidump_macos.c @@ -243,8 +243,22 @@ write_cv_record( cv_record->cv_signature = CV_SIGNATURE_RSDS; cv_record->age = 0; // Not used for Mach-O - // Copy UUID + // Copy UUID with byte-swap for GUID format. + // Mach-O LC_UUID is big-endian (RFC 4122), but the RSDS CV record uses + // Windows GUID layout where the first 3 fields (Data1=uint32, Data2=uint16, + // Data3=uint16) are little-endian. When minidump readers (symbolicator, + // breakpad) parse the GUID struct, they byte-swap these fields back. + // We must pre-swap here so the round-trip produces the original Mach-O UUID. memcpy(cv_record->signature, uuid, 16); + // Swap Data1 (bytes 0-3) + uint8_t *s = cv_record->signature; + uint8_t tmp; + tmp = s[0]; s[0] = s[3]; s[3] = tmp; + tmp = s[1]; s[1] = s[2]; s[2] = tmp; + // Swap Data2 (bytes 4-5) + tmp = s[4]; s[4] = s[5]; s[5] = tmp; + // Swap Data3 (bytes 6-7) + tmp = s[6]; s[6] = s[7]; s[7] = tmp; // Copy module path memcpy(cv_record->pdb_file_name, module_path, path_len + 1); diff --git a/src/backends/native/sentry_crash_daemon.c b/src/backends/native/sentry_crash_daemon.c index fea4fe03a7..717ffa8f05 100644 --- a/src/backends/native/sentry_crash_daemon.c +++ b/src/backends/native/sentry_crash_daemon.c @@ -2092,9 +2092,9 @@ build_native_crash_event( sentry_value_set_by_key( image, "image_addr", sentry_value_new_string(addr_buf)); - // Set image_size as int32 (modules > 2GB are extremely rare) + // Use double for image_size to handle modules > 2GB (e.g. shared cache) sentry_value_set_by_key(image, "image_size", - sentry_value_new_int32((int32_t)mod->size)); + sentry_value_new_double((double)mod->size)); #if defined(SENTRY_PLATFORM_WINDOWS) // Set code_id for PE modules (TimeDateStamp + SizeOfImage) From 76420514022f0136cfd5e37bc9d88f92559b38cb Mon Sep 17 00:00:00 2001 From: Amir Mujacic Date: Wed, 15 Apr 2026 16:49:40 +0200 Subject: [PATCH 2/5] Fix changelog and stlye --- CHANGELOG.md | 1 + .../native/minidump/sentry_minidump_macos.c | 19 ++++++++++++++----- src/backends/native/sentry_crash_daemon.c | 3 ++- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2738e444c..61f01b933c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - macOS: cache VM regions for FP validation in the new unwinder. ([#1634](https://github.com/getsentry/sentry-native/pull/1634)) - Linux: remove dependency on `stdio` in the unwinder pointer validation code to reduce exposure to async-signal-unsafe functions. ([#1637](https://github.com/getsentry/sentry-native/pull/1637)) - macOS: replace sandbox-incompatible IPC primitives (`sem_open`, `shm_open`, `fork`) with sandbox-safe alternatives (`pthread_mutex`, file-backed `mmap`, `posix_spawn`) so the native backend works inside App Sandbox. ([#1644](https://github.com/getsentry/sentry-native/pull/1644)) +- macOS: fix minidump UUID byte order (swap GUID fields to match RSDS format) and use `double` for image sizes to support modules larger than 2 GB. ([#1651](https://github.com/getsentry/sentry-native/pull/1651)) ## 0.13.6 diff --git a/src/backends/native/minidump/sentry_minidump_macos.c b/src/backends/native/minidump/sentry_minidump_macos.c index e693e4a35f..bdbc87cd7c 100644 --- a/src/backends/native/minidump/sentry_minidump_macos.c +++ b/src/backends/native/minidump/sentry_minidump_macos.c @@ -248,17 +248,26 @@ write_cv_record( // Windows GUID layout where the first 3 fields (Data1=uint32, Data2=uint16, // Data3=uint16) are little-endian. When minidump readers (symbolicator, // breakpad) parse the GUID struct, they byte-swap these fields back. - // We must pre-swap here so the round-trip produces the original Mach-O UUID. + // We must pre-swap here so the round-trip produces the original Mach-O + // UUID. memcpy(cv_record->signature, uuid, 16); // Swap Data1 (bytes 0-3) uint8_t *s = cv_record->signature; uint8_t tmp; - tmp = s[0]; s[0] = s[3]; s[3] = tmp; - tmp = s[1]; s[1] = s[2]; s[2] = tmp; + tmp = s[0]; + s[0] = s[3]; + s[3] = tmp; + tmp = s[1]; + s[1] = s[2]; + s[2] = tmp; // Swap Data2 (bytes 4-5) - tmp = s[4]; s[4] = s[5]; s[5] = tmp; + tmp = s[4]; + s[4] = s[5]; + s[5] = tmp; // Swap Data3 (bytes 6-7) - tmp = s[6]; s[6] = s[7]; s[7] = tmp; + tmp = s[6]; + s[6] = s[7]; + s[7] = tmp; // Copy module path memcpy(cv_record->pdb_file_name, module_path, path_len + 1); diff --git a/src/backends/native/sentry_crash_daemon.c b/src/backends/native/sentry_crash_daemon.c index 717ffa8f05..771c08b217 100644 --- a/src/backends/native/sentry_crash_daemon.c +++ b/src/backends/native/sentry_crash_daemon.c @@ -2092,7 +2092,8 @@ build_native_crash_event( sentry_value_set_by_key( image, "image_addr", sentry_value_new_string(addr_buf)); - // Use double for image_size to handle modules > 2GB (e.g. shared cache) + // Use double for image_size to handle modules > 2GB (e.g. shared + // cache) sentry_value_set_by_key(image, "image_size", sentry_value_new_double((double)mod->size)); From 934ec103d8672d867cb42e7cabf81abcd4a8d9c0 Mon Sep 17 00:00:00 2001 From: Amir Mujacic Date: Thu, 16 Apr 2026 14:56:15 +0200 Subject: [PATCH 3/5] extract utility, remoove duplicated code, double -> int64 --- CHANGELOG.md | 2 +- .../native/minidump/sentry_minidump_macos.c | 25 +++---------------- src/backends/native/sentry_crash_daemon.c | 13 ++-------- src/modulefinder/sentry_modulefinder_linux.c | 9 +------ src/sentry_utils.h | 21 ++++++++++++++++ 5 files changed, 28 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61f01b933c..3f7364fc48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ - macOS: cache VM regions for FP validation in the new unwinder. ([#1634](https://github.com/getsentry/sentry-native/pull/1634)) - Linux: remove dependency on `stdio` in the unwinder pointer validation code to reduce exposure to async-signal-unsafe functions. ([#1637](https://github.com/getsentry/sentry-native/pull/1637)) - macOS: replace sandbox-incompatible IPC primitives (`sem_open`, `shm_open`, `fork`) with sandbox-safe alternatives (`pthread_mutex`, file-backed `mmap`, `posix_spawn`) so the native backend works inside App Sandbox. ([#1644](https://github.com/getsentry/sentry-native/pull/1644)) -- macOS: fix minidump UUID byte order (swap GUID fields to match RSDS format) and use `double` for image sizes to support modules larger than 2 GB. ([#1651](https://github.com/getsentry/sentry-native/pull/1651)) +- Fix minidump UUID byte order (swap GUID fields to match RSDS format) and use `int64` for image sizes to support modules larger than 2 GB. ([#1651](https://github.com/getsentry/sentry-native/pull/1651)) ## 0.13.6 diff --git a/src/backends/native/minidump/sentry_minidump_macos.c b/src/backends/native/minidump/sentry_minidump_macos.c index bdbc87cd7c..bde715c795 100644 --- a/src/backends/native/minidump/sentry_minidump_macos.c +++ b/src/backends/native/minidump/sentry_minidump_macos.c @@ -1,4 +1,5 @@ #include "sentry_boot.h" +#include "sentry_utils.h" #if defined(SENTRY_PLATFORM_MACOS) @@ -245,29 +246,9 @@ write_cv_record( // Copy UUID with byte-swap for GUID format. // Mach-O LC_UUID is big-endian (RFC 4122), but the RSDS CV record uses - // Windows GUID layout where the first 3 fields (Data1=uint32, Data2=uint16, - // Data3=uint16) are little-endian. When minidump readers (symbolicator, - // breakpad) parse the GUID struct, they byte-swap these fields back. - // We must pre-swap here so the round-trip produces the original Mach-O - // UUID. + // Windows GUID layout where the first 3 fields are little-endian. memcpy(cv_record->signature, uuid, 16); - // Swap Data1 (bytes 0-3) - uint8_t *s = cv_record->signature; - uint8_t tmp; - tmp = s[0]; - s[0] = s[3]; - s[3] = tmp; - tmp = s[1]; - s[1] = s[2]; - s[2] = tmp; - // Swap Data2 (bytes 4-5) - tmp = s[4]; - s[4] = s[5]; - s[5] = tmp; - // Swap Data3 (bytes 6-7) - tmp = s[6]; - s[6] = s[7]; - s[7] = tmp; + sentry__uuid_swap_guid_bytes(cv_record->signature); // Copy module path memcpy(cv_record->pdb_file_name, module_path, path_len + 1); diff --git a/src/backends/native/sentry_crash_daemon.c b/src/backends/native/sentry_crash_daemon.c index 771c08b217..6fcbd0af6a 100644 --- a/src/backends/native/sentry_crash_daemon.c +++ b/src/backends/native/sentry_crash_daemon.c @@ -29,7 +29,6 @@ #include #if defined(SENTRY_PLATFORM_UNIX) -# include # include # include # include @@ -1171,13 +1170,7 @@ capture_modules_from_proc_maps(sentry_crash_context_t *ctx) mod->name, mod->uuid, sizeof(mod->uuid)); // Convert to little-endian GUID format for Sentry debug_id - // (same byte swapping as sentry_modulefinder_linux.c) - uint32_t *a = (uint32_t *)mod->uuid; - *a = htonl(*a); - uint16_t *b = (uint16_t *)(mod->uuid + 4); - *b = htons(*b); - uint16_t *c = (uint16_t *)(mod->uuid + 6); - *c = htons(*c); + sentry__uuid_swap_guid_bytes(mod->uuid); SENTRY_DEBUGF("Captured module: %s base=0x%llx size=0x%llx", mod->name, (unsigned long long)mod->base_address, @@ -2092,10 +2085,8 @@ build_native_crash_event( sentry_value_set_by_key( image, "image_addr", sentry_value_new_string(addr_buf)); - // Use double for image_size to handle modules > 2GB (e.g. shared - // cache) sentry_value_set_by_key(image, "image_size", - sentry_value_new_double((double)mod->size)); + sentry_value_new_int64((int64_t)mod->size)); #if defined(SENTRY_PLATFORM_WINDOWS) // Set code_id for PE modules (TimeDateStamp + SizeOfImage) diff --git a/src/modulefinder/sentry_modulefinder_linux.c b/src/modulefinder/sentry_modulefinder_linux.c index a826bb7bf3..8219d0cf72 100644 --- a/src/modulefinder/sentry_modulefinder_linux.c +++ b/src/modulefinder/sentry_modulefinder_linux.c @@ -10,7 +10,6 @@ #include "sentry_utils.h" #include "sentry_value.h" -#include #include #include #include @@ -493,13 +492,7 @@ sentry__procmaps_read_ids_from_elf( // https://getsentry.github.io/symbolicator/advanced/symbol-server-compatibility/#identifiers // in particular, the debug_id is a `little-endian GUID`, so we have // to do appropriate byte-flipping - char *uuid_bytes = uuid.bytes; - uint32_t *a = (uint32_t *)uuid_bytes; - *a = htonl(*a); - uint16_t *b = (uint16_t *)(uuid_bytes + 4); - *b = htons(*b); - uint16_t *c = (uint16_t *)(uuid_bytes + 6); - *c = htons(*c); + sentry__uuid_swap_guid_bytes(uuid.bytes); sentry_value_set_by_key(value, "debug_id", sentry__value_new_uuid(&uuid)); return true; diff --git a/src/sentry_utils.h b/src/sentry_utils.h index 75ea87d4c5..1b89055f07 100644 --- a/src/sentry_utils.h +++ b/src/sentry_utils.h @@ -15,6 +15,10 @@ # include #endif +#ifndef SENTRY_PLATFORM_WINDOWS +# include +#endif + #ifdef SENTRY_PLATFORM_PS # undef MIN # undef MAX @@ -24,6 +28,23 @@ #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) +/** + * Byte-swap the first three GUID fields (Data1, Data2, Data3) of a 16-byte + * UUID in place. This converts between RFC 4122 (big-endian) and Windows + * mixed-endian GUID layout, which is used by RSDS CodeView records and Sentry + * debug-id strings. + */ +static inline void +sentry__uuid_swap_guid_bytes(void *uuid) +{ + uint32_t *a = (uint32_t *)uuid; + *a = htonl(*a); + uint16_t *b = (uint16_t *)((char *)uuid + 4); + *b = htons(*b); + uint16_t *c = (uint16_t *)((char *)uuid + 6); + *c = htons(*c); +} + #if defined(_MSC_VER) && !defined(__clang__) # define UNREACHABLE(reason) assert(!reason) #else From 693574ee53f9171f544e4f244f16e79a41b5c378 Mon Sep 17 00:00:00 2001 From: Amir Mujacic Date: Thu, 16 Apr 2026 15:01:05 +0200 Subject: [PATCH 4/5] Fix windows builds --- src/sentry_utils.h | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/sentry_utils.h b/src/sentry_utils.h index 1b89055f07..e7512db43f 100644 --- a/src/sentry_utils.h +++ b/src/sentry_utils.h @@ -15,7 +15,9 @@ # include #endif -#ifndef SENTRY_PLATFORM_WINDOWS +#ifdef SENTRY_PLATFORM_WINDOWS +# include +#else # include #endif @@ -38,11 +40,17 @@ static inline void sentry__uuid_swap_guid_bytes(void *uuid) { uint32_t *a = (uint32_t *)uuid; - *a = htonl(*a); uint16_t *b = (uint16_t *)((char *)uuid + 4); - *b = htons(*b); uint16_t *c = (uint16_t *)((char *)uuid + 6); +#ifdef SENTRY_PLATFORM_WINDOWS + *a = _byteswap_ulong(*a); + *b = _byteswap_ushort(*b); + *c = _byteswap_ushort(*c); +#else + *a = htonl(*a); + *b = htons(*b); *c = htons(*c); +#endif } #if defined(_MSC_VER) && !defined(__clang__) From b7592ecdcb7c0534c2834ca772e3f983c20d3c39 Mon Sep 17 00:00:00 2001 From: Amir Mujacic Date: Tue, 21 Apr 2026 13:38:20 +0200 Subject: [PATCH 5/5] fix(utils): avoid cast-align warning in uuid swap for ClangCL Rewrite sentry__uuid_swap_guid_bytes to use byte-wise swaps so the function compiles cleanly under -Werror=cast-align (ClangCL on Windows). Drops the now-unused and includes. Co-Authored-By: Claude Opus 4.6 --- src/sentry_utils.h | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/sentry_utils.h b/src/sentry_utils.h index e7512db43f..c74c293b4a 100644 --- a/src/sentry_utils.h +++ b/src/sentry_utils.h @@ -15,12 +15,6 @@ # include #endif -#ifdef SENTRY_PLATFORM_WINDOWS -# include -#else -# include -#endif - #ifdef SENTRY_PLATFORM_PS # undef MIN # undef MAX @@ -39,18 +33,23 @@ static inline void sentry__uuid_swap_guid_bytes(void *uuid) { - uint32_t *a = (uint32_t *)uuid; - uint16_t *b = (uint16_t *)((char *)uuid + 4); - uint16_t *c = (uint16_t *)((char *)uuid + 6); -#ifdef SENTRY_PLATFORM_WINDOWS - *a = _byteswap_ulong(*a); - *b = _byteswap_ushort(*b); - *c = _byteswap_ushort(*c); -#else - *a = htonl(*a); - *b = htons(*b); - *c = htons(*c); -#endif + uint8_t *p = (uint8_t *)uuid; + uint8_t t; + // Swap Data1 (4 bytes) + t = p[0]; + p[0] = p[3]; + p[3] = t; + t = p[1]; + p[1] = p[2]; + p[2] = t; + // Swap Data2 (2 bytes) + t = p[4]; + p[4] = p[5]; + p[5] = t; + // Swap Data3 (2 bytes) + t = p[6]; + p[6] = p[7]; + p[7] = t; } #if defined(_MSC_VER) && !defined(__clang__)