bugfix(system): Update crash message - #2069
Draft
JohnsterID wants to merge 7 commits into
Draft
Conversation
JohnsterID
force-pushed
the
improve-crash-message
branch
from
January 8, 2026 11:01
ef722a3 to
24d2f11
Compare
JohnsterID
marked this pull request as ready for review
January 8, 2026 21:05
xezon
reviewed
Jan 10, 2026
JohnsterID
force-pushed
the
improve-crash-message
branch
from
January 10, 2026 21:13
24d2f11 to
85a17f6
Compare
xezon
reviewed
Jan 11, 2026
JohnsterID
added a commit
to JohnsterID/GeneralsGameCode
that referenced
this pull request
Jan 11, 2026
Add -testcrash command line flag to deliberately trigger a null pointer dereference crash. This allows capturing screenshots of the crash dialog for PR TheSuperHackers#2069 review. Usage: generalszh.exe -testcrash This commit should NOT be merged to main - it exists only for testing and documentation purposes.
JohnsterID
added a commit
to JohnsterID/GeneralsGameCode
that referenced
this pull request
Jan 12, 2026
… strings Add null and empty string checks after calling g_LastErrorDump.str() to handle cases where isEmpty() doesn't work reliably across different build configurations and STL implementations. Issue discovered in testing: Location field showed different values across builds when calling ReleaseCrash() without exception context: - Win32 Release: Empty (correct) - VC6 Release: Shows 'T' (incorrect - isEmpty() failed) - Win32 Debug: Shows corrupted data (incorrect - isEmpty() failed) The additional check ensures consistent behavior across all builds. This doesn't affect real crashes - exceptions always populate g_LastErrorDump through DumpExceptionInfo() which properly clears and fills the string. Relates to TheSuperHackers#2069
JohnsterID
marked this pull request as draft
January 12, 2026 00:25
JohnsterID
added a commit
to JohnsterID/GeneralsGameCode
that referenced
this pull request
Jan 12, 2026
… strings Add null and empty string checks after calling g_LastErrorDump.str() to handle cases where isEmpty() doesn't work reliably across different build configurations and STL implementations. Issue discovered in testing: Location field showed different values across builds when calling ReleaseCrash() without exception context: - Win32 Release: Empty (correct) - VC6 Release: Shows 'T' (incorrect - isEmpty() failed) - Win32 Debug: Shows corrupted data (incorrect - isEmpty() failed) The additional check ensures consistent behavior across all builds. This doesn't affect real crashes - exceptions always populate g_LastErrorDump through DumpExceptionInfo() which properly clears and fills the string. Relates to TheSuperHackers#2069
JohnsterID
added a commit
to JohnsterID/GeneralsGameCode
that referenced
this pull request
Jan 12, 2026
Add check to verify stack trace starts with two spaces (valid format from
WriteStackLine). This prevents extraction of garbage/uninitialized data from
g_LastErrorDump when ReleaseCrash() is called without exception context.
Issue: Previous defensive check (!stackStr || !*stackStr) didn't work because
g_LastErrorDump contained garbage data ('T', '^', corrupted bytes) which are
not NULL or empty - they're just invalid.
Root cause: g_LastErrorDump is a global variable that may contain uninitialized
or leftover data. When ReleaseCrash() is called directly, DumpExceptionInfo()
never runs to clear() and populate it properly. Different STL implementations
(VC6/STLPort vs Win32) initialize globals differently, causing inconsistent
behavior across builds.
Solution: Valid stack traces from WriteStackLine() always start with " "
(two spaces). By checking for this prefix, we can distinguish between:
- Valid exception stack traces: " filename(line) : function" ✓
- Garbage data: "T", "^", corrupted bytes ✗
Test results before fix:
- VC6 Release: Shows "T" in Location field
- Win32 Release: Shows "^" in Location field
- Win32 Debug: Shows corrupted data in Location field
Expected after fix: All builds show empty Location field when no exception.
Relates to TheSuperHackers#2069
JohnsterID
added a commit
to JohnsterID/GeneralsGameCode
that referenced
this pull request
Jan 12, 2026
Add check to verify stack trace starts with two spaces (valid format from
WriteStackLine). This prevents extraction of garbage/uninitialized data from
g_LastErrorDump when ReleaseCrash() is called without exception context.
Issue: Previous defensive check (!stackStr || !*stackStr) didn't work because
g_LastErrorDump contained garbage data ('T', '^', corrupted bytes) which are
not NULL or empty - they're just invalid.
Root cause: g_LastErrorDump is a global variable that may contain uninitialized
or leftover data. When ReleaseCrash() is called directly, DumpExceptionInfo()
never runs to clear() and populate it properly. Different STL implementations
(VC6/STLPort vs Win32) initialize globals differently, causing inconsistent
behavior across builds.
Solution: Valid stack traces from WriteStackLine() always start with " "
(two spaces). By checking for this prefix, we can distinguish between:
- Valid exception stack traces: " filename(line) : function" ✓
- Garbage data: "T", "^", corrupted bytes ✗
Test results before fix:
- VC6 Release: Shows "T" in Location field
- Win32 Release: Shows "^" in Location field
- Win32 Debug: Shows corrupted data in Location field
Expected after fix: All builds show empty Location field when no exception.
Relates to TheSuperHackers#2069
JohnsterID
added a commit
to JohnsterID/GeneralsGameCode
that referenced
this pull request
Jan 12, 2026
…) reliability
Explicitly call g_LastErrorDump.clear() in DebugInit() to ensure the global
AsciiString is properly initialized at program startup. This makes isEmpty()
work reliably across all build configurations.
Root cause: g_LastErrorDump is a global variable that may contain uninitialized
or garbage data depending on STL implementation (VC6/STLPort vs Win32). Without
explicit initialization, isEmpty() returns false even though the string contains
invalid data, causing extractCrashLocation to extract garbage ('T', '^', etc).
Solution: Initialize to empty at startup. This is the correct fix rather than
trying to validate content format, because:
1. isEmpty() is the intended check - now it works correctly
2. No heuristics needed to detect valid vs invalid content
3. Simpler and more maintainable code
4. Guaranteed consistent behavior across all builds
Previous attempts:
- a316c10: Added NULL/empty check (didn't help - string had content)
- 5a2ee72: Added two-space format check (didn't help - garbage started with spaces)
This fix addresses the root cause by ensuring isEmpty() is reliable.
Test results before fix:
- VC6: Shows 'T' or ' T' in Location
- Win32: Shows '^' or ' ^' in Location
- Debug: Shows corrupted data in Location
Expected after fix: All builds show empty Location when no exception.
Relates to TheSuperHackers#2069
JohnsterID
added a commit
to JohnsterID/GeneralsGameCode
that referenced
this pull request
Jan 12, 2026
…) reliability
Explicitly call g_LastErrorDump.clear() in DebugInit() to ensure the global
AsciiString is properly initialized at program startup. This makes isEmpty()
work reliably across all build configurations.
Root cause: g_LastErrorDump is a global variable that may contain uninitialized
or garbage data depending on STL implementation (VC6/STLPort vs Win32). Without
explicit initialization, isEmpty() returns false even though the string contains
invalid data, causing extractCrashLocation to extract garbage ('T', '^', etc).
Solution: Initialize to empty at startup. This is the correct fix rather than
trying to validate content format, because:
1. isEmpty() is the intended check - now it works correctly
2. No heuristics needed to detect valid vs invalid content
3. Simpler and more maintainable code
4. Guaranteed consistent behavior across all builds
Previous attempts:
- a316c10: Added NULL/empty check (didn't help - string had content)
- 5a2ee72: Added two-space format check (didn't help - garbage started with spaces)
This fix addresses the root cause by ensuring isEmpty() is reliable.
Test results before fix:
- VC6: Shows 'T' or ' T' in Location
- Win32: Shows '^' or ' ^' in Location
- Debug: Shows corrupted data in Location
Expected after fix: All builds show empty Location when no exception.
Relates to TheSuperHackers#2069
|
Has merge conflicts. |
xezon
reviewed
Jan 17, 2026
JohnsterID
added a commit
to JohnsterID/GeneralsGameCode
that referenced
this pull request
Jan 20, 2026
…ne/Xvfb testing setup Review Findings: - Code quality: 9/10 - Excellent defensive programming and safety - Critical issue: Crash dialog not shown for real exceptions (80-90% of crashes) - PR comments: 6 concerns require attention from latest review (Jan 17) Key Issues Identified: 1. Comment TheSuperHackers#26: Simplify extractCrashLocation() - show 5 lines, remove filters 2. Comment TheSuperHackers#25: Buffer size confusion - 400 vs 512 char limit 3. Comment TheSuperHackers#23: 'Location: T' bug needs investigation 4. UnHandledExceptionFilter: Needs ReleaseCrash() call for real exceptions Required Actions (4-6 hours): - Refactor extractCrashLocation per Comment TheSuperHackers#26 (1-2h) - Address buffer size concerns (30min) - Fix 'Location: T' bug (30-60min) - Add UnHandledExceptionFilter fix (30min) Environment Setup: - Wine 11.0, widl, MinGW-w64 GCC 14, Xvfb, CMake installed - test-wine-xvfb.sh: Automated build and test script for Wine/Xvfb Documents Analyzed: - All 26 PR review comments from TheSuperHackers#2069 - TEST_CRASH_BRANCH_README.md (test-crash-dialog-capture) - IMPORTANT_CRASH_DIALOG_ISSUE.md (test-crash-dialog-capture) - CI_TEST_RESULTS_ANALYSIS.md (test-crash-dialog-capture) - CRASH_REVIEW_ANALYSIS.md (crash-message-review-analysis) Recommendation: NEEDS WORK before merge Status: Testing environment ready, detailed review complete
- Change crash report URL to GeneralsCrashReports repository - Fix buffer write order in extractCrashLocation to check bufferSize first - Replace manual whitespace checks with standard isspace function
…handling - Add comments explaining crash location extraction behavior - Fix overly conservative Unknown rejection that discarded partial stacks - Only reject if first line (crash location) is Unknown, not entire trace - Document 400 char limit rationale (512 byte buffer with safety margin) Previous behavior rejected any stack trace containing <Unknown> anywhere, which discarded partially useful traces where the crash location had symbols but deeper frames didn't. Now allows display of useful crash locations even when some stack frames lack symbol information.
… strings Add null and empty string checks after calling g_LastErrorDump.str() to handle cases where isEmpty() doesn't work reliably across different build configurations and STL implementations. Issue discovered in testing: Location field showed different values across builds when calling ReleaseCrash() without exception context: - Win32 Release: Empty (correct) - VC6 Release: Shows 'T' (incorrect - isEmpty() failed) - Win32 Debug: Shows corrupted data (incorrect - isEmpty() failed) The additional check ensures consistent behavior across all builds. This doesn't affect real crashes - exceptions always populate g_LastErrorDump through DumpExceptionInfo() which properly clears and fills the string. Relates to TheSuperHackers#2069
Add check to verify stack trace starts with two spaces (valid format from
WriteStackLine). This prevents extraction of garbage/uninitialized data from
g_LastErrorDump when ReleaseCrash() is called without exception context.
Issue: Previous defensive check (!stackStr || !*stackStr) didn't work because
g_LastErrorDump contained garbage data ('T', '^', corrupted bytes) which are
not NULL or empty - they're just invalid.
Root cause: g_LastErrorDump is a global variable that may contain uninitialized
or leftover data. When ReleaseCrash() is called directly, DumpExceptionInfo()
never runs to clear() and populate it properly. Different STL implementations
(VC6/STLPort vs Win32) initialize globals differently, causing inconsistent
behavior across builds.
Solution: Valid stack traces from WriteStackLine() always start with " "
(two spaces). By checking for this prefix, we can distinguish between:
- Valid exception stack traces: " filename(line) : function" ✓
- Garbage data: "T", "^", corrupted bytes ✗
Test results before fix:
- VC6 Release: Shows "T" in Location field
- Win32 Release: Shows "^" in Location field
- Win32 Debug: Shows corrupted data in Location field
Expected after fix: All builds show empty Location field when no exception.
Relates to TheSuperHackers#2069
…) reliability
Explicitly call g_LastErrorDump.clear() in DebugInit() to ensure the global
AsciiString is properly initialized at program startup. This makes isEmpty()
work reliably across all build configurations.
Root cause: g_LastErrorDump is a global variable that may contain uninitialized
or garbage data depending on STL implementation (VC6/STLPort vs Win32). Without
explicit initialization, isEmpty() returns false even though the string contains
invalid data, causing extractCrashLocation to extract garbage ('T', '^', etc).
Solution: Initialize to empty at startup. This is the correct fix rather than
trying to validate content format, because:
1. isEmpty() is the intended check - now it works correctly
2. No heuristics needed to detect valid vs invalid content
3. Simpler and more maintainable code
4. Guaranteed consistent behavior across all builds
Previous attempts:
- a316c10: Added NULL/empty check (didn't help - string had content)
- 5a2ee72: Added two-space format check (didn't help - garbage started with spaces)
This fix addresses the root cause by ensuring isEmpty() is reliable.
Test results before fix:
- VC6: Shows 'T' or ' T' in Location
- Win32: Shows '^' or ' ^' in Location
- Debug: Shows corrupted data in Location
Expected after fix: All builds show empty Location when no exception.
Relates to TheSuperHackers#2069
…ptionFilter crash dialog Addresses review comments TheSuperHackers#7-11: - Simplified extractCrashLocation to show first 5 lines of stack trace - Removed arbitrary 400 char limit, now uses full buffer (bufferSize - 1) - Fixed buffer initialization order to prevent 'Location: T' garbage - Updated g_LastErrorDump comment to clarify static initialization timing - Show <Unknown> frames as-is without filtering - Added ReleaseCrash call to UnHandledExceptionFilter so crash dialog appears for unhandled exceptions, not just DEBUG_CRASH macro calls
JohnsterID
force-pushed
the
improve-crash-message
branch
from
March 18, 2026 08:38
0e72c06 to
ad38778
Compare
JohnsterID
marked this pull request as ready for review
March 22, 2026 07:13
|
| Filename | Overview |
|---|---|
| Core/GameEngine/Source/Common/System/Debug.cpp | Core crash dialog logic rewritten — adds crash-path info, GitHub link, and stack-trace location excerpt. Three new comment headers are dated 2025 (violating the current-year rule) and two MessageBox calls switched from nullptr to NULL. |
| Generals/Code/Main/WinMain.cpp | Adds a ReleaseCrash("Unhandled exception") call in UnHandledExceptionFilter so users see the new crash dialog for all unhandled exceptions, not just explicit DEBUG_CRASH calls. |
| GeneralsMD/Code/Main/WinMain.cpp | Identical change to Generals/Code/Main/WinMain.cpp, applied to the Zero Hour variant of the exception filter. |
Sequence Diagram
sequenceDiagram
participant OS as Windows SEH
participant UEF as UnHandledExceptionFilter
participant MD as MiniDumper
participant RC as ReleaseCrash
participant MB as MessageBox
OS->>UEF: Unhandled exception
UEF->>UEF: DumpExceptionInfo()
UEF->>MD: TriggerMiniDumpForException(Minimal)
UEF->>MD: TriggerMiniDumpForException(Full)
UEF->>MD: shutdownMiniDumper()
UEF->>RC: ReleaseCrash("Unhandled exception") [NEW]
RC->>RC: TriggerMiniDump() (guarded — dumper already shut down)
RC->>RC: Build message (path + stack excerpt + GitHub link)
RC->>MB: MessageBox("Game Crash", ...)
MB-->>RC: User clicks OK
RC->>RC: _exit(1)
Prompt To Fix All With AI
This is a comment left during a code review.
Path: Core/GameEngine/Source/Common/System/Debug.cpp
Line: 908
Comment:
**NULL instead of nullptr**
`NULL` is used here for the `HWND` parameter, but the codebase uses `nullptr` for null pointer literals. The original code used `nullptr` for this same parameter; this change introduces an inconsistency.
```suggestion
::MessageBox(nullptr, buff, "Game Crash", MB_OK|MB_SYSTEMMODAL|MB_ICONERROR);
```
**Rule Used:** Use nullptr instead of NULL for null pointer liter... ([source](https://app.greptile.com/review/custom-context?memory=c69cf1a9-c69a-4330-a013-69bb5d6701da))
**Learnt From**
[TheSuperHackers/GeneralsGameCode#2067](https://github.com/TheSuperHackers/GeneralsGameCode/pull/2067#discussion_r2703746722)
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: Core/GameEngine/Source/Common/System/Debug.cpp
Line: 959
Comment:
**NULL instead of nullptr**
`NULL` is used for the `HWND` parameter to `MessageBoxW`, which expects a pointer type. Use `nullptr` to stay consistent with the project style and the original code.
```suggestion
::MessageBoxW(nullptr, fullMessage.str(), prompt.str(), MB_OK|MB_SYSTEMMODAL|MB_ICONERROR);
```
**Rule Used:** Use nullptr instead of NULL for null pointer liter... ([source](https://app.greptile.com/review/custom-context?memory=c69cf1a9-c69a-4330-a013-69bb5d6701da))
**Learnt From**
[TheSuperHackers/GeneralsGameCode#2067](https://github.com/TheSuperHackers/GeneralsGameCode/pull/2067#discussion_r2703746722)
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: Core/GameEngine/Source/Common/System/Debug.cpp
Line: 757
Comment:
**Comment date references 2025**
The comment date `06/01/2025` is prior to the current year (2026). All three newly added comment headers in this file carry the same 2025 date (`extractCrashLocation` at line 757, `ReleaseCrash` at line 866, and `ReleaseCrashLocalized` at line 935). These should be updated to a 2026 date.
```suggestion
// TheSuperHackers @bugfix JohnsterID 06/01/2026 Helper function to extract crash location from stack trace.
```
**Rule Used:** What: Flag newly created code comments that refere... ([source](https://app.greptile.com/review/custom-context?memory=fd72a556-4fd8-4db4-8b08-8e51516a64ad))
How can I resolve this? If you propose a fix, please make it concise.Last reviewed commit: "Fix review feedback:..."
Caball009
marked this pull request as draft
August 26, 2026 08:11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.