Fix heap-use-after-free in CGameWorld::RemoveEntity

Entities have a pointer to their parent entity. If the parent entity is freed first, then freeing the child will cause access to the already freed parent.

This is fixed by adding a child pointer and clearing the child and parent pointers when either child or parent is freed.
This commit is contained in:
Robert Müller 2022-06-26 10:32:03 +02:00
parent 1e31db257f
commit 2df4c4c668
3 changed files with 17 additions and 8 deletions

View file

@ -24,7 +24,8 @@ CEntity::CEntity(CGameWorld *pGameWorld, int ObjType, vec2 Pos, int ProximityRad
m_SnapTicks = -1;
// DDRace
m_pParent = 0;
m_pParent = nullptr;
m_pChild = nullptr;
m_DestroyTick = -1;
m_LastRenderTick = -1;
}

View file

@ -62,6 +62,7 @@ public:
int m_DestroyTick;
int m_LastRenderTick;
CEntity *m_pParent;
CEntity *m_pChild;
CEntity *NextEntity() { return m_pNextTypeEntity; }
int ID() { return m_ID; }
void Keep()

View file

@ -30,10 +30,7 @@ CGameWorld::CGameWorld()
CGameWorld::~CGameWorld()
{
// delete all entities
for(auto &pFirstEntityType : m_apFirstEntityTypes)
while(pFirstEntityType)
delete pFirstEntityType;
Clear();
if(m_pChild && m_pChild->m_pParent == this)
{
OnModified();
@ -143,9 +140,18 @@ void CGameWorld::RemoveEntity(CEntity *pEnt)
pEnt->m_pNextTypeEntity = 0;
pEnt->m_pPrevTypeEntity = 0;
if(m_IsValidCopy && m_pParent && m_pParent->m_pChild == this && pEnt->m_pParent)
pEnt->m_pParent->m_DestroyTick = GameTick();
pEnt->m_pParent = 0;
if(pEnt->m_pParent)
{
if(m_IsValidCopy && m_pParent && m_pParent->m_pChild == this)
pEnt->m_pParent->m_DestroyTick = GameTick();
pEnt->m_pParent->m_pChild = nullptr;
pEnt->m_pParent = nullptr;
}
if(pEnt->m_pChild)
{
pEnt->m_pChild->m_pParent = nullptr;
pEnt->m_pChild = nullptr;
}
}
void CGameWorld::RemoveCharacter(CCharacter *pChar)
@ -578,6 +584,7 @@ void CGameWorld::CopyWorld(CGameWorld *pFrom)
if(pCopy)
{
pCopy->m_pParent = pEnt;
pEnt->m_pChild = pCopy;
this->InsertEntity(pCopy);
}
}