Skip to content

Commit

Permalink
Fixed|Client: Crash due to stray mobjs being left in the client ID hash
Browse files Browse the repository at this point in the history
ClMobj_Destroy() was not unlinking the object from the ID hash. Instead,
it was trying to unlink to twice from the blockmap/sector.
  • Loading branch information
skyjake committed May 8, 2012
1 parent 684960d commit 7c8efa0
Showing 1 changed file with 52 additions and 5 deletions.
57 changes: 52 additions & 5 deletions doomsday/engine/portable/src/cl_mobj.c
Expand Up @@ -61,6 +61,28 @@ static cmhash_t* ClMobj_Hash(thid_t id)
return GameMap_ClMobjHash(theMap, id);
}

#ifdef _DEBUG
void checkMobjHash(void)
{
int i;
assert(theMap != 0);
for(i = 0; i < CLIENT_MOBJ_HASH_SIZE; ++i)
{
int count1 = 0, count2 = 0;
clmoinfo_t* info;
for(info = theMap->clMobjHash[i].first; info; info = info->next, count1++)
{
assert(ClMobj_MobjForInfo(info) != 0);
}
for(info = theMap->clMobjHash[i].last; info; info = info->prev, count2++)
{
assert(ClMobj_MobjForInfo(info) != 0);
}
assert(count1 == count2);
}
}
#endif

/**
* Links the clmobj into the client mobj hash table.
*/
Expand All @@ -72,6 +94,10 @@ static void ClMobj_LinkInHash(mobj_t* mo, thid_t id)

CL_ASSERT_CLMOBJ(mo);

#ifdef _DEBUG
checkMobjHash();
#endif

// Set the ID.
mo->thinker.id = id;
info->next = NULL;
Expand All @@ -87,6 +113,10 @@ static void ClMobj_LinkInHash(mobj_t* mo, thid_t id)
{
hash->first = info;
}

#ifdef _DEBUG
checkMobjHash();
#endif
}

/**
Expand All @@ -99,6 +129,10 @@ static void ClMobj_UnlinkInHash(mobj_t* mo)

CL_ASSERT_CLMOBJ(mo);

#ifdef _DEBUG
checkMobjHash();
#endif

if(hash->first == info)
hash->first = info->next;
if(hash->last == info)
Expand All @@ -107,16 +141,17 @@ static void ClMobj_UnlinkInHash(mobj_t* mo)
info->next->prev = info->prev;
if(info->prev)
info->prev->next = info->next;

#ifdef _DEBUG
checkMobjHash();
#endif
}

mobj_t* ClMobj_MobjForInfo(clmoinfo_t* info)
{
assert(info->startMagic == CLM_MAGIC1);
assert(info->endMagic == CLM_MAGIC2);

if(info->startMagic != CLM_MAGIC1 || info->endMagic != CLM_MAGIC2)
return 0; // Not a clmobj info.

return (mobj_t*) ((char*)info + sizeof(clmoinfo_t));
}

Expand Down Expand Up @@ -533,6 +568,10 @@ void ClMobj_Destroy(mobj_t* mo)
{
clmoinfo_t* info = 0;

#ifdef _DEBUG
checkMobjHash();
#endif

DEBUG_VERBOSE2_Message(("ClMobj_Destroy: mobj %i being destroyed.\n", mo->thinker.id));

CL_ASSERT_CLMOBJ(mo);
Expand All @@ -543,11 +582,15 @@ void ClMobj_Destroy(mobj_t* mo)

// The ID is free once again.
GameMap_SetMobjID(theMap, mo->thinker.id, false);
ClMobj_Unlink(mo);
ClMobj_Unlink(mo);
ClMobj_UnlinkInHash(mo);
ClMobj_Unlink(mo); // from block/sector

// This will free the entire mobj + info.
Z_Free(info);

#ifdef _DEBUG
checkMobjHash();
#endif
}

/**
Expand Down Expand Up @@ -1018,4 +1061,8 @@ void ClMobj_ReadNullDelta2(boolean skip)
// The mobj will soon time out and be permanently removed.
info->time = Sys_GetRealTime();
info->flags |= CLMF_UNPREDICTABLE | CLMF_NULLED;

#ifdef _DEBUG
checkMobjHash();
#endif
}

0 comments on commit 7c8efa0

Please sign in to comment.