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.
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. |
|
I'm inclined to leave out the Is this PR going to be squashed and merged? Otherwise I'll have to rename the commit names. |
xezon
left a comment
There was a problem hiding this comment.
In hindsight it would have been good if each fix had its own pull, because we needed to discuss quite a bit here.
We can merge with Squash or Rebase. Both are ok.
| void FixupScoreScreenMovieWindow(); | ||
| FixupScoreScreenMovieWindow(); | ||
|
|
||
| destroyQuitMenu(); |
There was a problem hiding this comment.
Is this ok to call always? When a replay auto ends, then there will be no quit menu to destroy?
| AudioRequest::~AudioRequest() | ||
| { | ||
|
|
||
| if (m_usePendingEvent) |
There was a problem hiding this comment.
This branch still contains the audio request fix. It needs to be removed.
| } | ||
| else if (TheChallengeGameInfo) | ||
| { | ||
| delete TheChallengeGameInfo; |
There was a problem hiding this comment.
Maybe delete them on game shutdown instead? Because it looks like they don't need to be recreated when all callsites already check for nullptr before allocation.
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: