fixed various issues in the handle system with cloning

fixed plugins being able to free each other's handles

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40264
This commit is contained in:
David Anderson 2007-01-02 01:44:46 +00:00
parent 0f711cd479
commit 32a2aa75e3
6 changed files with 67 additions and 29 deletions

View File

@ -42,13 +42,15 @@ namespace SourceMod
HandleError_Access, /* No access permitted to free this handle */
HandleError_Limit, /* The limited number of handles has been reached */
HandleError_Identity, /* The identity token was not usable */
HandleError_Owner, /* Owners do not match for this operation */
};
enum HandleAccessRight
{
HandleAccess_Create, /* TYPE: Instances can be created by other objects (this makes it searchable) */
HandleAccess_Read, /* HANDLES: Can be read by other objects */
HandleAccess_Delete, /* HANDLES: Can be deleted by other objects */
HandleAccess_IdentDelete, /* HANDLES: Can be deleted by other identities */
HandleAccess_OwnerDelete, /* HANDLES: Can be deleted by other owners */
HandleAccess_Inherit, /* TYPE: Can be inherited by new types */
HandleAccess_Clone, /* HANDLES: Can be cloned */
/* ------------- */
@ -62,9 +64,10 @@ namespace SourceMod
owner = NULL;
access[HandleAccess_Create] = true;
access[HandleAccess_Read] = true;
access[HandleAccess_Delete] = true;
access[HandleAccess_IdentDelete] = true;
access[HandleAccess_Inherit] = true;
access[HandleAccess_Clone] = true;
access[HandleAccess_OwnerDelete] = false;
}
IdentityToken_t *owner; /* Owner of the handle */
bool access[HandleAccess_TOTAL]; /* World access rights */
@ -166,7 +169,7 @@ namespace SourceMod
*
* @param type Type to use on the handle.
* @param object Object to bind to the handle.
* @param owner Owner for the handle.
* @param owner Owner for the handle. NULL means anonymous (no owner).
* @param ident Identity token if any security rights are needed.
* @return A new Handle_t, or 0 on failure.
*/
@ -196,10 +199,11 @@ namespace SourceMod
* only perform any further action if the counter hits 0.
*
* @param type Handle_t identifier to destroy.
* @param owner Owner of handle (NULL for none).
* @param ident Identity token, for destroying secure handles (NULL for none).
* @return A HandleError error code.
*/
virtual HandleError FreeHandle(Handle_t handle, IdentityToken_t *ident) =0;
virtual HandleError FreeHandle(Handle_t handle, IdentityToken_t *owner, IdentityToken_t *ident) =0;
/**
* @brief Clones a handle by adding to its internal reference count. Its data,

View File

@ -21,8 +21,11 @@ static cell_t sm_CloseHandle(IPluginContext *pContext, const cell_t *params)
{
Handle_t hndl = static_cast<Handle_t>(params[1]);
HandleError err = g_HandleSys.FreeHandle(hndl, NULL);
/* :TODO: make this a little bit cleaner, eh? */
IPlugin *pPlugin = g_PluginSys.FindPluginByContext(pContext->GetContext());
HandleError err = g_HandleSys.FreeHandle(hndl, pPlugin->GetIdentity(), NULL);
if (err == HandleError_None)
{
return 1;

View File

@ -334,7 +334,8 @@ HandleError HandleSystem::GetHandle(Handle_t handle,
IdentityToken_t *ident,
QHandle **in_pHandle,
unsigned int *in_index,
HandleAccessRight access)
HandleAccessRight access,
bool ignoreFree)
{
unsigned int serial = (handle >> 16);
unsigned int index = (handle & HANDLESYS_HANDLE_MASK);
@ -352,7 +353,8 @@ HandleError HandleSystem::GetHandle(Handle_t handle,
{
return HandleError_Access;
}
if (!pHandle->set)
if (!pHandle->set
|| (pHandle->set == HandleSet_Freed && !ignoreFree))
{
return HandleError_Freed;
} else if (pHandle->set == HandleSet_Identity
@ -383,6 +385,12 @@ HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *out_newhandle,
return err;
}
/* Identities cannot be cloned */
if (pHandle->set == HandleSet_Identity)
{
return HandleError_Identity;
}
QHandleType *pType = &m_Types[pHandle->type];
/* Get a new Handle ID */
@ -395,7 +403,8 @@ HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *out_newhandle,
return err;
}
pNewHandle->clone = index;
pNewHandle->clone = handle;
pHandle->refcount++;
if (out_newhandle)
{
@ -405,41 +414,60 @@ HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *out_newhandle,
return HandleError_None;
}
HandleError HandleSystem::FreeHandle(Handle_t handle, IdentityToken_t *ident)
HandleError HandleSystem::FreeHandle(Handle_t handle, IdentityToken_t *pOwner, IdentityToken_t *ident)
{
unsigned int index;
QHandle *pHandle;
HandleError err;
if ((err=GetHandle(handle, ident, &pHandle, &index, HandleAccess_Delete)) != HandleError_None)
if ((err=GetHandle(handle, ident, &pHandle, &index, HandleAccess_IdentDelete)) != HandleError_None)
{
return err;
}
QHandleType *pType = &m_Types[pHandle->type];
if (pType->sec.access[HandleAccess_OwnerDelete] == false
&& pHandle->owner
&& pHandle->owner != pOwner)
{
return HandleError_Access;
}
bool dofree = false;
if (pHandle->clone)
{
/* If we're a clone, there's not a lot to do. */
if (FreeHandle(pHandle->clone, ident) != HandleError_None)
/* If we're a clone, decrease the parent reference count */
QHandle *pMaster;
unsigned int master;
/* This call should not return an error, it'd be a corruption sign */
err = GetHandle(pHandle->clone, ident, &pMaster, &master, HandleAccess_IdentDelete, true);
assert(err == HandleError_None);
/* Release the clone now */
ReleasePrimHandle(index);
/* Decrement the master's reference count */
if (--pMaster->refcount == 0)
{
assert(false);
/* Type should be the same but do this anyway... */
pType = &m_Types[pMaster->type];
pType->dispatch->OnHandleDestroy(pMaster->type, pMaster->object);
ReleasePrimHandle(master);
}
dofree = true;
} else {
/* Decrement, free if necessary */
if (--pHandle->refcount == 0)
{
dofree = true;
pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object);
ReleasePrimHandle(index);
} else {
/* We must be cloned, so mark ourselves as freed */
pHandle->set = HandleSet_Freed;
}
}
if (dofree)
{
ReleasePrimHandle(index);
}
return HandleError_None;
}
@ -477,7 +505,8 @@ HandleError HandleSystem::ReadHandle(Handle_t handle,
/* if we're a clone, the rules change - object is ONLY in our reference */
if (pHandle->clone)
{
pHandle = &m_Handles[pHandle->clone];
/* :TODO: optimize this */
return ReadHandle(pHandle->clone, pHandle->type, ident, object);
}
*object = pHandle->object;
}

