+ Mem_PrintList(0);
+ Mem_PrintStats();
+ Mem_PrintList(1<<30);
+ Mem_PrintStats();
+ Sys_Error("Mem_Alloc: out of memory (alloc of size %f (%.3fMB) at %s:%i)", (double)realsize, (double)realsize / (1 << 20), filename, fileline);
+ }
+ // calculate address that aligns the end of the memheader_t to the specified alignment
+ mem = (memheader_t*)((((size_t)base + sizeof(memheader_t) + (alignment-1)) & ~(alignment-1)) - sizeof(memheader_t));
+ mem->baseaddress = (void*)base;
+ mem->filename = filename;
+ mem->fileline = fileline;
+ mem->size = size;
+ mem->pool = pool;
+
+ // calculate sentinels (detects buffer overruns, in a way that is hard to exploit)
+ sentinel1 = MEMHEADER_SENTINEL_FOR_ADDRESS(&mem->sentinel);
+ sentinel2 = MEMHEADER_SENTINEL_FOR_ADDRESS((unsigned char *) mem + sizeof(memheader_t) + mem->size);
+ mem->sentinel = sentinel1;
+ memcpy((unsigned char *) mem + sizeof(memheader_t) + mem->size, &sentinel2, sizeof(sentinel2));
+
+ // append to head of list
+ mem->next = pool->chain;
+ mem->prev = NULL;
+ pool->chain = mem;
+ if (mem->next)
+ mem->next->prev = mem;
+
+ if (mem_mutex)
+ Thread_UnlockMutex(mem_mutex);
+
+ // copy the shared portion in the case of a realloc, then memset the rest
+ sharedsize = 0;
+ remainsize = size;
+ if (olddata)
+ {
+ oldmem = (memheader_t*)olddata - 1;
+ sharedsize = min(oldmem->size, size);
+ memcpy((void *)((unsigned char *) mem + sizeof(memheader_t)), olddata, sharedsize);
+ remainsize -= sharedsize;
+ _Mem_Free(olddata, filename, fileline);
+ }
+ memset((void *)((unsigned char *) mem + sizeof(memheader_t) + sharedsize), 0, remainsize);
+ return (void *)((unsigned char *) mem + sizeof(memheader_t));
+}
+
+// only used by _Mem_Free and _Mem_FreePool
+static void _Mem_FreeBlock(memheader_t *mem, const char *filename, int fileline)
+{
+ mempool_t *pool;
+ size_t size;
+ size_t realsize;
+ unsigned int sentinel1;
+ unsigned int sentinel2;
+
+ // check sentinels (detects buffer overruns, in a way that is hard to exploit)
+ sentinel1 = MEMHEADER_SENTINEL_FOR_ADDRESS(&mem->sentinel);
+ sentinel2 = MEMHEADER_SENTINEL_FOR_ADDRESS((unsigned char *) mem + sizeof(memheader_t) + mem->size);
+ if (mem->sentinel != sentinel1)
+ Sys_Error("Mem_Free: trashed head sentinel (alloc at %s:%i, free at %s:%i)", mem->filename, mem->fileline, filename, fileline);
+ if (memcmp((unsigned char *) mem + sizeof(memheader_t) + mem->size, &sentinel2, sizeof(sentinel2)))
+ Sys_Error("Mem_Free: trashed tail sentinel (alloc at %s:%i, free at %s:%i)", mem->filename, mem->fileline, filename, fileline);
+
+ pool = mem->pool;
+ if (developer_memory.integer)
+ Con_DPrintf("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));
+ // unlink memheader from doubly linked list
+ if ((mem->prev ? mem->prev->next != mem : pool->chain != mem) || (mem->next && mem->next->prev != mem))
+ Sys_Error("Mem_Free: not allocated or double freed (free at %s:%i)", filename, fileline);
+ if (mem_mutex)
+ Thread_LockMutex(mem_mutex);
+ if (mem->prev)
+ mem->prev->next = mem->next;
+ else
+ pool->chain = mem->next;
+ if (mem->next)
+ mem->next->prev = mem->prev;
+ // memheader has been unlinked, do the actual free now
+ size = mem->size;
+ realsize = sizeof(memheader_t) + size + sizeof(sentinel2);
+ pool->totalsize -= size;
+ pool->realsize -= realsize;
+ Clump_FreeBlock(mem->baseaddress, realsize);
+ if (mem_mutex)
+ Thread_UnlockMutex(mem_mutex);
+}
+
+void _Mem_Free(void *data, const char *filename, int fileline)
+{
+ if (data == NULL)
+ {
+ Con_DPrintf("Mem_Free: data == NULL (called at %s:%i)\n", filename, fileline);
+ return;