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_Access, /* No access permitted to free this handle */
|
||||||
HandleError_Limit, /* The limited number of handles has been reached */
|
HandleError_Limit, /* The limited number of handles has been reached */
|
||||||
HandleError_Identity, /* The identity token was not usable */
|
HandleError_Identity, /* The identity token was not usable */
|
||||||
|
HandleError_Owner, /* Owners do not match for this operation */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum HandleAccessRight
|
enum HandleAccessRight
|
||||||
{
|
{
|
||||||
HandleAccess_Create, /* TYPE: Instances can be created by other objects (this makes it searchable) */
|
HandleAccess_Create, /* TYPE: Instances can be created by other objects (this makes it searchable) */
|
||||||
HandleAccess_Read, /* HANDLES: Can be read by other objects */
|
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_Inherit, /* TYPE: Can be inherited by new types */
|
||||||
HandleAccess_Clone, /* HANDLES: Can be cloned */
|
HandleAccess_Clone, /* HANDLES: Can be cloned */
|
||||||
/* ------------- */
|
/* ------------- */
|
||||||
@ -62,9 +64,10 @@ namespace SourceMod
|
|||||||
owner = NULL;
|
owner = NULL;
|
||||||
access[HandleAccess_Create] = true;
|
access[HandleAccess_Create] = true;
|
||||||
access[HandleAccess_Read] = true;
|
access[HandleAccess_Read] = true;
|
||||||
access[HandleAccess_Delete] = true;
|
access[HandleAccess_IdentDelete] = true;
|
||||||
access[HandleAccess_Inherit] = true;
|
access[HandleAccess_Inherit] = true;
|
||||||
access[HandleAccess_Clone] = true;
|
access[HandleAccess_Clone] = true;
|
||||||
|
access[HandleAccess_OwnerDelete] = false;
|
||||||
}
|
}
|
||||||
IdentityToken_t *owner; /* Owner of the handle */
|
IdentityToken_t *owner; /* Owner of the handle */
|
||||||
bool access[HandleAccess_TOTAL]; /* World access rights */
|
bool access[HandleAccess_TOTAL]; /* World access rights */
|
||||||
@ -166,7 +169,7 @@ namespace SourceMod
|
|||||||
*
|
*
|
||||||
* @param type Type to use on the handle.
|
* @param type Type to use on the handle.
|
||||||
* @param object Object to bind to 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.
|
* @param ident Identity token if any security rights are needed.
|
||||||
* @return A new Handle_t, or 0 on failure.
|
* @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.
|
* only perform any further action if the counter hits 0.
|
||||||
*
|
*
|
||||||
* @param type Handle_t identifier to destroy.
|
* @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).
|
* @param ident Identity token, for destroying secure handles (NULL for none).
|
||||||
* @return A HandleError error code.
|
* @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,
|
* @brief Clones a handle by adding to its internal reference count. Its data,
|
||||||
|
@ -21,7 +21,10 @@ static cell_t sm_CloseHandle(IPluginContext *pContext, const cell_t *params)
|
|||||||
{
|
{
|
||||||
Handle_t hndl = static_cast<Handle_t>(params[1]);
|
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)
|
if (err == HandleError_None)
|
||||||
{
|
{
|
||||||
|
@ -334,7 +334,8 @@ HandleError HandleSystem::GetHandle(Handle_t handle,
|
|||||||
IdentityToken_t *ident,
|
IdentityToken_t *ident,
|
||||||
QHandle **in_pHandle,
|
QHandle **in_pHandle,
|
||||||
unsigned int *in_index,
|
unsigned int *in_index,
|
||||||
HandleAccessRight access)
|
HandleAccessRight access,
|
||||||
|
bool ignoreFree)
|
||||||
{
|
{
|
||||||
unsigned int serial = (handle >> 16);
|
unsigned int serial = (handle >> 16);
|
||||||
unsigned int index = (handle & HANDLESYS_HANDLE_MASK);
|
unsigned int index = (handle & HANDLESYS_HANDLE_MASK);
|
||||||
@ -352,7 +353,8 @@ HandleError HandleSystem::GetHandle(Handle_t handle,
|
|||||||
{
|
{
|
||||||
return HandleError_Access;
|
return HandleError_Access;
|
||||||
}
|
}
|
||||||
if (!pHandle->set)
|
if (!pHandle->set
|
||||||
|
|| (pHandle->set == HandleSet_Freed && !ignoreFree))
|
||||||
{
|
{
|
||||||
return HandleError_Freed;
|
return HandleError_Freed;
|
||||||
} else if (pHandle->set == HandleSet_Identity
|
} else if (pHandle->set == HandleSet_Identity
|
||||||
@ -383,6 +385,12 @@ HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *out_newhandle,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Identities cannot be cloned */
|
||||||
|
if (pHandle->set == HandleSet_Identity)
|
||||||
|
{
|
||||||
|
return HandleError_Identity;
|
||||||
|
}
|
||||||
|
|
||||||
QHandleType *pType = &m_Types[pHandle->type];
|
QHandleType *pType = &m_Types[pHandle->type];
|
||||||
|
|
||||||
/* Get a new Handle ID */
|
/* Get a new Handle ID */
|
||||||
@ -395,7 +403,8 @@ HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *out_newhandle,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
pNewHandle->clone = index;
|
pNewHandle->clone = handle;
|
||||||
|
pHandle->refcount++;
|
||||||
|
|
||||||
if (out_newhandle)
|
if (out_newhandle)
|
||||||
{
|
{
|
||||||
@ -405,39 +414,58 @@ HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *out_newhandle,
|
|||||||
return HandleError_None;
|
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;
|
unsigned int index;
|
||||||
QHandle *pHandle;
|
QHandle *pHandle;
|
||||||
HandleError err;
|
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;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
QHandleType *pType = &m_Types[pHandle->type];
|
QHandleType *pType = &m_Types[pHandle->type];
|
||||||
|
|
||||||
|
if (pType->sec.access[HandleAccess_OwnerDelete] == false
|
||||||
|
&& pHandle->owner
|
||||||
|
&& pHandle->owner != pOwner)
|
||||||
|
{
|
||||||
|
return HandleError_Access;
|
||||||
|
}
|
||||||
|
|
||||||
bool dofree = false;
|
bool dofree = false;
|
||||||
if (pHandle->clone)
|
if (pHandle->clone)
|
||||||
{
|
{
|
||||||
/* If we're a clone, there's not a lot to do. */
|
/* If we're a clone, decrease the parent reference count */
|
||||||
if (FreeHandle(pHandle->clone, ident) != HandleError_None)
|
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 {
|
} else {
|
||||||
|
/* Decrement, free if necessary */
|
||||||
if (--pHandle->refcount == 0)
|
if (--pHandle->refcount == 0)
|
||||||
{
|
{
|
||||||
dofree = true;
|
|
||||||
pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object);
|
pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dofree)
|
|
||||||
{
|
|
||||||
ReleasePrimHandle(index);
|
ReleasePrimHandle(index);
|
||||||
|
} else {
|
||||||
|
/* We must be cloned, so mark ourselves as freed */
|
||||||
|
pHandle->set = HandleSet_Freed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return HandleError_None;
|
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 we're a clone, the rules change - object is ONLY in our reference */
|
||||||
if (pHandle->clone)
|
if (pHandle->clone)
|
||||||
{
|
{
|
||||||
pHandle = &m_Handles[pHandle->clone];
|
/* :TODO: optimize this */
|
||||||
|
return ReadHandle(pHandle->clone, pHandle->type, ident, object);
|
||||||
}
|
}
|
||||||
*object = pHandle->object;
|
*object = pHandle->object;
|
||||||
}
|
}
|
||||||
|
@ -36,8 +36,9 @@
|
|||||||
enum HandleSet
|
enum HandleSet
|
||||||
{
|
{
|
||||||
HandleSet_None = 0,
|
HandleSet_None = 0,
|
||||||
HandleSet_Used,
|
HandleSet_Used, /* The Handle is in use */
|
||||||
HandleSet_Identity
|
HandleSet_Freed, /* The "master" Handle of a clone chain is freed */
|
||||||
|
HandleSet_Identity, /* The Handle is a special identity */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct QHandle
|
struct QHandle
|
||||||
@ -91,7 +92,7 @@ public: //IHandleSystem
|
|||||||
IdentityToken_t *source,
|
IdentityToken_t *source,
|
||||||
IdentityToken_t *ident);
|
IdentityToken_t *ident);
|
||||||
Handle_t CreateScriptHandle(HandleType_t type, void *object, IPluginContext *pContext, 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 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);
|
HandleError ReadHandle(Handle_t handle, HandleType_t type, IdentityToken_t *ident, void **object);
|
||||||
bool TypeCheck(HandleType_t intype, HandleType_t outtype);
|
bool TypeCheck(HandleType_t intype, HandleType_t outtype);
|
||||||
@ -103,7 +104,8 @@ protected:
|
|||||||
IdentityToken_t *ident,
|
IdentityToken_t *ident,
|
||||||
QHandle **pHandle,
|
QHandle **pHandle,
|
||||||
unsigned int *index,
|
unsigned int *index,
|
||||||
HandleAccessRight access);
|
HandleAccessRight access,
|
||||||
|
bool ignoreFree=false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a basic handle and sets its reference count to 1.
|
* Creates a basic handle and sets its reference count to 1.
|
||||||
|
@ -74,7 +74,7 @@ CPlugin::~CPlugin()
|
|||||||
|
|
||||||
if (m_handle)
|
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);
|
g_ShareSys.DestroyIdentity(m_ident);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1117,7 +1117,7 @@ void CPluginManager::OnSourceModAllInitialized()
|
|||||||
|
|
||||||
sec.owner = m_MyIdent; /* :TODO: implement ShareSys */
|
sec.owner = m_MyIdent; /* :TODO: implement ShareSys */
|
||||||
sec.access[HandleAccess_Create] = false;
|
sec.access[HandleAccess_Create] = false;
|
||||||
sec.access[HandleAccess_Delete] = false;
|
sec.access[HandleAccess_IdentDelete] = false;
|
||||||
sec.access[HandleAccess_Inherit] = false;
|
sec.access[HandleAccess_Inherit] = false;
|
||||||
sec.access[HandleAccess_Clone] = false;
|
sec.access[HandleAccess_Clone] = false;
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ void ShareSystem::OnSourceModStartup(bool late)
|
|||||||
|
|
||||||
sec.owner = GetIdentRoot();
|
sec.owner = GetIdentRoot();
|
||||||
sec.access[HandleAccess_Inherit] = false;
|
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_TypeRoot = g_HandleSys.CreateTypeEx("Identity", this, 0, &sec, NULL);
|
||||||
m_IfaceType = g_HandleSys.CreateTypeEx("Interface", 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)
|
void ShareSystem::DestroyIdentity(IdentityToken_t *identity)
|
||||||
{
|
{
|
||||||
g_HandleSys.FreeHandle(identity->ident, GetIdentRoot());
|
g_HandleSys.FreeHandle(identity->ident, NULL, GetIdentRoot());
|
||||||
delete identity;
|
delete identity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user