From 90f5bff69b9cdeb11452a5f3d1e732fe7f534c48 Mon Sep 17 00:00:00 2001 From: majcosta Date: Tue, 28 Jul 2026 10:05:47 -0300 Subject: [PATCH] Report module names, not the paths they were loaded from MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The module table is what makes a report symbolizable, but a full path also carries the player's Windows account name and wherever they keep the game, and the report leaves their machine. Symbolizing only ever matched on module name and base — symbolize_crash already ran every path through baseName() before printing it — so the directory was read by nothing. Say so in the consent prompt too. "No personal information" was not true of a table full of paths, and is only worth claiming if it holds. Co-Authored-By: Claude Opus 5 --- sgp/crash_telemetry.cpp | 4 +++- sgp/debug_win_util.cpp | 31 ++++++++++++++++++++++--------- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/sgp/crash_telemetry.cpp b/sgp/crash_telemetry.cpp index daf6d79f9..37118b6e5 100644 --- a/sgp/crash_telemetry.cpp +++ b/sgp/crash_telemetry.cpp @@ -148,7 +148,9 @@ void processCrashTelemetry(const wchar_t* url) { if (consent < 0) { // first run: ask once, remember the answer int r = MessageBoxW(NULL, L"This build can send crash reports to the developers to help fix bugs.\n" - L"A report contains only technical crash data \x2014 no personal information.\n\n" + L"A report contains where the game crashed, the names of the loaded\n" + L"modules, and the HANDLE from your Ja2.ini if you set one. No file\n" + L"paths, no save games, nothing else about your machine.\n\n" L"Send crash reports automatically?", L"Jagged Alliance 2 v1.13 \x2014 Crash Reporting", MB_YESNO | MB_ICONQUESTION); diff --git a/sgp/debug_win_util.cpp b/sgp/debug_win_util.cpp index 62481d622..53ee92c81 100644 --- a/sgp/debug_win_util.cpp +++ b/sgp/debug_win_util.cpp @@ -304,7 +304,7 @@ void writeExceptionBacktrace(_EXCEPTION_POINTERS* ep) { // nor anything identifiable in a sibling module: without this table none of // the addresses below can be symbolized. Walked off the PEB loader list, which // costs no allocation, unlike EnumProcessModules or DbgHelp's module APIs. - emit(wsprintfA(line, " modules (base size path):\r\n")); + emit(wsprintfA(line, " modules (base size name):\r\n")); PEB_LDR_DATA* ldr = NtCurrentTeb()->ProcessEnvironmentBlock->Ldr; LIST_ENTRY* head = &ldr->InMemoryOrderModuleList; int seen = 0; @@ -318,15 +318,28 @@ void writeExceptionBacktrace(_EXCEPTION_POINTERS* ep) { IMAGE_NT_HEADERS* nt = (IMAGE_NT_HEADERS*)(base + dos->e_lfanew); if (nt->Signature != IMAGE_NT_SIGNATURE) continue; - // Truncate the path into a terminated buffer: FullDllName is counted, not - // terminated, and wsprintf supports neither "*" precision nor a way to - // bound %S, so a long path would run off the end of both. - WCHAR path[140]; - int pathChars = (int)(m->FullDllName.Length / sizeof(WCHAR)) + 1; - lstrcpynW(path, m->FullDllName.Buffer, - pathChars < ARRAYSIZE(path) ? pathChars : ARRAYSIZE(path)); + // File name only, never the directory: a full path carries the player's + // Windows account name and whatever else their install path says about + // them, and the report leaves the machine. Symbolizing matches on module + // name and base, so the directory was never read by anything. + // + // Copied into a terminated buffer: FullDllName is counted, not terminated, + // and wsprintf supports neither "*" precision nor a way to bound %S, so a + // long name would run off the end of both. + const WCHAR* full = m->FullDllName.Buffer; + int fullChars = (int)(m->FullDllName.Length / sizeof(WCHAR)); + if (!full || fullChars <= 0) + continue; + int start = 0; + for (int i = 0; i < fullChars; ++i) + if (full[i] == L'\\' || full[i] == L'/') + start = i + 1; + WCHAR modname[64]; + int nameChars = fullChars - start + 1; + lstrcpynW(modname, full + start, + nameChars < ARRAYSIZE(modname) ? nameChars : ARRAYSIZE(modname)); emit(wsprintfA(line, " %08lX %08lX %S\r\n", base, - nt->OptionalHeader.SizeOfImage, path)); + nt->OptionalHeader.SizeOfImage, modname)); } // Committed stack bounds from the TEB, so a bad ebp can't fault our reads.