bugfix(lan): Fix crash when changing settings in the LAN lobby#2676
bugfix(lan): Fix crash when changing settings in the LAN lobby#2676Caball009 wants to merge 1 commit intoTheSuperHackers:mainfrom
Conversation
|
| Filename | Overview |
|---|---|
| GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/LanGameOptionsMenu.cpp | Adds early-return guards in four message-handler cases to ignore option changes after DeinitLanGameGadgets nulls the gadget pointers; however, the new guards dereference TheLAN->GetMyGame() without a null check, inconsistent with the existing null-guarded pattern at line 825. |
Sequence Diagram
sequenceDiagram
participant UI as GUI / Input
participant Sys as LanGameOptionsMenuSystem
participant LAN as TheLAN
participant Gadgets as DeinitLanGameGadgets
Note over Gadgets: Called during countdown (1→0)
Gadgets->>Gadgets: Sets comboBox*, button*, textEntry* → nullptr
UI->>Sys: GCM_SELECTED / GBM_SELECTED / GBM_SELECTED_RIGHT / GEM_EDIT_DONE
Sys->>LAN: GetMyGame()
alt myGame == nullptr
LAN-->>Sys: nullptr
Sys->>Sys: *** CRASH: myGame->isGameInProgress() ***
else myGame != nullptr
LAN-->>Sys: LANGameInfo*
Sys->>Sys: isGameInProgress() → true
Sys-->>UI: MSG_IGNORED ✓ crash prevented
end
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 1
GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/LanGameOptionsMenu.cpp:1156-1158
**Missing null check before `isGameInProgress()` call**
`TheLAN->GetMyGame()` can return `nullptr` — the existing code at line 825 of this same file already accounts for this with an explicit null guard: `if (TheLAN->GetMyGame() && TheLAN->GetMyGame()->isGameInProgress())`. All four new `myGame->isGameInProgress()` checks in this PR skip that guard, so if `GetMyGame()` ever returns `nullptr` in a message-handler context (e.g., after the LAN session is partially torn down), the fix itself will crash at the same dereference it is trying to prevent.
```suggestion
LANGameInfo* myGame = TheLAN->GetMyGame();
if (!myGame || myGame->isGameInProgress())
return MSG_IGNORED;
```
Reviews (1): Last reviewed commit: "bugfix(lan): Fix crash when changing set..." | Re-trigger Greptile
| break; | ||
|
|
||
| LANGameInfo* myGame = TheLAN->GetMyGame(); | ||
| if (myGame->isGameInProgress()) |
There was a problem hiding this comment.
It is very suspicious that the menu can still be interacted with after it was shutdown. Why is this possible? Is there maybe a general issue with menus?
There was a problem hiding this comment.
I don't think this is because of a general issues with menus. The game just nulls the button pointers before it changes the window / takes away control from the user.
Perhaps from user perspective the cleanest solution would be to disable (grey out) the buttons when the timer has zero seconds remaining. I don't know how to access the buttons in the code that has access to the timer, though.
There was a problem hiding this comment.
It would be good if the window is changed or control is taken before the button pointers are nulled. That way no special safe guards need to be placed in multiple handlers.
Is the issue maybe that the handling of a button press is delayed by 1 or multiple frames because of input system updates, and so it can arrive after the menu screen was destroyed? If so, maybe the solution here is to add a condition into every menu input handler and check that the owning menu is still active, and if not, return early and do not handle the input.
It's currently possible to crash the game with a well-timed option change in the LAN lobby / options menu. The game calls
DeinitLanGameGadgets, which sets a few pointers tonullptr, when the countdown is somewhere between 1 and game start. If the options are changed after this (but before the game the actually starts), the game crashes because it attempts to dereference the pointers.This PR adds a few checks in
LanGameOptionsMenuSystemto ignore such changes.Callstack for
DeinitLanGameGadgets:Callstack for crash (in this case changing the super weapon limit):
TODO: