fix(memory): Fix various memory leaks (2)#2710
Conversation
|
| Filename | Overview |
|---|---|
| Core/GameEngine/Source/Common/Audio/AudioRequest.cpp | Adds destructor to delete m_pendingEvent when m_usePendingEvent is true, fixing the leak when requests are discarded (e.g. on pause). |
| Core/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp | Restructures clearGameData to add destroyQuitMenu and TheSkirmishGameInfo/TheChallengeGameInfo deletion; the campaign Next Mission crash on deletion of TheChallengeGameInfo is acknowledged but unresolved. |
| Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp | Resets m_usePendingEvent and m_pendingEvent to prevent double-free after processRequest takes ownership of the audio event. |
| Core/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp | Moves getAnimHandle() call (which AddRefs) inside the m_renderObject null guard, preventing a ref-count leak when m_renderObject is null. |
| Core/Libraries/Source/WWVegas/WW3D2/hcanim.cpp | Scopes tc_chan/ad_chan/newbitchan variables to their case blocks and deletes the channel object on Load_W3D failure, fixing leaks on partial animation load. |
| Core/Libraries/Source/WWVegas/WW3D2/seglinerenderer.cpp | Replaces Get_Texture() (which AddRefs) with Peek_Texture() in the debug warning path, preventing an unmatched reference count increase. |
| GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp | Adds deleteInstance(upgrade) inside the upgrade guard and moves markUIDirty() inside the same guard; correctly fixes the cancel-upgrade leak. |
| GeneralsMD/Code/GameEngine/Source/Common/System/SaveGame/GameStateMap.cpp | Adds delete[] buffer before each error-path throw in embedPristineMap, embedInUseMap, and extractAndSaveMap; all three sites have a non-null buffer at those points. |
| GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp | Replaces the heap-allocated singleton DynamicAudioEventInfo marker with a static subclass instance (DynamicAudioEventInfoStatic), avoiding both the static-init-order fiasco and the leak. |
| GeneralsMD/Code/GameEngine/Source/GameLogic/Map/SidesList.cpp | Adds deleteInstance for scripts that cannot be matched to a skirmish side, preventing a leak during prepareForMP_or_Skirmish. |
| GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/BattlePlanUpdate.cpp | Adds deleteInstance(m_bonuses) in the destructor, fixing the per-Strategy-Center build leak. |
| GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/hrawanim.cpp | Scopes newchan/newbitchan to their case blocks and correctly deletes the channel on Load_W3D failure, fixing leaks on partial animation load. |
| GeneralsMD/Code/Tools/WorldBuilder/src/ScriptDialog.cpp | Adds deleteInstance for scripts that cannot be matched to a player side or whose target side has no existing script list, preventing leaks during script import. |
Reviews (4): Last reviewed commit: "Addressed feedback & made tweaks." | Re-trigger Greptile
| if (TheSkirmishGameInfo) | ||
| { | ||
| delete TheSkirmishGameInfo; | ||
| TheSkirmishGameInfo = nullptr; | ||
| TheGameInfo = nullptr; | ||
| } | ||
| else if (TheChallengeGameInfo) | ||
| { | ||
| delete TheChallengeGameInfo; | ||
| TheChallengeGameInfo = nullptr; | ||
| TheGameInfo = nullptr; | ||
| } |
There was a problem hiding this comment.
TheChallengeGameInfo deletion breaks the challenge campaign "Next Mission" flow
clearGameData(TRUE) (which shows the score screen) now unconditionally deletes TheChallengeGameInfo. In ScoreScreen.cpp, startNextCampaignGame() immediately asserts TheChallengeGameInfo != nullptr (line 200) before re-configuring it for the next mission. Since clearGameData() runs before the score screen updates, TheChallengeGameInfo is already null by the time the player clicks "Next Mission", causing an assertion failure / crash on every challenge campaign mission transition.
The same applies to TheSkirmishGameInfo being set to null before ScoreScreenUpdate() uses TheGameInfo (line 428 of ScoreScreen.cpp) to start score-screen music, silently breaking score-screen music for all regular skirmish games.
A targeted fix would guard these deletions to only run when the game info was allocated during a save-game load (e.g. by checking an additional flag or by only deleting when isLoadingSave() was true).
Prompt To Fix With AI
This is a comment left during a code review.
Path: Core/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp
Line: 283-294
Comment:
**`TheChallengeGameInfo` deletion breaks the challenge campaign "Next Mission" flow**
`clearGameData(TRUE)` (which shows the score screen) now unconditionally deletes `TheChallengeGameInfo`. In `ScoreScreen.cpp`, `startNextCampaignGame()` immediately asserts `TheChallengeGameInfo != nullptr` (line 200) before re-configuring it for the next mission. Since `clearGameData()` runs _before_ the score screen updates, `TheChallengeGameInfo` is already null by the time the player clicks "Next Mission", causing an assertion failure / crash on every challenge campaign mission transition.
The same applies to `TheSkirmishGameInfo` being set to null before `ScoreScreenUpdate()` uses `TheGameInfo` (line 428 of `ScoreScreen.cpp`) to start score-screen music, silently breaking score-screen music for all regular skirmish games.
A targeted fix would guard these deletions to only run when the game info was allocated during a save-game load (e.g. by checking an additional flag or by only deleting when `isLoadingSave()` was true).
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
Good point.
A targeted fix would guard these deletions to only run when the game info was allocated during a save-game load (e.g. by checking an additional flag or by only deleting when isLoadingSave() was true).
This doesn't fix the crash that happens when restarting a challenge match from the 'score screen'. I could use some suggestions where these deallocations are better suited to take place.
| processRequest(req); | ||
|
|
||
| // TheSuperHackers @info Deallocating the audio event is no longer responsibility of this request, | ||
| // because it was just processed. Reset fields to avoid double free. |
There was a problem hiding this comment.
This does not fit under the umbrella of memory leaks, but memory corruptions.
There was a problem hiding this comment.
This is an essential part of fixing the memory leak.
There was a problem hiding this comment.
A memory corruption typically classifies more severe than a memory leak. Therefore I would typically classify it as such first.
Are there particular changes / commits that you'd like in a separate PR? |
I would say any fixes that span multiple files are good candidates for separation. |
| // TheSuperHackers @info Deallocating the audio event is no longer responsibility of this request, | ||
| // because it was just processed. Reset fields to avoid double free. | ||
| req->m_usePendingEvent = false; | ||
| req->m_pendingEvent = nullptr; |
This PR fixes 10 memory leaks (in order of commits):
BattlePlanUpdate::m_bonuseswas never deallocated, so every time a USA Strategy Center was built, there'd be a leak.SegLineRendererClass::Get_Texturehas a side effect as it increases the reference count, so shouldn't be used here.DynamicAudioEventInfoand everything it would allocate would not be deallocated before the game process ends, and show up as a leak.TheSkirmishGameInfoorTheChallengeGameInfobut not deallocate them.TODO: