core/logic/HandleSys.cpp
author David Anderson <dvander@alliedmods.net>
Sun Aug 25 11:59:45 2013 -0700 (2013-08-25)
changeset 4064 d7ca1e28949d
parent 4059 65557adee9a8
child 4115 b5511a1fa380
permissions -rw-r--r--
Switch HandleSys off KTrie (bug 5884 part 2, r=ds).
     1 /**
     2  * vim: set ts=4 sw=4 tw=99 noet :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or modify it under
     9  * the terms of the GNU General Public License, version 3.0, as published by the
    10  * Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful, but WITHOUT
    13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    15  * details.
    16  *
    17  * You should have received a copy of the GNU General Public License along with
    18  * this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to link the
    21  * code of this program (as well as its derivative works) to "Half-Life 2," the
    22  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    23  * by the Valve Corporation.  You must obey the GNU General Public License in
    24  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    25  * this exception to all derivative works.  AlliedModders LLC defines further
    26  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    27  * or <http://www.sourcemod.net/license.php>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #include "HandleSys.h"
    33 #include <assert.h>
    34 #include <string.h>
    35 #include "common_logic.h"
    36 #include "ShareSys.h"
    37 #include "ExtensionSys.h"
    38 #include "PluginSys.h"
    39 
    40 HandleSystem g_HandleSys;
    41 
    42 QHandle *ignore_handle;
    43 
    44 inline HandleType_t TypeParent(HandleType_t type)
    45 {
    46 	return (type & ~HANDLESYS_SUBTYPE_MASK);
    47 }
    48 
    49 inline HandleError IdentityHandle(IdentityToken_t *token, unsigned int *index)
    50 {
    51 	return g_HandleSys.GetHandle(token->ident, g_ShareSys.GetIdentRoot(), &ignore_handle, index);
    52 }
    53 
    54 HandleSystem::HandleSystem()
    55 {
    56 	m_Handles = new QHandle[HANDLESYS_MAX_HANDLES + 1];
    57 	memset(m_Handles, 0, sizeof(QHandle) * (HANDLESYS_MAX_HANDLES + 1));
    58 
    59 	m_Types = new QHandleType[HANDLESYS_TYPEARRAY_SIZE];
    60 	memset(m_Types, 0, sizeof(QHandleType) * HANDLESYS_TYPEARRAY_SIZE);
    61 
    62 	m_strtab = new BaseStringTable(512);
    63 
    64 	m_TypeTail = 0;
    65 }
    66 
    67 HandleSystem::~HandleSystem()
    68 {
    69 	delete [] m_Handles;
    70 	delete [] m_Types;
    71 	delete m_strtab;
    72 }
    73 
    74 
    75 HandleType_t HandleSystem::CreateType(const char *name, 
    76 									  IHandleTypeDispatch *dispatch, 
    77 									  HandleType_t parent, 
    78 									  const TypeAccess *typeAccess, 
    79 									  const HandleAccess *hndlAccess, 
    80 									  IdentityToken_t *ident,
    81 									  HandleError *err)
    82 {
    83 	if (!dispatch)
    84 	{
    85 		if (err)
    86 		{
    87 			*err = HandleError_Parameter;
    88 		}
    89 		return 0;
    90 	}
    91 
    92 	if (typeAccess && typeAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
    93 	{
    94 		if (err)
    95 		{
    96 			*err = HandleError_Version;
    97 		}
    98 		return 0;
    99 	}
   100 
   101 	if (hndlAccess && hndlAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
   102 	{
   103 		if (err)
   104 		{
   105 			*err = HandleError_Version;
   106 		}
   107 		return 0;
   108 	}
   109 
   110 	bool isChild = false;
   111 
   112 	if (parent != 0)
   113 	{
   114 		isChild = true;
   115 		if (parent & HANDLESYS_SUBTYPE_MASK)
   116 		{
   117 			if (err)
   118 			{
   119 				*err = HandleError_NoInherit;
   120 			}
   121 			return 0;
   122 		}
   123 		if (parent >= HANDLESYS_TYPEARRAY_SIZE
   124 			|| m_Types[parent].dispatch == NULL)
   125 		{
   126 			if (err)
   127 			{
   128 				*err = HandleError_Parameter;
   129 			}
   130 			return 0;
   131 		}
   132 		if (m_Types[parent].typeSec.access[HTypeAccess_Inherit] == false
   133 			&& (m_Types[parent].typeSec.ident != ident))
   134 		{
   135 			if (err)
   136 			{
   137 				*err = HandleError_Access;
   138 			}
   139 			return 0;
   140 		}
   141 	}
   142 
   143 	if (name && name[0] != '\0')
   144 	{
   145 		if (m_TypeLookup.retrieve(name))
   146 		{
   147 			if (err)
   148 			{
   149 				*err = HandleError_Parameter;
   150 			}
   151 			return 0;
   152 		}
   153 	}
   154 
   155 	unsigned int index;
   156 
   157 	if (isChild)
   158 	{
   159 		QHandleType *pParent = &m_Types[parent];
   160 		if (pParent->children >= HANDLESYS_MAX_SUBTYPES)
   161 		{
   162 			if (err)
   163 			{
   164 				*err = HandleError_Limit;
   165 			}
   166 			return 0;
   167 		}
   168 		index = 0;
   169 		for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++)
   170 		{
   171 			if (m_Types[parent + i].dispatch == NULL)
   172 			{
   173 				index = parent + i;
   174 				break;
   175 			}
   176 		}
   177 		if (!index)
   178 		{
   179 			if (err)
   180 			{
   181 				*err = HandleError_Limit;
   182 			}
   183 			return 0;
   184 		}
   185 		pParent->children++;
   186 	} else {
   187 		if (m_FreeTypes == 0)
   188 		{
   189 			/* Reserve another index */
   190 			if (m_TypeTail >= HANDLESYS_TYPEARRAY_SIZE)
   191 			{
   192 				if (err)
   193 				{
   194 					*err = HandleError_Limit;
   195 				}
   196 				return 0;
   197 			} else {
   198 				m_TypeTail += (HANDLESYS_MAX_SUBTYPES + 1);
   199 				index = m_TypeTail;
   200 			}
   201 		} else {
   202 			/* The "free array" is compacted into the normal array for easiness */
   203 			index = m_Types[m_FreeTypes--].freeID;
   204 		}
   205 	}
   206 
   207 	QHandleType *pType = &m_Types[index];
   208 	
   209 	pType->dispatch = dispatch;
   210 	if (name && name[0] != '\0')
   211 	{
   212 		pType->nameIdx = m_strtab->AddString(name);
   213 		m_TypeLookup.insert(name, pType);
   214 	} else {
   215 		pType->nameIdx = -1;
   216 	}
   217 
   218 	pType->opened = 0;
   219 
   220 	if (typeAccess)
   221 	{
   222 		pType->typeSec = *typeAccess;
   223 	} else {
   224 		InitAccessDefaults(&pType->typeSec, NULL);
   225 		pType->typeSec.ident = ident;
   226 	}
   227 
   228 	if (hndlAccess)
   229 	{
   230 		pType->hndlSec = *hndlAccess;
   231 	} else {
   232 		InitAccessDefaults(NULL, &pType->hndlSec);
   233 	}
   234 
   235 	if (!isChild)
   236 	{
   237 		pType->children = 0;
   238 	}
   239 
   240 	return index;
   241 }
   242 
   243 bool HandleSystem::FindHandleType(const char *name, HandleType_t *aResult)
   244 {
   245 	QHandleType *type;
   246 	if (!m_TypeLookup.retrieve(name, &type))
   247 		return false;
   248 
   249 	if (aResult)
   250 		*aResult = type - m_Types;
   251 
   252 	return true;
   253 }
   254 
   255 HandleError HandleSystem::TryAllocHandle(unsigned int *handle)
   256 {
   257 	if (m_FreeHandles == 0)
   258 	{
   259 		if (m_HandleTail >= HANDLESYS_MAX_HANDLES)
   260 		{
   261 			return HandleError_Limit;;
   262 		}
   263 		*handle = ++m_HandleTail;
   264 	}
   265 	else
   266 	{
   267 		*handle = m_Handles[m_FreeHandles--].freeID;
   268 	}
   269 
   270 	return HandleError_None;
   271 }
   272 
   273 HandleError HandleSystem::MakePrimHandle(HandleType_t type, 
   274 						   QHandle **in_pHandle, 
   275 						   unsigned int *in_index, 
   276 						   Handle_t *in_handle,
   277 						   IdentityToken_t *owner,
   278 						   bool identity)
   279 {
   280 	HandleError err;
   281 	unsigned int owner_index = 0;
   282 
   283 	if (owner && (IdentityHandle(owner, &owner_index) != HandleError_None))
   284 	{
   285 		return HandleError_Identity;
   286 	}
   287 
   288 	unsigned int handle;
   289 	if ((err = TryAllocHandle(&handle)) != HandleError_None)
   290 	{
   291 		if (!TryAndFreeSomeHandles()
   292 			|| (err = TryAllocHandle(&handle)) != HandleError_None)
   293 		{
   294 			return err;
   295 		}
   296 	}
   297 
   298 	QHandle *pHandle = &m_Handles[handle];
   299 	
   300 	assert(pHandle->set == false);
   301 
   302 	if (++m_HSerial >= HANDLESYS_MAX_SERIALS)
   303 	{
   304 		m_HSerial = 1;
   305 	}
   306 
   307 	/* Set essential information */
   308 	pHandle->set = identity ? HandleSet_Identity : HandleSet_Used;
   309 	pHandle->refcount = 1;
   310 	pHandle->type = type;
   311 	pHandle->serial = m_HSerial;
   312 	pHandle->owner = owner;
   313 	pHandle->ch_next = 0;
   314 	pHandle->access_special = false;
   315 	pHandle->is_destroying = false;
   316 
   317 	/* Create the hash value */
   318 	Handle_t hash = pHandle->serial;
   319 	hash <<= 16;
   320 	hash |= handle;
   321 
   322 	/* Add a reference count to the type */
   323 	m_Types[type].opened++;
   324 
   325 	/* Output */
   326 	*in_pHandle = pHandle;
   327 	*in_index = handle;
   328 	*in_handle = hash;
   329 
   330 	/* Decode the identity token 
   331 	 * For now, we don't allow nested ownership
   332 	 */
   333 	if (owner && !identity)
   334 	{
   335 		QHandle *pIdentity = &m_Handles[owner_index];
   336 		if (pIdentity->ch_prev == 0)
   337 		{
   338 			pIdentity->ch_prev = handle;
   339 			pIdentity->ch_next = handle;
   340 			pHandle->ch_prev = 0;
   341 		}
   342 		else
   343 		{
   344 			/* Link previous node to us (forward) */
   345 			m_Handles[pIdentity->ch_next].ch_next = handle;
   346 			/* Link us to previous node (backwards) */
   347 			pHandle->ch_prev = pIdentity->ch_next;
   348 			/* Set new tail */
   349 			pIdentity->ch_next = handle;
   350 		}
   351 		pIdentity->refcount++;
   352 	}
   353 	else
   354 	{
   355 		pHandle->ch_prev = 0;
   356 	}
   357 
   358 	return HandleError_None;
   359 }
   360 
   361 void HandleSystem::SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pToken)
   362 {
   363 	if (!type
   364 		|| type >= HANDLESYS_TYPEARRAY_SIZE
   365 		|| m_Types[type].dispatch == NULL)
   366 	{
   367 		return;
   368 	}
   369 
   370 	m_Types[type].typeSec.ident = pToken;
   371 }
   372 
   373 Handle_t HandleSystem::CreateHandleInt(HandleType_t type, 
   374 									   void *object, 
   375 									   const HandleSecurity *pSec,
   376 									   HandleError *err, 
   377 									   const HandleAccess *pAccess,
   378 									   bool identity)
   379 {
   380 	IdentityToken_t *ident;
   381 	IdentityToken_t *owner;
   382 
   383 	if (pSec)
   384 	{
   385 		ident = pSec->pIdentity;
   386 		owner = pSec->pOwner;
   387 	} else {
   388 		ident = NULL;
   389 		owner = NULL;
   390 	}
   391 
   392 	if (!type 
   393 		|| type >= HANDLESYS_TYPEARRAY_SIZE
   394 		|| m_Types[type].dispatch == NULL)
   395 	{
   396 		if (err)
   397 		{
   398 			*err = HandleError_Parameter;
   399 		}
   400 		return 0;
   401 	}
   402 
   403 	/* Check to see if we're allowed to create this handle type */
   404 	QHandleType *pType = &m_Types[type];
   405 	if (!pType->typeSec.access[HTypeAccess_Create]
   406 	&& (!pType->typeSec.ident
   407 		|| pType->typeSec.ident != ident))
   408 	{
   409 		if (err)
   410 		{
   411 			*err = HandleError_Access;
   412 		}
   413 		return 0;
   414 	}
   415 
   416 	unsigned int index;
   417 	Handle_t handle;
   418 	QHandle *pHandle;
   419 	HandleError _err;
   420 
   421 	if ((_err=MakePrimHandle(type, &pHandle, &index, &handle, owner, identity)) != HandleError_None)
   422 	{
   423 		if (err)
   424 		{
   425 			*err = _err;
   426 		}
   427 		return 0;
   428 	}
   429 
   430 	if (pAccess)
   431 	{
   432 		pHandle->access_special = true;
   433 		pHandle->sec = *pAccess;
   434 	}
   435 
   436 	pHandle->object = object;
   437 	pHandle->clone = 0;
   438 
   439 	return handle;
   440 }
   441 
   442 Handle_t HandleSystem::CreateHandleEx(HandleType_t type, void *object, const HandleSecurity *pSec, const HandleAccess *pAccess, HandleError *err)
   443 {
   444 	return CreateHandleInt(type, object, pSec, err, pAccess, false);
   445 }
   446 
   447 Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t *owner, IdentityToken_t *ident, HandleError *err)
   448 {
   449 	HandleSecurity sec;
   450 
   451 	sec.pIdentity = ident;
   452 	sec.pOwner = owner;
   453 
   454 	return CreateHandleEx(type, object, &sec, NULL, err);
   455 }
   456 
   457 bool HandleSystem::TypeCheck(HandleType_t intype, HandleType_t outtype)
   458 {
   459 	/* Check the type inheritance */
   460 	if (intype & HANDLESYS_SUBTYPE_MASK)
   461 	{
   462 		if (intype != outtype
   463 			&& (TypeParent(intype) != TypeParent(outtype)))
   464 		{
   465 			return false;
   466 		}
   467 	} else {
   468 		if (intype != outtype)
   469 		{
   470 			return false;
   471 		}
   472 	}
   473 
   474 	return true;
   475 }
   476 
   477 HandleError HandleSystem::GetHandle(Handle_t handle,
   478 									IdentityToken_t *ident, 
   479 									QHandle **in_pHandle, 
   480 									unsigned int *in_index,
   481 									bool ignoreFree)
   482 {
   483 	unsigned int serial = (handle >> 16);
   484 	unsigned int index = (handle & HANDLESYS_HANDLE_MASK);
   485 
   486 	if (index == 0 || index > m_HandleTail || index > HANDLESYS_MAX_HANDLES)
   487 	{
   488 		return HandleError_Index;
   489 	}
   490 
   491 	QHandle *pHandle = &m_Handles[index];
   492 
   493 	if (!pHandle->set
   494 		|| (pHandle->set == HandleSet_Freed && !ignoreFree))
   495 	{
   496 		return HandleError_Freed;
   497 	} else if (pHandle->set == HandleSet_Identity
   498 			   && ident != g_ShareSys.GetIdentRoot())
   499 	{
   500 		/* Only IdentityHandle() can read this! */
   501 		return HandleError_Identity;
   502 	}
   503 	if (pHandle->serial != serial)
   504 	{
   505 		return HandleError_Changed;
   506 	}
   507 
   508 	*in_pHandle = pHandle;
   509 	*in_index = index;
   510 
   511 	return HandleError_None;
   512 }
   513 
   514 bool HandleSystem::CheckAccess(QHandle *pHandle, HandleAccessRight right, const HandleSecurity *pSecurity)
   515 {
   516 	QHandleType *pType = &m_Types[pHandle->type];
   517 	unsigned int access;
   518 
   519 	if (pHandle->access_special)
   520 	{
   521 		access = pHandle->sec.access[right];
   522 	} else {
   523 		access = pType->hndlSec.access[right];
   524 	}
   525 
   526 	/* Check if the type's identity matches */
   527 	if (access & HANDLE_RESTRICT_IDENTITY)
   528 	{
   529 		IdentityToken_t *owner = pType->typeSec.ident;
   530 		if (!owner
   531 			|| (!pSecurity || pSecurity->pIdentity != owner))
   532 		{
   533 			return false;
   534 		}
   535 	}
   536 
   537 	/* Check if the owner is allowed */
   538 	if (access & HANDLE_RESTRICT_OWNER)
   539 	{
   540 		IdentityToken_t *owner = pHandle->owner;
   541 		if (owner
   542 			&& (!pSecurity || pSecurity->pOwner != owner))
   543 		{
   544 			return false;
   545 		}
   546 	}
   547 
   548 	return true;
   549 }
   550 
   551 HandleError HandleSystem::CloneHandle(QHandle *pHandle, unsigned int index, Handle_t *newhandle, IdentityToken_t *newOwner)
   552 {
   553 	/* Get a new Handle ID */
   554 	unsigned int new_index;
   555 	QHandle *pNewHandle;
   556 	Handle_t new_handle;
   557 	HandleError err;
   558 
   559 	if ((err=MakePrimHandle(pHandle->type, &pNewHandle, &new_index, &new_handle, newOwner)) != HandleError_None)
   560 	{
   561 		return err;
   562 	}
   563 
   564 	/* Assign permissions from parent */
   565 	if (pHandle->access_special)
   566 	{
   567 		pNewHandle->access_special = true;
   568 		pNewHandle->sec = pHandle->sec;
   569 	}
   570 
   571 	pNewHandle->clone = index;
   572 	pNewHandle->object = NULL;
   573 	pHandle->refcount++;
   574 
   575 	*newhandle = new_handle;
   576 
   577 	return HandleError_None;
   578 }
   579 
   580 HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t *newOwner, const HandleSecurity *pSecurity)
   581 {
   582 	HandleError err;
   583 	QHandle *pHandle;
   584 	unsigned int index;
   585 	IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL;
   586 
   587 	if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None)
   588 	{
   589 		return err;
   590 	}
   591 
   592 	/* Identities cannot be cloned */
   593 	if (pHandle->set == HandleSet_Identity)
   594 	{
   595 		return HandleError_Identity;
   596 	}
   597 
   598 	/* Check if the handle can be cloned */
   599 	if (!CheckAccess(pHandle, HandleAccess_Clone, pSecurity))
   600 	{
   601 		return HandleError_Access;
   602 	}
   603 
   604 	/* Make sure we're not cloning a clone */
   605 	if (pHandle->clone)
   606 	{
   607 		QHandle *pParent = &m_Handles[pHandle->clone];
   608 		return CloneHandle(pParent, pHandle->clone, newhandle, newOwner);
   609 	}
   610 
   611 	return CloneHandle(pHandle, index, newhandle, newOwner);
   612 }
   613 
   614 Handle_t HandleSystem::FastCloneHandle(QHandle *pHandle, unsigned int index)
   615 {
   616 	if (pHandle->clone)
   617 		return FastCloneHandle(&m_Handles[pHandle->clone], pHandle->clone);
   618 
   619 	Handle_t hndl;
   620 	if (CloneHandle(pHandle, index, &hndl, g_pCoreIdent) != HandleError_None)
   621 		return BAD_HANDLE;
   622 
   623 	return hndl;
   624 }
   625 
   626 Handle_t HandleSystem::FastCloneHandle(Handle_t hndl)
   627 {
   628 	QHandle *pHandle;
   629 	unsigned int index;
   630 
   631 	GetHandleUnchecked(hndl, pHandle, index);
   632 
   633 	return FastCloneHandle(pHandle, index);
   634 }
   635 
   636 void HandleSystem::GetHandleUnchecked(Handle_t hndl, QHandle *& pHandle, unsigned int &index)
   637 {
   638 #ifndef NDEBUG
   639 	unsigned int serial = (hndl >> 16);
   640 #endif
   641 	index = (hndl & HANDLESYS_HANDLE_MASK);
   642 
   643 	assert(index != 0 && index <= m_HandleTail && index < HANDLESYS_MAX_HANDLES);
   644 
   645 	pHandle = &m_Handles[index];
   646 
   647 	assert(pHandle->set && pHandle->set != HandleSet_Freed);
   648 	assert(pHandle->serial == serial);
   649 }
   650 
   651 HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index)
   652 {
   653 	if (pHandle->is_destroying)
   654 	{
   655 		/* Someone tried to free this recursively.  
   656 		 * We'll just ignore this safely.
   657 		 */
   658 		return HandleError_None;
   659 	}
   660 
   661 	QHandleType *pType = &m_Types[pHandle->type];
   662 
   663 	if (pHandle->clone)
   664 	{
   665 		/* If we're a clone, decrease the parent reference count */
   666 		QHandle *pMaster;
   667 		unsigned int master;
   668 
   669 		/* Note that if we ever have per-handle security, we would need to re-check
   670 		* the access on this Handle. */
   671 		master = pHandle->clone;
   672 		pMaster = &m_Handles[master];
   673 
   674 		/* Release the clone now */
   675 		pHandle->is_destroying = true;
   676 		ReleasePrimHandle(index);
   677 
   678 		/* Decrement the master's reference count */
   679 		if (--pMaster->refcount == 0)
   680 		{
   681 			/* Type should be the same but do this anyway... */
   682 			pType = &m_Types[pMaster->type];
   683 			pMaster->is_destroying = true;
   684 			if (pMaster->object)
   685 			{
   686 				pType->dispatch->OnHandleDestroy(pMaster->type, pMaster->object);
   687 			}
   688 			ReleasePrimHandle(master);
   689 		}
   690 	} else if (pHandle->set == HandleSet_Identity) {
   691 		/* If we're an identity, skip all this stuff!
   692 		 * NOTE: SHARESYS DOES NOT CARE ABOUT THE DESTRUCTOR
   693 		 */
   694 		pHandle->is_destroying = true;
   695 		ReleasePrimHandle(index);
   696 	} else {
   697 		/* Decrement, free if necessary */
   698 		if (--pHandle->refcount == 0)
   699 		{
   700 			pHandle->is_destroying = true;
   701 			if (pHandle->object)
   702 			{
   703 				pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object);
   704 			}
   705 			ReleasePrimHandle(index);
   706 		} else {
   707 			/* We must be cloned, so mark ourselves as freed */
   708 			pHandle->set = HandleSet_Freed;
   709 			/* Now, unlink us, so we're not being tracked by the owner */
   710 			if (pHandle->owner)
   711 			{
   712 				UnlinkHandleFromOwner(pHandle, index);
   713 			}
   714 		}
   715 	}
   716 
   717 	return HandleError_None;
   718 }
   719 
   720 HandleError HandleSystem::FreeHandle(Handle_t handle, const HandleSecurity *pSecurity)
   721 {
   722 	unsigned int index;
   723 	QHandle *pHandle;
   724 	HandleError err;
   725 	IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL;
   726 
   727 	if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None)
   728 	{
   729 		return err;
   730 	}
   731 
   732 	if (!CheckAccess(pHandle, HandleAccess_Delete, pSecurity))
   733 	{
   734 		return HandleError_Access;
   735 	}
   736 
   737 	return FreeHandle(pHandle, index);
   738 }
   739 
   740 HandleError HandleSystem::ReadHandle(Handle_t handle, HandleType_t type, const HandleSecurity *pSecurity, void **object)
   741 {
   742 	unsigned int index;
   743 	QHandle *pHandle;
   744 	HandleError err;
   745 	IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL;
   746 
   747 	if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None)
   748 	{
   749 		return err;
   750 	}
   751 
   752 	if (!CheckAccess(pHandle, HandleAccess_Read, pSecurity))
   753 	{
   754 		return HandleError_Access;
   755 	}
   756 
   757 	/* Check the type inheritance */
   758 	if (pHandle->type & HANDLESYS_SUBTYPE_MASK)
   759 	{
   760 		if (pHandle->type != type
   761 			&& (TypeParent(pHandle->type) != TypeParent(type)))
   762 		{
   763 			return HandleError_Type;
   764 		}
   765 	} else if (type) {
   766 		if (pHandle->type != type)
   767 		{
   768 			return HandleError_Type;
   769 		}
   770 	}
   771 
   772 	if (object)
   773 	{
   774 		/* if we're a clone, the rules change - object is ONLY in our reference */
   775 		if (pHandle->clone)
   776 		{
   777 			pHandle = &m_Handles[pHandle->clone];
   778 		}
   779 		*object = pHandle->object;
   780 	}
   781 
   782 	return HandleError_None;
   783 }
   784 
   785 void HandleSystem::UnlinkHandleFromOwner(QHandle *pHandle, unsigned int index)
   786 {
   787 	/* Unlink us if necessary */
   788 	unsigned int ident_index;
   789 	if (IdentityHandle(pHandle->owner, &ident_index) != HandleError_None)
   790 	{
   791 		/* Uh-oh! */
   792 		assert(pHandle->owner == 0);
   793 		return;
   794 	}
   795 
   796 	pHandle->owner = NULL;
   797 
   798 	/* Note that since 0 is an invalid handle, if any of these links are 0,
   799 	* the data can still be set.
   800 	*/
   801 	QHandle *pIdentity = &m_Handles[ident_index];
   802 
   803 	/* Unlink case: We're the head AND tail node */
   804 	if (index == pIdentity->ch_prev && index == pIdentity->ch_next)
   805 	{
   806 		pIdentity->ch_prev = 0;
   807 		pIdentity->ch_next = 0;
   808 	}
   809 	/* Unlink case: We're the head node */
   810 	else if (index == pIdentity->ch_prev) {
   811 		/* Link us to the next in the chain */
   812 		pIdentity->ch_prev = pHandle->ch_next;
   813 		/* Patch up the previous link */
   814 		m_Handles[pHandle->ch_next].ch_prev = 0;
   815 	}
   816 	/* Unlink case: We're the tail node */
   817 	else if (index == pIdentity->ch_next) {
   818 		/* Link us to the previous in the chain */
   819 		pIdentity->ch_next = pHandle->ch_prev;
   820 		/* Patch up the next link */
   821 		m_Handles[pHandle->ch_prev].ch_next = 0;
   822 	}
   823 	/* Unlink case: We're in the middle! */
   824 	else {
   825 		/* Patch the forward reference */
   826 		m_Handles[pHandle->ch_next].ch_prev = pHandle->ch_prev;
   827 		/* Patch the backward reference */
   828 		m_Handles[pHandle->ch_prev].ch_next = pHandle->ch_next;
   829 	}
   830 
   831 	/* Lastly, decrease the reference count */
   832 	pIdentity->refcount--;
   833 }
   834 
   835 void HandleSystem::ReleasePrimHandle(unsigned int index)
   836 {
   837 	QHandle *pHandle = &m_Handles[index];
   838 	HandleSet set = pHandle->set;
   839 
   840 	if (pHandle->owner && (set != HandleSet_Identity))
   841 	{
   842 		UnlinkHandleFromOwner(pHandle, index);
   843 	}
   844 
   845 	/* Were we an identity ourself? */
   846 	QHandle *pLocal;
   847 	if (set == HandleSet_Identity)
   848 	{
   849 		/* Extra work to do.  We need to find everything connected to this identity and release it. */
   850 		unsigned int ch_index;
   851 #if defined _DEBUG
   852 		unsigned int old_index = 0;
   853 #endif
   854 		while ((ch_index = pHandle->ch_next) != 0)
   855 		{
   856 			pLocal = &m_Handles[ch_index];
   857 #if defined _DEBUG
   858 			assert(old_index != ch_index);
   859 			assert(pLocal->set == HandleSet_Used);
   860 			old_index = ch_index;
   861 #endif
   862 			FreeHandle(pLocal, ch_index);
   863 		}
   864 	}
   865 
   866 	pHandle->set = HandleSet_None;
   867 	m_Types[pHandle->type].opened--;
   868 	m_Handles[++m_FreeHandles].freeID = index;
   869 }
   870 
   871 bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident)
   872 {
   873 	if (type == 0 || type >= HANDLESYS_TYPEARRAY_SIZE)
   874 	{
   875 		return false;
   876 	}
   877 
   878 	QHandleType *pType = &m_Types[type];
   879 
   880 	if (pType->typeSec.ident
   881 		&& pType->typeSec.ident != ident)
   882 	{
   883 		return false;
   884 	}
   885 
   886 	if (pType->dispatch == NULL)
   887 	{
   888 		return false;
   889 	}
   890 
   891 	/* Remove children if we have to */
   892 	if (!(type & HANDLESYS_SUBTYPE_MASK))
   893 	{
   894 		QHandleType *childType;
   895 		for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++)
   896 		{
   897 			childType = &m_Types[type + i];
   898 			if (childType->dispatch)
   899 			{
   900 				RemoveType(type + i, childType->typeSec.ident);
   901 			}
   902 		}
   903 		/* Link us into the free chain */
   904 		m_Types[++m_FreeTypes].freeID = type;
   905 	}
   906 
   907 	/* Invalidate the type now */
   908 	IHandleTypeDispatch *dispatch = pType->dispatch;
   909 	pType->dispatch = NULL;
   910 
   911 	/* Make sure nothing is using this type. */
   912 	if (pType->opened)
   913 	{
   914 		QHandle *pHandle;
   915 		for (unsigned int i=1; i<=m_HandleTail; i++)
   916 		{
   917 			pHandle = &m_Handles[i];
   918 			if (!pHandle->set || pHandle->type != type)
   919 			{
   920 				continue;
   921 			}
   922 
   923 			FreeHandle(pHandle, i);
   924 
   925 			if (pType->opened == 0)
   926 			{
   927 				break;
   928 			}
   929 		}
   930 	}
   931 
   932 	/* Remove it from the type cache. */
   933 	if (pType->nameIdx != -1)
   934 	{
   935 		const char *typeName;
   936 
   937 		typeName = m_strtab->GetString(pType->nameIdx);
   938 		m_TypeLookup.remove(typeName);
   939 	}
   940 
   941 	return true;
   942 }
   943 
   944 bool HandleSystem::InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess)
   945 {
   946 	if (pTypeAccess)
   947 	{
   948 		if (pTypeAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
   949 		{
   950 			return false;
   951 		}
   952 		pTypeAccess->access[HTypeAccess_Create] = false;
   953 		pTypeAccess->access[HTypeAccess_Inherit] = false;
   954 		pTypeAccess->ident = NULL;
   955 	}
   956 
   957 	if (pHandleAccess)
   958 	{
   959 		if (pHandleAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
   960 		{
   961 			return false;
   962 		}
   963 
   964 		pHandleAccess->access[HandleAccess_Clone] = 0;
   965 		pHandleAccess->access[HandleAccess_Delete] = HANDLE_RESTRICT_OWNER;
   966 		pHandleAccess->access[HandleAccess_Read] = HANDLE_RESTRICT_IDENTITY;
   967 	}
   968 
   969 	return true;
   970 }
   971 
   972 #define HANDLE_LOG_VERY_BAD(message, ...) \
   973 	smcore.LogFatal(message, ##__VA_ARGS__); \
   974 	smcore.LogError(message, ##__VA_ARGS__);
   975 
   976 bool HandleSystem::TryAndFreeSomeHandles()
   977 {
   978 	IPlugin *highest_owner = NULL;
   979 	unsigned int highest_handle_count = 0;
   980 
   981 	/* Search all plugins */
   982 	for (IPluginIterator *pl_iter = g_PluginSys.GetPluginIterator(); pl_iter->MorePlugins(); pl_iter->NextPlugin())
   983 	{
   984 		IPlugin *plugin = pl_iter->GetPlugin();
   985 		IdentityToken_t *identity = plugin->GetIdentity();
   986 		unsigned int handle_count = 0;
   987 
   988 		if (identity == NULL)
   989 		{
   990 			continue;
   991 		}
   992 
   993 		/* Search all handles */
   994 		for (unsigned int i = 1; i <= m_HandleTail; i++)
   995 		{
   996 			if (m_Handles[i].set != HandleSet_Used)
   997 			{
   998 				continue;
   999 			}
  1000 			if (m_Handles[i].owner == identity)
  1001 			{
  1002 				handle_count++;
  1003 			}
  1004 		}
  1005 
  1006 		if (handle_count > highest_handle_count)
  1007 		{
  1008 			highest_owner = plugin;
  1009 			highest_handle_count = handle_count;
  1010 		}
  1011 	}
  1012 
  1013 	if (highest_owner == NULL || highest_handle_count == 0)
  1014 	{
  1015 		return false;
  1016 	}
  1017 
  1018 	HANDLE_LOG_VERY_BAD("[SM] MEMORY LEAK DETECTED IN PLUGIN (file \"%s\")", highest_owner->GetFilename());
  1019 	HANDLE_LOG_VERY_BAD("[SM] Unloading plugin to free %d handles.", highest_handle_count);
  1020 	HANDLE_LOG_VERY_BAD("[SM] Contact the author(s) of this plugin to correct this error.", highest_handle_count);
  1021 	HANDLE_LOG_VERY_BAD("--------------------------------------------------------------------------");
  1022 
  1023 	const IdentityToken_t *pIdentity = highest_owner->GetIdentity();
  1024 	unsigned int total = 0, highest_index = 0, total_size = 0, size;
  1025 	unsigned int * pCount = new unsigned int[HANDLESYS_TYPEARRAY_SIZE+1];
  1026 	memset(pCount, 0, ((HANDLESYS_TYPEARRAY_SIZE + 1) * sizeof(unsigned int)));
  1027 
  1028 	for (unsigned int i = 1; i <= m_HandleTail; ++i)
  1029 	{
  1030 		const QHandle &Handle = m_Handles[i];
  1031 		if (Handle.set != HandleSet_Used || Handle.owner != pIdentity)
  1032 		{
  1033 			continue;
  1034 		}
  1035 
  1036 		++pCount[Handle.type];
  1037 		++total;
  1038 
  1039 		if (Handle.type >= highest_index)
  1040 		{
  1041 			highest_index = ((Handle.type) + 1);
  1042 		}
  1043 
  1044 		if (Handle.clone != 0)
  1045 		{
  1046 			continue;
  1047 		}
  1048 
  1049 		if (m_Types[Handle.type].dispatch->GetHandleApproxSize(Handle.type, Handle.object, &size))
  1050 		{
  1051 			total_size += size;
  1052 		}
  1053 	}
  1054 
  1055 	const char * pTypeName = NULL;
  1056 
  1057 	for (unsigned int i = 0; i < highest_index; ++i)
  1058 	{
  1059 		if (pCount[i] == 0)
  1060 		{
  1061 			continue; /* We may have gaps, it's fine. */
  1062 		}
  1063 
  1064 		if (m_Types[i].nameIdx != -1)
  1065 		{
  1066 			pTypeName = m_strtab->GetString(m_Types[i].nameIdx);
  1067 		}
  1068 		else
  1069 		{
  1070 			pTypeName = "ANON";
  1071 		}
  1072 
  1073 		HANDLE_LOG_VERY_BAD("Type\t%-20.20s|\tCount\t%u", pTypeName, pCount[i]);
  1074 	}
  1075 
  1076 	HANDLE_LOG_VERY_BAD("-- Approximately %d bytes of memory are in use by (%u) Handles.\n", total_size, total);
  1077 	delete [] pCount;
  1078 
  1079 	highest_owner->GetBaseContext()->ThrowNativeErrorEx(SP_ERROR_MEMACCESS, "Memory leak");
  1080 
  1081 	return scripts->UnloadPlugin(highest_owner);
  1082 }
  1083 
  1084 void HandleSystem::Dump(HANDLE_REPORTER rep)
  1085 {
  1086 	unsigned int total_size = 0;
  1087 	rep("%-10.10s\t%-20.20s\t%-20.20s\t%-10.10s", "Handle", "Owner", "Type", "Memory");
  1088 	rep("--------------------------------------------------------------------------");
  1089 	for (unsigned int i = 1; i <= m_HandleTail; i++)
  1090 	{
  1091 		if (m_Handles[i].set != HandleSet_Used)
  1092 		{
  1093 			continue;
  1094 		}
  1095 		/* Get the index */
  1096 		unsigned int index = (m_Handles[i].serial << 16) | i;
  1097 		/* Determine the owner */
  1098 		const char *owner = "UNKNOWN";
  1099 		if (m_Handles[i].owner)
  1100 		{
  1101 			IdentityToken_t *pOwner = m_Handles[i].owner;
  1102 			if (pOwner == g_pCoreIdent)
  1103 			{
  1104 				owner = "CORE";
  1105 			}
  1106 			else if (pOwner == scripts->GetIdentity())
  1107 			{
  1108 				owner = "PLUGINSYS";
  1109 			}
  1110 			else
  1111 			{
  1112 				IExtension *ext = g_Extensions.GetExtensionFromIdent(pOwner);
  1113 				if (ext)
  1114 				{
  1115 					owner = ext->GetFilename();
  1116 				}
  1117 				else
  1118 				{
  1119 					SMPlugin *pPlugin = scripts->FindPluginByIdentity(pOwner);
  1120 					if (pPlugin)
  1121 					{
  1122 						owner = pPlugin->GetFilename();
  1123 					}
  1124 				}
  1125 			}
  1126 		}
  1127 		else
  1128 		{
  1129 			owner = "NONE";
  1130 		}
  1131 		const char *type = "ANON";
  1132 		QHandleType *pType = &m_Types[m_Handles[i].type];
  1133 		unsigned int size = 0;
  1134 		unsigned int parentIdx;
  1135 		bool bresult;
  1136 		if (pType->nameIdx != -1)
  1137 		{
  1138 			type = m_strtab->GetString(pType->nameIdx);
  1139 		}
  1140 
  1141 		if ((parentIdx = m_Handles[i].clone) != 0)
  1142 		{
  1143 			if (m_Handles[parentIdx].refcount > 0)
  1144 			{
  1145 				size = 0;
  1146 				bresult = true;
  1147 			}
  1148 			else
  1149 			{
  1150 				bresult = pType->dispatch->GetHandleApproxSize(m_Handles[parentIdx].type, m_Handles[parentIdx].object, &size);
  1151 			}
  1152 		}
  1153 		else
  1154 		{
  1155 			bresult = pType->dispatch->GetHandleApproxSize(m_Handles[i].type, m_Handles[i].object, &size);
  1156 		}
  1157 
  1158 		if (pType->dispatch->GetDispatchVersion() < HANDLESYS_MEMUSAGE_MIN_VERSION
  1159 			|| !bresult)
  1160 		{
  1161 			rep("0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, "-1");
  1162 		}
  1163 		else
  1164 		{
  1165 			char buffer[32];
  1166 			smcore.Format(buffer, sizeof(buffer), "%d", size);
  1167 			rep("0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, buffer);
  1168 			total_size += size;
  1169 		}
  1170 	}
  1171 	rep("-- Approximately %d bytes of memory are in use by Handles.\n", total_size);
  1172 }
  1173