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:
parent
0f711cd479
commit
32a2aa75e3
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user