Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,9 @@ void OpenContain::addOrRemoveObjFromWorld(Object* obj, Bool add)
}
else
{
DEBUG_ASSERTCRASH(!getObject()->isEffectivelyDead() && !getObject()->isDestroyed(),
("object shouldn't become an occupant of a dead or destroyed container object"));

// remove object from its group (if any)
obj->leaveGroup();

Expand Down Expand Up @@ -277,11 +280,26 @@ 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())
{
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;
}

#if defined(RTS_DEBUG)
if( !isValidContainerFor( rider, false ) )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -362,8 +362,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 leaving the payload in an invalid state.
if (!getObject()->isDestroyed())
{
createPayload();
}
#endif
}

if( moduleData && moduleData->m_healthRegen )
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,9 @@ void OpenContain::addOrRemoveObjFromWorld(Object* obj, Bool add)
}
else
{
DEBUG_ASSERTCRASH(!getObject()->isEffectivelyDead() && !getObject()->isDestroyed(),
("object shouldn't become an occupant of a dead or destroyed container object"));

// remove object from its group (if any)
obj->leaveGroup();

Expand Down Expand Up @@ -292,11 +295,26 @@ 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.
Comment thread
xezon marked this conversation as resolved.
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 leaving the payload in an invalid state.
if (!getObject()->isDestroyed())
{
createPayload();
}
#endif
}

if( moduleData && moduleData->m_healthRegen )
{
Expand Down
Loading