View File

@ -36,8 +36,9 @@
enum HandleSet
{
HandleSet_None = 0,
HandleSet_Used,
HandleSet_Identity
HandleSet_Used, /* The Handle is in use */
HandleSet_Freed, /* The "master" Handle of a clone chain is freed */
HandleSet_Identity, /* The Handle is a special identity */
};
struct QHandle
@ -91,7 +92,7 @@ public: //IHandleSystem
IdentityToken_t *source,
IdentityToken_t *ident);
Handle_t CreateScriptHandle(HandleType_t type, void *object, IPluginContext *pContext, IdentityToken_t *ident);
HandleError FreeHandle(Handle_t handle, IdentityToken_t *ident);
HandleError FreeHandle(Handle_t handle, IdentityToken_t *owner, IdentityToken_t *ident);
HandleError CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t *source, IdentityToken_t *ident);
HandleError ReadHandle(Handle_t handle, HandleType_t type, IdentityToken_t *ident, void **object);
bool TypeCheck(HandleType_t intype, HandleType_t outtype);
@ -103,7 +104,8 @@ protected:
IdentityToken_t *ident,
QHandle **pHandle,
unsigned int *index,
HandleAccessRight access);
HandleAccessRight access,
bool ignoreFree=false);
/**
* Creates a basic handle and sets its reference count to 1.

View File

@ -74,7 +74,7 @@ CPlugin::~CPlugin()
if (m_handle)
{
g_HandleSys.FreeHandle(m_handle, g_PluginSys.GetIdentity());
g_HandleSys.FreeHandle(m_handle, g_PluginSys.GetIdentity(), g_PluginSys.GetIdentity());
g_ShareSys.DestroyIdentity(m_ident);
}
}
@ -1117,7 +1117,7 @@ void CPluginManager::OnSourceModAllInitialized()
sec.owner = m_MyIdent; /* :TODO: implement ShareSys */
sec.access[HandleAccess_Create] = false;
sec.access[HandleAccess_Delete] = false;
sec.access[HandleAccess_IdentDelete] = false;
sec.access[HandleAccess_Inherit] = false;
sec.access[HandleAccess_Clone] = false;

View File

@ -27,7 +27,7 @@ void ShareSystem::OnSourceModStartup(bool late)
sec.owner = GetIdentRoot();
sec.access[HandleAccess_Inherit] = false;
sec.access[HandleAccess_Delete] = false;
sec.access[HandleAccess_IdentDelete] = false;
m_TypeRoot = g_HandleSys.CreateTypeEx("Identity", this, 0, &sec, NULL);
m_IfaceType = g_HandleSys.CreateTypeEx("Interface", this, 0, &sec, NULL);
@ -184,7 +184,7 @@ void ShareSystem::AddNatives(IdentityToken_t *token, const sp_nativeinfo_t *nati
void ShareSystem::DestroyIdentity(IdentityToken_t *identity)
{
g_HandleSys.FreeHandle(identity->ident, GetIdentRoot());
g_HandleSys.FreeHandle(identity->ident, NULL, GetIdentRoot());
delete identity;
}