Skip to content

Commit 6e96a09

Browse files
authored
bugfix(contain): Restore retail compatibility after crash fix in OpenContain::killAllContained (#2439)
1 parent bab63d4 commit 6e96a09

1 file changed

Lines changed: 20 additions & 14 deletions

File tree

GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Contain/OpenContain.cpp

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -447,32 +447,38 @@ void OpenContain::removeAllContained( Bool exposeStealthUnits )
447447
//-------------------------------------------------------------------------------------------------
448448
void OpenContain::killAllContained()
449449
{
450-
// TheSuperHackers @bugfix xezon 23/05/2025 Empty m_containList straight away
451-
// to prevent a potential child call to catastrophically modify the m_containList as well.
452-
// This scenario can happen if the killed occupant(s) apply deadly damage on death
453-
// to the host container, which then attempts to remove all remaining occupants
454-
// on the death of the host container. This is reproducible by shooting with
455-
// Neutron Shells on a GLA Technical containing GLA Terrorists.
450+
// TheSuperHackers @bugfix Caball009 11/03/2026 The contain list must be updated while iterating over it,
451+
// because e.g. garrisoned infantry relies on that behavior for the team ownership of civilian buildings.
456452

457-
ContainedItemsList list;
458-
list.swap(m_containList);
459-
m_containListSize = 0;
460-
461-
ContainedItemsList::iterator it = list.begin();
462-
463-
while ( it != list.end() )
453+
ContainedItemsList::iterator it = m_containList.begin();
454+
while ( it != m_containList.end() )
464455
{
465-
Object *rider = *it++;
456+
Object *rider = *it;
466457

467458
DEBUG_ASSERTCRASH( rider, ("Contain list must not contain null element"));
468459
if ( rider )
469460
{
461+
m_containList.erase(it);
462+
--m_containListSize;
463+
470464
onRemoving( rider );
471465
rider->onRemovedFrom( getObject() );
472466
rider->kill();
467+
468+
// After kill, the iterator may or may not be invalidated and the list may or may not be empty.
469+
// Set the iterator to the beginning of the list.
470+
it = m_containList.begin();
471+
}
472+
else
473+
{
474+
++it;
473475
}
474476
}
475477

478+
DEBUG_ASSERTCRASH(m_containList.empty(), ("killAllContained should have emptied the contain list"));
479+
480+
m_containList.clear();
481+
m_containListSize = 0;
476482
}
477483

478484
//--------------------------------------------------------------------------------------------------------

0 commit comments

Comments
 (0)