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