Fix a number of issues with cloned handles (bug 5240, r=asherkin).

This commit is contained in:
Kyle Sanderson 2013-03-17 22:05:33 +00:00
parent b3e48b0ad7
commit e3d2ddf278

View File

@ -579,6 +579,7 @@ HandleError HandleSystem::CloneHandle(QHandle *pHandle, unsigned int index, Hand
} }
pNewHandle->clone = index; pNewHandle->clone = index;
pNewHandle->object = NULL;
pHandle->refcount++; pHandle->refcount++;
*newhandle = new_handle; *newhandle = new_handle;
@ -659,6 +660,14 @@ void HandleSystem::GetHandleUnchecked(Handle_t hndl, QHandle *& pHandle, unsigne
HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index) HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index)
{ {
if (pHandle->is_destroying)
{
/* Someone tried to free this recursively.
* We'll just ignore this safely.
*/
return HandleError_None;
}
QHandleType *pType = &m_Types[pHandle->type]; QHandleType *pType = &m_Types[pHandle->type];
if (pHandle->clone) if (pHandle->clone)
@ -673,6 +682,7 @@ HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index)
pMaster = &m_Handles[master]; pMaster = &m_Handles[master];
/* Release the clone now */ /* Release the clone now */
pHandle->is_destroying = true;
ReleasePrimHandle(index); ReleasePrimHandle(index);
/* Decrement the master's reference count */ /* Decrement the master's reference count */
@ -681,20 +691,27 @@ HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index)
/* Type should be the same but do this anyway... */ /* Type should be the same but do this anyway... */
pType = &m_Types[pMaster->type]; pType = &m_Types[pMaster->type];
pMaster->is_destroying = true; pMaster->is_destroying = true;
pType->dispatch->OnHandleDestroy(pMaster->type, pMaster->object); if (pMaster->object)
{
pType->dispatch->OnHandleDestroy(pMaster->type, pMaster->object);
}
ReleasePrimHandle(master); ReleasePrimHandle(master);
} }
} else if (pHandle->set == HandleSet_Identity) { } else if (pHandle->set == HandleSet_Identity) {
/* If we're an identity, skip all this stuff! /* If we're an identity, skip all this stuff!
* NOTE: SHARESYS DOES NOT CARE ABOUT THE DESTRUCTOR * NOTE: SHARESYS DOES NOT CARE ABOUT THE DESTRUCTOR
*/ */
pHandle->is_destroying = true;
ReleasePrimHandle(index); ReleasePrimHandle(index);
} else { } else {
/* Decrement, free if necessary */ /* Decrement, free if necessary */
if (--pHandle->refcount == 0) if (--pHandle->refcount == 0)
{ {
pHandle->is_destroying = true; pHandle->is_destroying = true;
pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object); if (pHandle->object)
{
pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object);
}
ReleasePrimHandle(index); ReleasePrimHandle(index);
} else { } else {
/* We must be cloned, so mark ourselves as freed */ /* We must be cloned, so mark ourselves as freed */
@ -727,14 +744,6 @@ HandleError HandleSystem::FreeHandle(Handle_t handle, const HandleSecurity *pSec
return HandleError_Access; return HandleError_Access;
} }
if (pHandle->is_destroying)
{
/* Someone tried to free this recursively.
* We'll just ignore this safely.
*/
return HandleError_None;
}
return FreeHandle(pHandle, index); return FreeHandle(pHandle, index);
} }
@ -793,6 +802,9 @@ void HandleSystem::UnlinkHandleFromOwner(QHandle *pHandle, unsigned int index)
assert(pHandle->owner == 0); assert(pHandle->owner == 0);
return; return;
} }
pHandle->owner = NULL;
/* Note that since 0 is an invalid handle, if any of these links are 0, /* Note that since 0 is an invalid handle, if any of these links are 0,
* the data can still be set. * the data can still be set.
*/ */
@ -917,29 +929,9 @@ bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident)
{ {
continue; continue;
} }
if (pHandle->clone)
{ FreeHandle(pHandle, i);
/* Get parent */
QHandle *pOther = &m_Handles[pHandle->clone];
if (--pOther->refcount == 0)
{
/* Free! */
dispatch->OnHandleDestroy(type, pOther->object);
ReleasePrimHandle(pHandle->clone);
}
/* Unlink ourselves since we don't have a reference count */
ReleasePrimHandle(i);
} else {
/* If it's not a clone, we still have to check the reference count.
* Either way, we'll be destroyed eventually because the handle types do not change.
*/
if (--pHandle->refcount == 0)
{
/* Free! */
dispatch->OnHandleDestroy(type, pHandle->object);
ReleasePrimHandle(i);
}
}
if (pType->opened == 0) if (pType->opened == 0)
{ {
break; break;