#include "quakedef.h"
+#if MEMPARANOIA
+#ifdef _MSC_VER
+#include <vadefs.h>
+#else
+#include <stdint.h>
+#endif
+#define MEMHEADER_SENTINEL_FOR_ADDRESS(p) ((sentinel_seed ^ (unsigned int) (uintptr_t) (p)) + sentinel_seed)
+unsigned int sentinel_seed;
+#else
+#define MEMHEADER_SENTINEL1 0xDEADF00D
+#define MEMHEADER_SENTINEL2 0xDF
+#endif
+
+#if MEMCLUMPING
+#define MEMCLUMP_SENTINEL 0xABADCAFE
+#endif
+
cvar_t developer_memory = {0, "developer_memory", "0", "prints debugging information about memory allocations"};
cvar_t developer_memorydebug = {0, "developer_memorydebug", "0", "enables memory corruption checks (very slow)"};
#if MEMCLUMPING
int i, j, k, needed, endbit, largest;
memclump_t *clump, **clumpchainpointer;
+#endif
+#if MEMPARANOIA
+ unsigned int sentinel2;
#endif
memheader_t *mem;
if (size <= 0)
if (size < 4096)
{
// clumping
- needed = (sizeof(memheader_t) + size + sizeof(int) + (MEMUNIT - 1)) / MEMUNIT;
+#if MEMPARANOIA
+ needed = (sizeof(memheader_t) + size + sizeof(unsigned int) + (MEMUNIT - 1)) / MEMUNIT;
+#else
+ needed = (sizeof(memheader_t) + size + sizeof(unsigned char) + (MEMUNIT - 1)) / MEMUNIT;
+#endif
endbit = MEMBITS - needed;
for (clumpchainpointer = &pool->clumpchain;*clumpchainpointer;clumpchainpointer = &(*clumpchainpointer)->chain)
{
{
// big allocations are not clumped
#endif
- pool->realsize += sizeof(memheader_t) + size + sizeof(int);
- mem = (memheader_t *)malloc(sizeof(memheader_t) + size + sizeof(int));
+#if MEMPARANOIA
+ pool->realsize += sizeof(memheader_t) + size + sizeof(sentinel2);
+ mem = (memheader_t *)malloc(sizeof(memheader_t) + size + sizeof(sentinel2));
+#else
+ pool->realsize += sizeof(memheader_t) + size + 1;
+ mem = (memheader_t *)malloc(sizeof(memheader_t) + size + 1);
+#endif
if (mem == NULL)
Sys_Error("Mem_Alloc: out of memory (alloc at %s:%i)", filename, fileline);
#if MEMCLUMPING
mem->fileline = fileline;
mem->size = size;
mem->pool = pool;
+#if MEMPARANOIA
+ mem->sentinel1 = MEMHEADER_SENTINEL_FOR_ADDRESS(&mem->sentinel1);
+ sentinel2 = MEMHEADER_SENTINEL_FOR_ADDRESS((unsigned char *) mem + sizeof(memheader_t) + mem->size);
+ memcpy((unsigned char *) mem + sizeof(memheader_t) + mem->size, &sentinel2, sizeof(sentinel2));
+#else
mem->sentinel1 = MEMHEADER_SENTINEL1;
// we have to use only a single byte for this sentinel, because it may not be aligned, and some platforms can't use unaligned accesses
*((unsigned char *) mem + sizeof(memheader_t) + mem->size) = MEMHEADER_SENTINEL2;
+#endif
// append to head of list
mem->next = pool->chain;
mem->prev = NULL;
memclump_t *clump, **clumpchainpointer;
#endif
mempool_t *pool;
+#if MEMPARANOIA
+ unsigned int sentinel2;
+ if (mem->sentinel1 != MEMHEADER_SENTINEL_FOR_ADDRESS(&mem->sentinel1))
+ Sys_Error("Mem_Free: trashed header sentinel 1 (alloc at %s:%i, free at %s:%i)", mem->filename, mem->fileline, filename, fileline);
+ sentinel2 = MEMHEADER_SENTINEL_FOR_ADDRESS((unsigned char *) mem + sizeof(memheader_t) + mem->size);
+ if (memcmp((unsigned char *) mem + sizeof(memheader_t) + mem->size, &sentinel2, sizeof(sentinel2)))
+ Sys_Error("Mem_Free: trashed header sentinel 2 (alloc at %s:%i, free at %s:%i)", mem->filename, mem->fileline, filename, fileline);
+#else
if (mem->sentinel1 != MEMHEADER_SENTINEL1)
Sys_Error("Mem_Free: trashed header sentinel 1 (alloc at %s:%i, free at %s:%i)", mem->filename, mem->fileline, filename, fileline);
if (*((unsigned char *) mem + sizeof(memheader_t) + mem->size) != MEMHEADER_SENTINEL2)
Sys_Error("Mem_Free: trashed header sentinel 2 (alloc at %s:%i, free at %s:%i)", mem->filename, mem->fileline, filename, fileline);
+#endif
pool = mem->pool;
if (developer.integer && developer_memory.integer)
Con_Printf("Mem_Free: pool %s, alloc %s:%i, free %s:%i, size %i bytes\n", pool->name, mem->filename, mem->fileline, filename, fileline, (int)(mem->size));
void _Mem_Free(void *data, const char *filename, int fileline)
{
if (data == NULL)
- Sys_Error("Mem_Free: data == NULL (called at %s:%i)", filename, fileline);
+ {
+ Con_DPrintf("Mem_Free: data == NULL (called at %s:%i)\n", filename, fileline);
+ return;
+ }
if (developer.integer && developer_memorydebug.integer)
{
if (pool == NULL)
Sys_Error("Mem_AllocPool: out of memory (allocpool at %s:%i)", filename, fileline);
memset(pool, 0, sizeof(mempool_t));
+#if MEMPARANOIA
+ pool->sentinel1 = MEMHEADER_SENTINEL_FOR_ADDRESS(&pool->sentinel1);
+ pool->sentinel2 = MEMHEADER_SENTINEL_FOR_ADDRESS(&pool->sentinel2);
+#else
pool->sentinel1 = MEMHEADER_SENTINEL1;
pool->sentinel2 = MEMHEADER_SENTINEL1;
+#endif
pool->filename = filename;
pool->fileline = fileline;
pool->flags = flags;
for (chainaddress = &poolchain;*chainaddress && *chainaddress != pool;chainaddress = &((*chainaddress)->next));
if (*chainaddress != pool)
Sys_Error("Mem_FreePool: pool already free (freepool at %s:%i)", filename, fileline);
+#if MEMPARANOIA
+ if (pool->sentinel1 != MEMHEADER_SENTINEL_FOR_ADDRESS(&pool->sentinel1))
+ Sys_Error("Mem_FreePool: trashed pool sentinel 1 (allocpool at %s:%i, freepool at %s:%i)", pool->filename, pool->fileline, filename, fileline);
+ if (pool->sentinel2 != MEMHEADER_SENTINEL_FOR_ADDRESS(&pool->sentinel2))
+ Sys_Error("Mem_FreePool: trashed pool sentinel 2 (allocpool at %s:%i, freepool at %s:%i)", pool->filename, pool->fileline, filename, fileline);
+#else
if (pool->sentinel1 != MEMHEADER_SENTINEL1)
Sys_Error("Mem_FreePool: trashed pool sentinel 1 (allocpool at %s:%i, freepool at %s:%i)", pool->filename, pool->fileline, filename, fileline);
if (pool->sentinel2 != MEMHEADER_SENTINEL1)
Sys_Error("Mem_FreePool: trashed pool sentinel 2 (allocpool at %s:%i, freepool at %s:%i)", pool->filename, pool->fileline, filename, fileline);
+#endif
*chainaddress = pool->next;
// free memory owned by the pool
}
if (pool == NULL)
Sys_Error("Mem_EmptyPool: pool == NULL (emptypool at %s:%i)", filename, fileline);
+#if MEMPARANOIA
+ if (pool->sentinel1 != MEMHEADER_SENTINEL_FOR_ADDRESS(&pool->sentinel1))
+ Sys_Error("Mem_EmptyPool: trashed pool sentinel 2 (allocpool at %s:%i, emptypool at %s:%i)", pool->filename, pool->fileline, filename, fileline);
+ if (pool->sentinel2 != MEMHEADER_SENTINEL_FOR_ADDRESS(&pool->sentinel2))
+ Sys_Error("Mem_EmptyPool: trashed pool sentinel 1 (allocpool at %s:%i, emptypool at %s:%i)", pool->filename, pool->fileline, filename, fileline);
+#else
if (pool->sentinel1 != MEMHEADER_SENTINEL1)
Sys_Error("Mem_EmptyPool: trashed pool sentinel 1 (allocpool at %s:%i, emptypool at %s:%i)", pool->filename, pool->fileline, filename, fileline);
if (pool->sentinel2 != MEMHEADER_SENTINEL1)
Sys_Error("Mem_EmptyPool: trashed pool sentinel 2 (allocpool at %s:%i, emptypool at %s:%i)", pool->filename, pool->fileline, filename, fileline);
+#endif
// free memory owned by the pool
while (pool->chain)
void _Mem_CheckSentinels(void *data, const char *filename, int fileline)
{
memheader_t *mem;
+#if MEMPARANOIA
+ unsigned int sentinel2;
+#endif
if (data == NULL)
Sys_Error("Mem_CheckSentinels: data == NULL (sentinel check at %s:%i)", filename, fileline);
mem = (memheader_t *)((unsigned char *) data - sizeof(memheader_t));
+#if MEMPARANOIA
+ if (mem->sentinel1 != MEMHEADER_SENTINEL_FOR_ADDRESS(&mem->sentinel1))
+ Sys_Error("Mem_Free: trashed header sentinel 1 (alloc at %s:%i, sentinel check at %s:%i)", mem->filename, mem->fileline, filename, fileline);
+ sentinel2 = MEMHEADER_SENTINEL_FOR_ADDRESS((unsigned char *) mem + sizeof(memheader_t) + mem->size);
+ if (memcmp((unsigned char *) mem + sizeof(memheader_t) + mem->size, &sentinel2, sizeof(sentinel2)))
+ Sys_Error("Mem_Free: trashed header sentinel 2 (alloc at %s:%i, sentinel check at %s:%i)", mem->filename, mem->fileline, filename, fileline);
+#else
if (mem->sentinel1 != MEMHEADER_SENTINEL1)
Sys_Error("Mem_CheckSentinels: trashed header sentinel 1 (block allocated at %s:%i, sentinel check at %s:%i)", mem->filename, mem->fileline, filename, fileline);
if (*((unsigned char *) mem + sizeof(memheader_t) + mem->size) != MEMHEADER_SENTINEL2)
Sys_Error("Mem_CheckSentinels: trashed header sentinel 2 (block allocated at %s:%i, sentinel check at %s:%i)", mem->filename, mem->fileline, filename, fileline);
+#endif
}
#if MEMCLUMPING
mempool_t *pool;
for (pool = poolchain;pool;pool = pool->next)
{
+#if MEMPARANOIA
+ if (pool->sentinel1 != MEMHEADER_SENTINEL_FOR_ADDRESS(&pool->sentinel1))
+ Sys_Error("Mem_CheckSentinelsGlobal: trashed pool sentinel 1 (allocpool at %s:%i, sentinel check at %s:%i)", pool->filename, pool->fileline, filename, fileline);
+ if (pool->sentinel2 != MEMHEADER_SENTINEL_FOR_ADDRESS(&pool->sentinel2))
+ Sys_Error("Mem_CheckSentinelsGlobal: trashed pool sentinel 2 (allocpool at %s:%i, sentinel check at %s:%i)", pool->filename, pool->fileline, filename, fileline);
+#else
if (pool->sentinel1 != MEMHEADER_SENTINEL1)
Sys_Error("Mem_CheckSentinelsGlobal: trashed pool sentinel 1 (allocpool at %s:%i, sentinel check at %s:%i)", pool->filename, pool->fileline, filename, fileline);
if (pool->sentinel2 != MEMHEADER_SENTINEL1)
Sys_Error("Mem_CheckSentinelsGlobal: trashed pool sentinel 2 (allocpool at %s:%i, sentinel check at %s:%i)", pool->filename, pool->fileline, filename, fileline);
+#endif
}
for (pool = poolchain;pool;pool = pool->next)
for (mem = pool->chain;mem;mem = mem->next)
{
memexpandablearray_array_t *oldarrays = l->arrays;
l->maxarrays = max(l->maxarrays * 2, 128);
- l->arrays = Mem_Alloc(l->mempool, l->maxarrays * sizeof(*l->arrays));
+ l->arrays = (memexpandablearray_array_t*) Mem_Alloc(l->mempool, l->maxarrays * sizeof(*l->arrays));
if (oldarrays)
{
memcpy(l->arrays, oldarrays, l->numarrays * sizeof(*l->arrays));
}
}
l->arrays[i].numflaggedrecords = 0;
- l->arrays[i].data = Mem_Alloc(l->mempool, (l->recordsize + 1) * l->numrecordsperarray);
+ l->arrays[i].data = (unsigned char *) Mem_Alloc(l->mempool, (l->recordsize + 1) * l->numrecordsperarray);
l->arrays[i].allocflags = l->arrays[i].data + l->recordsize * l->numrecordsperarray;
l->numarrays++;
}
}
}
-void Mem_ExpandableArray_FreeRecord(memexpandablearray_t *l, void *record)
+/*****************************************************************************
+ * IF YOU EDIT THIS:
+ * If this function was to change the size of the "expandable" array, you have
+ * to update r_shadow.c
+ * Just do a search for "range =", R_ShadowClearWorldLights would be the first
+ * function to look at. (And also seems like the only one?) You might have to
+ * move the call to Mem_ExpandableArray_IndexRange back into for(...) loop's
+ * condition
+ */
+void Mem_ExpandableArray_FreeRecord(memexpandablearray_t *l, void *record) // const!
{
size_t i, j;
unsigned char *p = (unsigned char *)record;
{
if ((pool->flags & POOLFLAG_TEMP) && pool->chain)
{
- Con_Printf("Memory pool %p has sprung a leak totalling %lu bytes (%.3fMB)! Listing contents...\n", pool, (unsigned long)pool->totalsize, pool->totalsize / 1048576.0);
+ Con_Printf("Memory pool %p has sprung a leak totalling %lu bytes (%.3fMB)! Listing contents...\n", (void *)pool, (unsigned long)pool->totalsize, pool->totalsize / 1048576.0);
for (mem = pool->chain;mem;mem = mem->next)
Con_Printf("%10lu bytes allocated at %s:%i\n", (unsigned long)mem->size, mem->filename, mem->fileline);
}
*/
void Memory_Init (void)
{
+#if MEMPARANOIA
+ sentinel_seed = rand();
+#endif
poolchain = NULL;
tempmempool = Mem_AllocPool("Temporary Memory", POOLFLAG_TEMP, NULL);
zonemempool = Mem_AllocPool("Zone", 0, NULL);