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,7 +21,10 @@ 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) | ||||
| 	{ | ||||
|  | ||||
| @ -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,39 +414,58 @@ 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); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (dofree) | ||||
| 	{ | ||||
| 			ReleasePrimHandle(index); | ||||
| 		} else { | ||||
| 			/* We must be cloned, so mark ourselves as freed */ | ||||
| 			pHandle->set = HandleSet_Freed; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	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