From bb5b0a204c891b826725ebafa1b18fa9aa4a72b2 Mon Sep 17 00:00:00 2001 From: Caball009 <82909616+Caball009@users.noreply.github.com> Date: Tue, 26 May 2026 16:23:51 +0200 Subject: [PATCH 1/6] Made hidden drawables visible. --- .../Source/GameLogic/Object/Contain/OpenContain.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp index 0da2deb1da7..fe5fc416978 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp @@ -343,6 +343,13 @@ void OpenContain::addToContain( Object *rider ) if (isEnclosingContainerFor( rider )) { addOrRemoveObjFromWorld(rider, false); + + // TheSuperHackers @tweak This shouldn't happen but make the occupants visible if it does. + if (getObject()->isEffectivelyDead() || getObject()->isDestroyed()) + { + if (Drawable* drawable = rider->getDrawable()) + drawable->setDrawableHidden(FALSE); + } } #if RETAIL_COMPATIBLE_CRC From 0844fa1617818c025882a84c8cb7e77824480734 Mon Sep 17 00:00:00 2001 From: Caball009 <82909616+Caball009@users.noreply.github.com> Date: Tue, 26 May 2026 16:25:14 +0200 Subject: [PATCH 2/6] Added logic to prevent occupant from entering a destroyed container object. --- .../Source/GameLogic/Object/Contain/OpenContain.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp index fe5fc416978..735b5eea160 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp @@ -292,6 +292,13 @@ void OpenContain::addToContain( Object *rider ) if( rider == nullptr ) return; +#if !RETAIL_COMPATIBLE_CRC + // TheSuperHackers @bugfix Caball009 25/05/2026 Ensure the occupant is only added to a non-destroyed + // container to avoid an invalid state and use-after-free bugs when accessing the contained by pointer. + if (getObject()->isDestroyed()) + return; +#endif + // TheSuperHackers @bugfix Stubbjax 06/02/2026 Ensure the rider is not destroyed to prevent a // likely crash if it enters the container on the same frame. If this occurs with an unpatched // client present in a match, the game has a small chance to mismatch. From ee3475dcebc5773ef647b25eacd4fc8b64b0b4b7 Mon Sep 17 00:00:00 2001 From: Caball009 <82909616+Caball009@users.noreply.github.com> Date: Tue, 26 May 2026 16:25:56 +0200 Subject: [PATCH 3/6] Added code to prevent the creation of the payload. --- .../GameLogic/Object/Contain/TransportContain.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/TransportContain.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/TransportContain.cpp index fe364eee869..d09af6e5f17 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/TransportContain.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/TransportContain.cpp @@ -469,8 +469,19 @@ UpdateSleepTime TransportContain::update() { const TransportContainModuleData *moduleData = getTransportContainModuleData(); - if( m_payloadCreated == FALSE ) + if (m_payloadCreated == FALSE) + { +#if RETAIL_COMPATIBLE_CRC createPayload(); +#else + // TheSuperHackers @bugfix Caball009 25/05/2026 Don't create payload + // for destroyed object to avoid an invalid state for the payload. + if (!getObject()->isDestroyed()) + { + createPayload(); + } +#endif + } if( moduleData && moduleData->m_healthRegen ) { From 735d8274117a8950c37161a5e0e7689c7e4389e0 Mon Sep 17 00:00:00 2001 From: Caball009 <82909616+Caball009@users.noreply.github.com> Date: Tue, 26 May 2026 16:26:15 +0200 Subject: [PATCH 4/6] Added debug assertions for destroyed container objects. --- .../Source/GameLogic/Object/Contain/OpenContain.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp index 735b5eea160..0e72ef0c3ad 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp @@ -296,14 +296,22 @@ void OpenContain::addToContain( Object *rider ) // TheSuperHackers @bugfix Caball009 25/05/2026 Ensure the occupant is only added to a non-destroyed // container to avoid an invalid state and use-after-free bugs when accessing the contained by pointer. if (getObject()->isDestroyed()) + { + DEBUG_CRASH(("'%s' is about to be added to '%s', which is destroyed", + rider->getTemplate()->getName().str(), getObject()->getTemplate()->getName().str())); return; + } #endif // TheSuperHackers @bugfix Stubbjax 06/02/2026 Ensure the rider is not destroyed to prevent a // likely crash if it enters the container on the same frame. If this occurs with an unpatched // client present in a match, the game has a small chance to mismatch. if (rider->isDestroyed()) + { + DEBUG_CRASH(("'%s', which is destroyed, is about to be added to '%s'", + rider->getTemplate()->getName().str(), getObject()->getTemplate()->getName().str())); return; + } Drawable *riderDraw = rider->getDrawable(); Bool wasSelected = FALSE; From 6544358bd188439fd31b0f2132e9c8684e5a0f36 Mon Sep 17 00:00:00 2001 From: Caball009 <82909616+Caball009@users.noreply.github.com> Date: Tue, 26 May 2026 16:35:53 +0200 Subject: [PATCH 5/6] Tweaked TSH comments. --- .../GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp | 2 +- .../Source/GameLogic/Object/Contain/TransportContain.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp index 0e72ef0c3ad..d61a8540a62 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp @@ -359,7 +359,7 @@ void OpenContain::addToContain( Object *rider ) { addOrRemoveObjFromWorld(rider, false); - // TheSuperHackers @tweak This shouldn't happen but make the occupants visible if it does. + // TheSuperHackers @tweak This shouldn't happen but make the occupant visible if it does. if (getObject()->isEffectivelyDead() || getObject()->isDestroyed()) { if (Drawable* drawable = rider->getDrawable()) diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/TransportContain.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/TransportContain.cpp index d09af6e5f17..cdadb37d560 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/TransportContain.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/TransportContain.cpp @@ -475,7 +475,7 @@ UpdateSleepTime TransportContain::update() createPayload(); #else // TheSuperHackers @bugfix Caball009 25/05/2026 Don't create payload - // for destroyed object to avoid an invalid state for the payload. + // for destroyed object to avoid leaving the payload in an invalid state. if (!getObject()->isDestroyed()) { createPayload(); From 9ad33a25b0fc3ef3596fb9706e4fa59e4b32a307 Mon Sep 17 00:00:00 2001 From: Caball009 <82909616+Caball009@users.noreply.github.com> Date: Wed, 27 May 2026 17:14:50 +0200 Subject: [PATCH 6/6] Moved call to 'Drawable::setDrawableHidden'. --- .../GameLogic/Object/Contain/OpenContain.cpp | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp index d61a8540a62..f9a001519c4 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp @@ -247,9 +247,17 @@ void OpenContain::addOrRemoveObjFromWorld(Object* obj, Bool add) // remove rider from partition manager ThePartitionManager->unRegisterObject( obj ); - // hide the drawable associated with rider - if( obj->getDrawable() ) - obj->getDrawable()->setDrawableHidden( true ); + if (Drawable* drawable = obj->getDrawable()) + { +#if RETAIL_COMPATIBLE_CRC + // TheSuperHackers @tweak This shouldn't happen but don't make the occupant invisible if it does. + if (!(getObject()->isEffectivelyDead() || getObject()->isDestroyed())) +#endif + { + // hide the drawable associated with rider + drawable->setDrawableHidden(true); + } + } // remove object from pathfind map TheAI->pathfinder()->removeObjectFromPathfindMap( obj ); @@ -358,13 +366,6 @@ void OpenContain::addToContain( Object *rider ) if (isEnclosingContainerFor( rider )) { addOrRemoveObjFromWorld(rider, false); - - // TheSuperHackers @tweak This shouldn't happen but make the occupant visible if it does. - if (getObject()->isEffectivelyDead() || getObject()->isDestroyed()) - { - if (Drawable* drawable = rider->getDrawable()) - drawable->setDrawableHidden(FALSE); - } } #if RETAIL_COMPATIBLE_CRC