From 93d344db439fea878b235eb317b29e2b12997e9c Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Wed, 4 Jun 2025 19:43:23 +0200 Subject: [PATCH 1/2] [ZH] Fix crash in TunnelContain::killAllContained() when killed occupants kill the host container --- .../GameEngine/Include/Common/TunnelTracker.h | 1 + .../Source/Common/RTS/TunnelTracker.cpp | 7 ++++++ .../Object/Contain/TunnelContain.cpp | 25 +++++++++++++------ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Include/Common/TunnelTracker.h b/GeneralsMD/Code/GameEngine/Include/Common/TunnelTracker.h index cde04a1f850..513131c3564 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/TunnelTracker.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/TunnelTracker.h @@ -49,6 +49,7 @@ class TunnelTracker : public MemoryPoolObject, UnsignedInt getContainCount() const { return m_containListSize; } Int getContainMax() const; const ContainedItemsList* getContainedItemsList() const { return &m_containList; } + void swapContainedItemsList(ContainedItemsList& newList); Bool isValidContainerFor(const Object* obj, Bool checkCapacity) const; void addToContainList( Object *obj ); ///< add 'obj' to contain list diff --git a/GeneralsMD/Code/GameEngine/Source/Common/RTS/TunnelTracker.cpp b/GeneralsMD/Code/GameEngine/Source/Common/RTS/TunnelTracker.cpp index 1a4a2141574..748e9aa0039 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/RTS/TunnelTracker.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/RTS/TunnelTracker.cpp @@ -107,6 +107,13 @@ Int TunnelTracker::getContainMax() const return TheGlobalData->m_maxTunnelCapacity; } +// ------------------------------------------------------------------------ +void TunnelTracker::swapContainedItemsList(ContainedItemsList& newList) +{ + m_containList.swap(newList); + m_containListSize = (Int)m_containList.size(); +} + // ------------------------------------------------------------------------ void TunnelTracker::updateNemesis(const Object *target) { diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/TunnelContain.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/TunnelContain.cpp index b5402ba3123..b7f5b31ecbd 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/TunnelContain.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/TunnelContain.cpp @@ -149,18 +149,27 @@ void TunnelContain::harmAndForceExitAllContained( DamageInfo *info ) //------------------------------------------------------------------------------------------------- void TunnelContain::killAllContained( void ) { + // TheSuperHackers @bugfix xezon 04/06/2025 Empty the TunnelSystem's m_containList straight away + // to prevent a potential child call to catastrophically modify the m_containList as well. + // This scenario can happen if the killed occupant(s) apply deadly damage on death + // to the host container, which then attempts to remove all remaining occupants + // on the death of the host container. This is reproducible by shooting with + // Neutron Shells on a GLA Tunnel containing GLA Terrorists. + + ContainedItemsList list; Player *owningPlayer = getObject()->getControllingPlayer(); - const ContainedItemsList *fullList = owningPlayer->getTunnelSystem()->getContainedItemsList(); + owningPlayer->getTunnelSystem()->swapContainedItemsList(list); - Object *obj; - ContainedItemsList::const_iterator it; - it = (*fullList).begin(); - while( it != (*fullList).end() ) + ContainedItemsList::iterator it = list.begin(); + + while ( it != list.end() ) { - obj = *it; - it++; + Object *obj = *it++; + DEBUG_ASSERTCRASH( obj, ("Contain list must not contain NULL element")); + removeFromContain( obj, true ); - obj->kill(); + + obj->kill(); } } //------------------------------------------------------------------------------------------------- From 19511f159cf15932e13bc8533b96e46a4267ccef Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sat, 7 Jun 2025 12:36:05 +0200 Subject: [PATCH 2/2] Improve comment --- .../Source/GameLogic/Object/Contain/TunnelContain.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/TunnelContain.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/TunnelContain.cpp index b7f5b31ecbd..f5f73efbf49 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/TunnelContain.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/TunnelContain.cpp @@ -149,8 +149,8 @@ void TunnelContain::harmAndForceExitAllContained( DamageInfo *info ) //------------------------------------------------------------------------------------------------- void TunnelContain::killAllContained( void ) { - // TheSuperHackers @bugfix xezon 04/06/2025 Empty the TunnelSystem's m_containList straight away - // to prevent a potential child call to catastrophically modify the m_containList as well. + // TheSuperHackers @bugfix xezon 04/06/2025 Empty the TunnelSystem's Contained Items List + // straight away to prevent a potential child call to catastrophically modify it as well. // This scenario can happen if the killed occupant(s) apply deadly damage on death // to the host container, which then attempts to remove all remaining occupants // on the death of the host container. This is reproducible by shooting with