From 8f1afe48b7ed153aecce38d263d19c7a10da5292 Mon Sep 17 00:00:00 2001 From: Caball009 <82909616+Caball009@users.noreply.github.com> Date: Wed, 13 May 2026 21:46:29 +0200 Subject: [PATCH 01/11] Added deletes to prevent potential memory leaks. --- Core/Libraries/Source/WWVegas/WW3D2/hcanim.cpp | 17 ++++++++++++----- .../Common/System/SaveGame/GameStateMap.cpp | 8 ++++++++ .../Libraries/Source/WWVegas/WW3D2/hrawanim.cpp | 11 ++++++++--- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/Core/Libraries/Source/WWVegas/WW3D2/hcanim.cpp b/Core/Libraries/Source/WWVegas/WW3D2/hcanim.cpp index 704898a8875..75af56396a0 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/hcanim.cpp +++ b/Core/Libraries/Source/WWVegas/WW3D2/hcanim.cpp @@ -293,10 +293,6 @@ int HCompressedAnimClass::Load_W3D(ChunkLoadClass & cload) /* ** Now, read in all of the other chunks (motion channels). */ - TimeCodedMotionChannelClass * tc_chan; - AdaptiveDeltaMotionChannelClass * ad_chan; - TimeCodedBitChannelClass * newbitchan; - while (cload.Open_Chunk()) { switch (cload.Cur_Chunk_ID()) { @@ -306,8 +302,10 @@ int HCompressedAnimClass::Load_W3D(ChunkLoadClass & cload) switch ( Flavor ) { case ANIM_FLAVOR_TIMECODED: - + { + TimeCodedMotionChannelClass* tc_chan = nullptr; if (!read_channel(cload,&tc_chan)) { + delete tc_chan; goto Error; } if (tc_chan->Get_Pivot() < NumNodes) { @@ -322,9 +320,13 @@ int HCompressedAnimClass::Load_W3D(ChunkLoadClass & cload) } break; + } case ANIM_FLAVOR_ADAPTIVE_DELTA: + { + AdaptiveDeltaMotionChannelClass* ad_chan = nullptr; if (!read_channel(cload,&ad_chan)) { + delete ad_chan; goto Error; } if (ad_chan->Get_Pivot() < NumNodes) { @@ -338,11 +340,15 @@ int HCompressedAnimClass::Load_W3D(ChunkLoadClass & cload) WWDEBUG_SAY(("ERROR! animation %s indexes a bone not present in the model. Please re-export!",Name)); } break; + } } break; case W3D_CHUNK_COMPRESSED_BIT_CHANNEL: + { + TimeCodedBitChannelClass* newbitchan = nullptr; if (!read_bit_channel(cload,&newbitchan)) { + delete newbitchan; goto Error; } if (newbitchan->Get_Pivot() < NumNodes) { @@ -357,6 +363,7 @@ int HCompressedAnimClass::Load_W3D(ChunkLoadClass & cload) } break; + } default: break; diff --git a/GeneralsMD/Code/GameEngine/Source/Common/System/SaveGame/GameStateMap.cpp b/GeneralsMD/Code/GameEngine/Source/Common/System/SaveGame/GameStateMap.cpp index b2c4d3fba4c..1771acdb4d8 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/System/SaveGame/GameStateMap.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/System/SaveGame/GameStateMap.cpp @@ -104,6 +104,8 @@ static void embedPristineMap( AsciiString map, Xfer *xfer ) if( file->read( buffer, fileSize ) != fileSize ) { + delete[] buffer; + DEBUG_CRASH(( "embedPristineMap - Error reading from file '%s'", map.str() )); throw SC_INVALID_DATA; @@ -161,6 +163,8 @@ static void embedInUseMap( AsciiString map, Xfer *xfer ) if( fread( buffer, 1, fileSize, fp ) != fileSize ) { + delete[] buffer; + DEBUG_CRASH(( "embedInUseMap - Error reading from file '%s'", map.str() )); throw SC_INVALID_DATA; @@ -204,6 +208,8 @@ static void extractAndSaveMap( AsciiString mapToSave, Xfer *xfer ) if( buffer == nullptr ) { + delete[] buffer; + DEBUG_CRASH(( "extractAndSaveMap - Unable to allocate buffer for file '%s'", mapToSave.str() )); throw SC_INVALID_DATA; @@ -216,6 +222,8 @@ static void extractAndSaveMap( AsciiString mapToSave, Xfer *xfer ) if( fwrite( buffer, 1, dataSize, fp ) != dataSize ) { + delete[] buffer; + DEBUG_CRASH(( "extractAndSaveMap - Error writing to file '%s'", mapToSave.str() )); throw SC_INVALID_DATA; diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/hrawanim.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/hrawanim.cpp index 54fdfb732e3..041403c8b95 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/hrawanim.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/hrawanim.cpp @@ -236,15 +236,15 @@ int HRawAnimClass::Load_W3D(ChunkLoadClass & cload) /* ** Now, read in all of the other chunks (motion channels). */ - MotionChannelClass * newchan; - BitChannelClass * newbitchan; - while (cload.Open_Chunk()) { switch (cload.Cur_Chunk_ID()) { case W3D_CHUNK_ANIMATION_CHANNEL: + { + MotionChannelClass* newchan = nullptr; if (!read_channel(cload,&newchan,pre30)) { + delete newchan; goto Error; } @@ -258,9 +258,13 @@ int HRawAnimClass::Load_W3D(ChunkLoadClass & cload) delete newchan; } break; + } case W3D_CHUNK_BIT_CHANNEL: + { + BitChannelClass* newbitchan = nullptr; if (!read_bit_channel(cload,&newbitchan,pre30)) { + delete newbitchan; goto Error; } @@ -274,6 +278,7 @@ int HRawAnimClass::Load_W3D(ChunkLoadClass & cload) delete newbitchan; } break; + } default: break; From 707f194f90f7fb518f5a1322a87959b1c5658e30 Mon Sep 17 00:00:00 2001 From: Caball009 <82909616+Caball009@users.noreply.github.com> Date: Wed, 13 May 2026 21:48:48 +0200 Subject: [PATCH 02/11] Fixed 'BattlePlan bonus' memory leak. --- .../Source/GameLogic/Object/Update/BattlePlanUpdate.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/BattlePlanUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/BattlePlanUpdate.cpp index d4d0cead9dd..333d39662c1 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/BattlePlanUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/BattlePlanUpdate.cpp @@ -164,6 +164,7 @@ BattlePlanUpdate::~BattlePlanUpdate() TheAudio->removeAudioEvent( m_holdTheLineUnpack.getPlayingHandle() ); TheAudio->removeAudioEvent( m_holdTheLinePack.getPlayingHandle() ); + deleteInstance(m_bonuses); } // ------------------------------------------------------------------------------------------------ From 8fe08f6721984daf580726b46664d474e292c2dc Mon Sep 17 00:00:00 2001 From: Caball009 <82909616+Caball009@users.noreply.github.com> Date: Wed, 13 May 2026 21:50:46 +0200 Subject: [PATCH 03/11] Fixed memory leak in line renderer texture. --- Core/Libraries/Source/WWVegas/WW3D2/seglinerenderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/Libraries/Source/WWVegas/WW3D2/seglinerenderer.cpp b/Core/Libraries/Source/WWVegas/WW3D2/seglinerenderer.cpp index 681c4c0b0fa..9b5970062ee 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/seglinerenderer.cpp +++ b/Core/Libraries/Source/WWVegas/WW3D2/seglinerenderer.cpp @@ -191,7 +191,7 @@ void SegLineRendererClass::Set_Texture_Tile_Factor(float factor) ///@todo: I raised this number and didn't see much difference on our min-spec. -MW const static float MAX_LINE_TILING_FACTOR = 50.0f; if (factor > MAX_LINE_TILING_FACTOR) { - WWDEBUG_SAY(("Texture (%s) Tile Factor (%.2f) too large in SegLineRendererClass!", Get_Texture()->Get_Texture_Name().str(), TextureTileFactor)); + WWDEBUG_SAY(("Texture (%s) Tile Factor (%.2f) too large in SegLineRendererClass!", Peek_Texture()->Get_Texture_Name().str(), TextureTileFactor)); factor = MAX_LINE_TILING_FACTOR; } else { factor = MAX(factor, 0.0f); From d713e62fef04a562c65809318e7b79a3cf3a65ef Mon Sep 17 00:00:00 2001 From: Caball009 <82909616+Caball009@users.noreply.github.com> Date: Wed, 13 May 2026 21:51:37 +0200 Subject: [PATCH 04/11] Fixed removed 'Upgrade' memory leak. --- .../Code/GameEngine/Source/Common/RTS/Player.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp b/GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp index a9a53e3a006..b7b5e5edc6a 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp @@ -3167,13 +3167,13 @@ void Player::removeUpgrade( const UpgradeTemplate *upgradeTemplate ) if( upgrade->getStatus() == UPGRADE_STATUS_COMPLETE ) onUpgradeRemoved(); - if( ThePlayerList->getLocalPlayer() == this ) - { - TheControlBar->markUIDirty(); - } + deleteInstance(upgrade); + if( ThePlayerList->getLocalPlayer() == this ) + { + TheControlBar->markUIDirty(); + } } - } From 41a3d91efade3dae7772257496da19193003485c Mon Sep 17 00:00:00 2001 From: Caball009 <82909616+Caball009@users.noreply.github.com> Date: Wed, 13 May 2026 21:53:21 +0200 Subject: [PATCH 05/11] Fixed script list memory leaks. --- .../Code/GameEngine/Source/GameLogic/Map/SidesList.cpp | 7 ++++++- GeneralsMD/Code/Tools/WorldBuilder/src/ScriptDialog.cpp | 9 +++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Map/SidesList.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Map/SidesList.cpp index 679ee2160f3..b2c05e49597 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Map/SidesList.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Map/SidesList.cpp @@ -544,7 +544,12 @@ void SidesList::prepareForMP_or_Skirmish() break; } } - if (curSide == -1) continue; + if (curSide == -1) + { + deleteInstance(scripts[i]); + scripts[i] = nullptr; + continue; + } deleteInstance(getSkirmishSideInfo(curSide)->getScriptList()); getSkirmishSideInfo(curSide)->setScriptList(scripts[i]); diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/ScriptDialog.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/ScriptDialog.cpp index fd36b02b024..27af92ec44a 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/ScriptDialog.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/ScriptDialog.cpp @@ -1584,6 +1584,9 @@ void ScriptDialog::OnLoad() msg += m_readPlayerNames[i].str(); msg += ", discarding scripts for this player."; ::AfxMessageBox(msg); + + deleteInstance(scripts[i]); + scripts[i] = nullptr; continue; } } @@ -1591,8 +1594,8 @@ void ScriptDialog::OnLoad() curSide = 0; ::AfxMessageBox("Imported scripts came from more players than exist in this map. Additional scripts moved to Neutral player."); } - ScriptList *pSL = m_sides.getSideInfo(curSide)->getScriptList(); + ScriptList *pSL = m_sides.getSideInfo(curSide)->getScriptList(); if (pSL) { Script *pScr; Script *pNextScr; @@ -1616,8 +1619,10 @@ void ScriptDialog::OnLoad() copied into the current scripts. */ scripts[i] = nullptr; //reloadPlayer(curSide, pSL); + } else { + deleteInstance(scripts[i]); + scripts[i] = nullptr; } - } for (i = 0; i < m_sides.getNumSides(); i++) { From d87c02edb874a8273a1cd9b50dd69159191324e7 Mon Sep 17 00:00:00 2001 From: Caball009 <82909616+Caball009@users.noreply.github.com> Date: Wed, 13 May 2026 21:54:42 +0200 Subject: [PATCH 06/11] Fixed animation memory leak. --- .../GameClient/Drawable/Draw/W3DModelDraw.cpp | 78 ++++++++++--------- 1 file changed, 40 insertions(+), 38 deletions(-) diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp index d5d1fd7f292..3b46fe5a5e4 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DModelDraw.cpp @@ -2180,51 +2180,53 @@ void W3DModelDraw::adjustAnimation(const ModelConditionInfo* prevState, Real pre const W3DAnimationInfo& animInfo = m_curState->m_animations[m_whichAnimInCurState]; - HAnimClass* animHandle = animInfo.getAnimHandle(); // note that this now returns an ADDREFED handle, which must be released by the caller! - if (m_renderObject && animHandle) + if (m_renderObject) { - Int startFrame = 0; - if (m_curState->m_mode == RenderObjClass::ANIM_MODE_ONCE_BACKWARDS || - m_curState->m_mode == RenderObjClass::ANIM_MODE_LOOP_BACKWARDS) + HAnimClass* animHandle = animInfo.getAnimHandle(); // note that this now returns an ADDREFED handle, which must be released by the caller! + if (animHandle) { - startFrame = animHandle->Get_Num_Frames()-1; - } + Int startFrame = 0; + if (m_curState->m_mode == RenderObjClass::ANIM_MODE_ONCE_BACKWARDS || + m_curState->m_mode == RenderObjClass::ANIM_MODE_LOOP_BACKWARDS) + { + startFrame = animHandle->Get_Num_Frames()-1; + } - if (testFlagBit(m_curState->m_flags, RANDOMIZE_START_FRAME)) - { - startFrame = GameClientRandomValue(0, animHandle->Get_Num_Frames()-1); - } - else if (testFlagBit(m_curState->m_flags, START_FRAME_FIRST)) - { - startFrame = 0; - } - else if (testFlagBit(m_curState->m_flags, START_FRAME_LAST)) - { - startFrame = animHandle->Get_Num_Frames()-1; - } - // order is important here: MAINTAIN_FRAME_ACROSS_STATES is overridden by the other bits, above. - else if (isAnyMaintainFrameFlagSet(m_curState->m_flags) && - prevState && - prevState != m_curState && - isAnyMaintainFrameFlagSet(prevState->m_flags) && - isCommonMaintainFrameFlagSet(m_curState->m_flags, prevState->m_flags) && - prevAnimFraction >= 0.0) - { - startFrame = REAL_TO_INT(prevAnimFraction * animHandle->Get_Num_Frames()-1); - } + if (testFlagBit(m_curState->m_flags, RANDOMIZE_START_FRAME)) + { + startFrame = GameClientRandomValue(0, animHandle->Get_Num_Frames()-1); + } + else if (testFlagBit(m_curState->m_flags, START_FRAME_FIRST)) + { + startFrame = 0; + } + else if (testFlagBit(m_curState->m_flags, START_FRAME_LAST)) + { + startFrame = animHandle->Get_Num_Frames()-1; + } + // order is important here: MAINTAIN_FRAME_ACROSS_STATES is overridden by the other bits, above. + else if (isAnyMaintainFrameFlagSet(m_curState->m_flags) && + prevState && + prevState != m_curState && + isAnyMaintainFrameFlagSet(prevState->m_flags) && + isCommonMaintainFrameFlagSet(m_curState->m_flags, prevState->m_flags) && + prevAnimFraction >= 0.0) + { + startFrame = REAL_TO_INT(prevAnimFraction * animHandle->Get_Num_Frames()-1); + } - m_renderObject->Set_Animation(animHandle, startFrame, m_curState->m_mode); - REF_PTR_RELEASE(animHandle); - animHandle = nullptr; + m_renderObject->Set_Animation(animHandle, startFrame, m_curState->m_mode); + REF_PTR_RELEASE(animHandle); + animHandle = nullptr; - if (m_renderObject->Class_ID() == RenderObjClass::CLASSID_HLOD) - { - HLodClass *hlod = (HLodClass*)m_renderObject; - Real factor = GameClientRandomValueReal( m_curState->m_animMinSpeedFactor, m_curState->m_animMaxSpeedFactor ); - hlod->Set_Animation_Frame_Rate_Multiplier( factor ); + if (m_renderObject->Class_ID() == RenderObjClass::CLASSID_HLOD) + { + HLodClass *hlod = (HLodClass*)m_renderObject; + Real factor = GameClientRandomValueReal( m_curState->m_animMinSpeedFactor, m_curState->m_animMaxSpeedFactor ); + hlod->Set_Animation_Frame_Rate_Multiplier( factor ); + } } } - } else { From 2b1c2d95f71258827f482ec9e570947f1e97c508 Mon Sep 17 00:00:00 2001 From: Caball009 <82909616+Caball009@users.noreply.github.com> Date: Wed, 13 May 2026 22:03:28 +0200 Subject: [PATCH 07/11] Fixed 'QuitMenu' memory leak. --- Core/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Core/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp b/Core/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp index c002ff8f239..b0f814545af 100644 --- a/Core/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp +++ b/Core/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp @@ -272,6 +272,8 @@ void GameLogic::clearGameData( Bool showScoreScreen ) void FixupScoreScreenMovieWindow(); FixupScoreScreenMovieWindow(); + + destroyQuitMenu(); } TheGameEngine->reset(); From a49c8100f5d260013a58b07d0cfd14709f3f0ff0 Mon Sep 17 00:00:00 2001 From: Caball009 <82909616+Caball009@users.noreply.github.com> Date: Wed, 13 May 2026 22:04:42 +0200 Subject: [PATCH 08/11] Fixed 'AudioRequest' audio event memory leak. --- Core/GameEngine/Source/Common/Audio/AudioRequest.cpp | 5 ++++- .../Source/MilesAudioDevice/MilesAudioManager.cpp | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Core/GameEngine/Source/Common/Audio/AudioRequest.cpp b/Core/GameEngine/Source/Common/Audio/AudioRequest.cpp index a3235e1b69a..504a6381f28 100644 --- a/Core/GameEngine/Source/Common/Audio/AudioRequest.cpp +++ b/Core/GameEngine/Source/Common/Audio/AudioRequest.cpp @@ -30,5 +30,8 @@ AudioRequest::~AudioRequest() { - + if (m_usePendingEvent) + { + delete m_pendingEvent; + } } diff --git a/Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp b/Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp index 3a541494959..55452fa470d 100644 --- a/Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp +++ b/Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp @@ -2236,6 +2236,11 @@ void MilesAudioManager::processRequestList() if (!req->m_requiresCheckForSample || checkForSample(req)) { 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. + req->m_usePendingEvent = false; + req->m_pendingEvent = nullptr; } deleteInstance(req); it = m_audioRequests.erase(it); From 2e0fe765792980b4008ddfc0ec5f6dc09871091e Mon Sep 17 00:00:00 2001 From: Caball009 <82909616+Caball009@users.noreply.github.com> Date: Thu, 14 May 2026 18:38:02 +0200 Subject: [PATCH 09/11] Fixed 'getNoSoundMarker' memory leak. --- .../Code/GameEngine/Source/GameClient/Drawable.cpp | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp index 40abef67afe..2b89cbd061e 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp @@ -116,17 +116,10 @@ static_assert(ARRAY_SIZE(TheDrawableIconNames) == MAX_ICONS + 1, "Incorrect arra * * OK, so it's a bit of a hack, but it saves memory in every Drawable */ -static DynamicAudioEventInfo * getNoSoundMarker() +static DynamicAudioEventInfo* marker = newInstance(DynamicAudioEventInfo); +static DynamicAudioEventInfo* getNoSoundMarker() { - static DynamicAudioEventInfo * marker = nullptr; - - if ( marker == nullptr ) - { - // Initialize first time function is called - marker = newInstance( DynamicAudioEventInfo ); - } - - return marker; + return marker; } From 229839f6bee110c019227f512dde76d71980b0cc Mon Sep 17 00:00:00 2001 From: Caball009 <82909616+Caball009@users.noreply.github.com> Date: Thu, 14 May 2026 18:40:46 +0200 Subject: [PATCH 10/11] Added workaround for 'TheSkirmishGameInfo' and 'TheChallengeGameInfo' memory leaks. --- .../GameLogic/System/GameLogicDispatch.cpp | 36 ++++++++++++++----- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/Core/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp b/Core/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp index b0f814545af..7519684a572 100644 --- a/Core/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp +++ b/Core/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp @@ -262,18 +262,36 @@ void GameLogic::clearGameData( Bool showScoreScreen ) TheScriptActions->closeWindows(FALSE); // Close victory or defeat windows. Bool shellGame = FALSE; - if ((!isInShellGame() || !isInGame()) && showScoreScreen && !TheGlobalData->m_headless) + if (showScoreScreen) { - shellGame = TRUE; - TheTransitionHandler->setGroup("FadeWholeScreen"); - TheShell->push("Menus/ScoreScreen.wnd"); - TheShell->showShell(FALSE); // by passing in false, we don't want to run the Init on the shell screen we just pushed on - TheTransitionHandler->reverse("FadeWholeScreen"); + if ((!isInShellGame() || !isInGame()) && !TheGlobalData->m_headless) + { + shellGame = TRUE; + TheTransitionHandler->setGroup("FadeWholeScreen"); + TheShell->push("Menus/ScoreScreen.wnd"); + TheShell->showShell(FALSE); // by passing in false, we don't want to run the Init on the shell screen we just pushed on + TheTransitionHandler->reverse("FadeWholeScreen"); + + void FixupScoreScreenMovieWindow(); + FixupScoreScreenMovieWindow(); - void FixupScoreScreenMovieWindow(); - FixupScoreScreenMovieWindow(); + destroyQuitMenu(); + } - destroyQuitMenu(); + // TheSuperHackers @info The game info may have been allocated on save game load. + // Deallocate it here until there's a better place to do it. + if (TheSkirmishGameInfo) + { + delete TheSkirmishGameInfo; + TheSkirmishGameInfo = nullptr; + TheGameInfo = nullptr; + } + else if (TheChallengeGameInfo) + { + delete TheChallengeGameInfo; + TheChallengeGameInfo = nullptr; + TheGameInfo = nullptr; + } } TheGameEngine->reset(); From 08a2a424e407d6f3e63a16ac1cf85db112990c35 Mon Sep 17 00:00:00 2001 From: Caball009 <82909616+Caball009@users.noreply.github.com> Date: Thu, 14 May 2026 20:13:51 +0200 Subject: [PATCH 11/11] Addressed feedback & made tweaks. --- .../MilesAudioDevice/MilesAudioManager.cpp | 2 +- .../Libraries/Source/WWVegas/WW3D2/hcanim.cpp | 51 ++++++++++++------- .../Common/System/SaveGame/GameStateMap.cpp | 2 - .../GameEngine/Source/GameClient/Drawable.cpp | 7 ++- .../Source/WWVegas/WW3D2/hrawanim.cpp | 45 ++++++++++------ 5 files changed, 68 insertions(+), 39 deletions(-) diff --git a/Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp b/Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp index 55452fa470d..3e1a832dca9 100644 --- a/Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp +++ b/Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp @@ -2238,7 +2238,7 @@ void MilesAudioManager::processRequestList() 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. + // because it was just processed. Reset fields to avoid use after free and double free. req->m_usePendingEvent = false; req->m_pendingEvent = nullptr; } diff --git a/Core/Libraries/Source/WWVegas/WW3D2/hcanim.cpp b/Core/Libraries/Source/WWVegas/WW3D2/hcanim.cpp index 75af56396a0..3bc866b7517 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/hcanim.cpp +++ b/Core/Libraries/Source/WWVegas/WW3D2/hcanim.cpp @@ -305,7 +305,6 @@ int HCompressedAnimClass::Load_W3D(ChunkLoadClass & cload) { TimeCodedMotionChannelClass* tc_chan = nullptr; if (!read_channel(cload,&tc_chan)) { - delete tc_chan; goto Error; } if (tc_chan->Get_Pivot() < NumNodes) { @@ -326,7 +325,6 @@ int HCompressedAnimClass::Load_W3D(ChunkLoadClass & cload) { AdaptiveDeltaMotionChannelClass* ad_chan = nullptr; if (!read_channel(cload,&ad_chan)) { - delete ad_chan; goto Error; } if (ad_chan->Get_Pivot() < NumNodes) { @@ -348,7 +346,6 @@ int HCompressedAnimClass::Load_W3D(ChunkLoadClass & cload) { TimeCodedBitChannelClass* newbitchan = nullptr; if (!read_bit_channel(cload,&newbitchan)) { - delete newbitchan; goto Error; } if (newbitchan->Get_Pivot() < NumNodes) { @@ -394,20 +391,32 @@ int HCompressedAnimClass::Load_W3D(ChunkLoadClass & cload) *=============================================================================================*/ bool HCompressedAnimClass::read_channel(ChunkLoadClass & cload,TimeCodedMotionChannelClass * * newchan) { - *newchan = W3DNEW TimeCodedMotionChannelClass; - bool result = (*newchan)->Load_W3D(cload); - - return result; - + TimeCodedMotionChannelClass* channel = W3DNEW TimeCodedMotionChannelClass; + if (channel->Load_W3D(cload)) + { + *newchan = channel; + return true; + } + else + { + delete channel; + return false; + } } bool HCompressedAnimClass::read_channel(ChunkLoadClass & cload,AdaptiveDeltaMotionChannelClass * * newchan) { - *newchan = W3DNEW AdaptiveDeltaMotionChannelClass; - bool result = (*newchan)->Load_W3D(cload); - - return result; - + AdaptiveDeltaMotionChannelClass* channel = W3DNEW AdaptiveDeltaMotionChannelClass; + if (channel->Load_W3D(cload)) + { + *newchan = channel; + return true; + } + else + { + delete channel; + return false; + } } @@ -490,11 +499,17 @@ void HCompressedAnimClass::add_channel(AdaptiveDeltaMotionChannelClass * newchan *=============================================================================================*/ bool HCompressedAnimClass::read_bit_channel(ChunkLoadClass & cload,TimeCodedBitChannelClass * * newchan) { - *newchan = W3DNEW TimeCodedBitChannelClass; - bool result = (*newchan)->Load_W3D(cload); - - return result; - + TimeCodedBitChannelClass* channel = W3DNEW TimeCodedBitChannelClass; + if (channel->Load_W3D(cload)) + { + *newchan = channel; + return true; + } + else + { + delete channel; + return false; + } } diff --git a/GeneralsMD/Code/GameEngine/Source/Common/System/SaveGame/GameStateMap.cpp b/GeneralsMD/Code/GameEngine/Source/Common/System/SaveGame/GameStateMap.cpp index 1771acdb4d8..f503e975f8c 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/System/SaveGame/GameStateMap.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/System/SaveGame/GameStateMap.cpp @@ -208,8 +208,6 @@ static void extractAndSaveMap( AsciiString mapToSave, Xfer *xfer ) if( buffer == nullptr ) { - delete[] buffer; - DEBUG_CRASH(( "extractAndSaveMap - Unable to allocate buffer for file '%s'", mapToSave.str() )); throw SC_INVALID_DATA; diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp index 2b89cbd061e..da55dbbf2d4 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp @@ -116,10 +116,13 @@ static_assert(ARRAY_SIZE(TheDrawableIconNames) == MAX_ICONS + 1, "Incorrect arra * * OK, so it's a bit of a hack, but it saves memory in every Drawable */ -static DynamicAudioEventInfo* marker = newInstance(DynamicAudioEventInfo); +class DynamicAudioEventInfoStatic : public DynamicAudioEventInfo +{}; +static DynamicAudioEventInfoStatic s_noSoundMarker; + static DynamicAudioEventInfo* getNoSoundMarker() { - return marker; + return &s_noSoundMarker; } diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/hrawanim.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/hrawanim.cpp index 041403c8b95..377e813236e 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/hrawanim.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/hrawanim.cpp @@ -244,7 +244,6 @@ int HRawAnimClass::Load_W3D(ChunkLoadClass & cload) { MotionChannelClass* newchan = nullptr; if (!read_channel(cload,&newchan,pre30)) { - delete newchan; goto Error; } @@ -258,13 +257,12 @@ int HRawAnimClass::Load_W3D(ChunkLoadClass & cload) delete newchan; } break; - } + } case W3D_CHUNK_BIT_CHANNEL: { BitChannelClass* newbitchan = nullptr; if (!read_bit_channel(cload,&newbitchan,pre30)) { - delete newbitchan; goto Error; } @@ -309,15 +307,22 @@ int HRawAnimClass::Load_W3D(ChunkLoadClass & cload) *=============================================================================================*/ bool HRawAnimClass::read_channel(ChunkLoadClass & cload,MotionChannelClass * * newchan,bool pre30) { - *newchan = W3DNEW MotionChannelClass; - bool result = (*newchan)->Load_W3D(cload); + MotionChannelClass* channel = W3DNEW MotionChannelClass; + if (channel->Load_W3D(cload)) + { + if (pre30) + { + channel->Set_Pivot(channel->Get_Pivot() + 1); + } - if (result && pre30) { -// (*newchan)->PivotIdx += 1; - (*newchan)->Set_Pivot((*newchan)->Get_Pivot()+1); + *newchan = channel; + return true; + } + else + { + delete channel; + return false; } - - return result; } /*********************************************************************************************** @@ -384,14 +389,22 @@ void HRawAnimClass::add_channel(MotionChannelClass * newchan) *=============================================================================================*/ bool HRawAnimClass::read_bit_channel(ChunkLoadClass & cload,BitChannelClass * * newchan,bool pre30) { - *newchan = W3DNEW BitChannelClass; - bool result = (*newchan)->Load_W3D(cload); + BitChannelClass* channel = W3DNEW BitChannelClass; + if (channel->Load_W3D(cload)) + { + if (pre30) + { + channel->PivotIdx += 1; + } - if (result && pre30) { - (*newchan)->PivotIdx += 1; + *newchan = channel; + return true; + } + else + { + delete channel; + return false; } - - return result; }