// // Z_ChangeTag // void (Z_ChangeTag)(void *ptr, int tag, __string file, int line) { register memblock_t __near *block = VoidToBlock(ptr); DEBUG_CHECKHEAP(); Z_IDCheck(IDBOOL(block->id != ZONEID), "Z_ChangeTag: Changed a tag without ZONEID", block, file, line); Z_IDCheck(IDBOOL(tag >= PU_PURGELEVEL && !block->user), "Z_ChangeTag: an owner is required for purgable blocks", block, file, line); #ifdef INSTRUMENTED if(block->tag < PU_PURGELEVEL && tag >= PU_PURGELEVEL) { active_memory -= block->size - block->extra; purgable_memory += block->size - block->extra; } else if(block->tag >= PU_PURGELEVEL && tag < PU_PURGELEVEL) { active_memory += block->size - block->extra; purgable_memory -= block->size - block->extra; } #endif block->tag = tag; Z_LogPrintf("* Z_ChangeTag(p=%p, tag=%d, file=%s:%d)\n", ptr, tag, file, line); }
// // Z_Malloc // // You can pass a NULL user if the tag is < PU_PURGELEVEL. // void *(Z_Malloc)(size_t size, int tag, void **user, const char *file, int line) { memblock_t *block; byte *ret; DEBUG_CHECKHEAP(); Z_IDCheckNB(IDBOOL(tag >= PU_PURGELEVEL && !user), "Z_Malloc: an owner is required for purgable blocks", file, line); if(!size) return user ? *user = NULL : NULL; // malloc(0) returns NULL if(!(block = (memblock_t *)(malloc(size + header_size)))) { if(blockbytag[PU_CACHE]) { Z_FreeTags(PU_CACHE, PU_CACHE); block = (memblock_t *)(malloc(size + header_size)); } } if(!block) { I_FatalError(I_ERR_KILL, "Z_Malloc: Failure trying to allocate %u bytes\n" "Source: %s:%d\n", (unsigned int)size, file, line); } block->size = size; if((block->next = blockbytag[tag])) block->next->prev = &block->next; blockbytag[tag] = block; block->prev = &blockbytag[tag]; INSTRUMENT(memorybytag[tag] += block->size); INSTRUMENT(block->file = file); INSTRUMENT(block->line = line); IDCHECK(block->id = ZONEID); // signature required in block header block->tag = tag; // tag block->user = user; // user ret = ((byte *) block + header_size); if(user) // if there is a user *user = ret; // set user to point to new block // scramble memory -- weed out any bugs SCRAMBLER(ret, size); Z_LogPrintf("* %p = Z_Malloc(size=%lu, tag=%d, user=%p, source=%s:%d)\n", ret, size, tag, user, file, line); return ret; }
// // Z_CheckTag // // haleyjd: a function to return the allocation tag of a block. // This is needed by W_CacheLumpNum so that it does not // inadvertently lower the cache level of lump allocations and // cause code which expects them to be static to lose them // int (Z_CheckTag)(void *ptr, const char *file, int line) { memblock_t *block = (memblock_t *)((byte *) ptr - header_size); DEBUG_CHECKHEAP(); Z_IDCheck(IDBOOL(block->id != ZONEID), "Z_CheckTag: block doesn't have ZONEID", block, file, line); return block->tag; }
// // Z_CheckTag // // haleyjd: a function to return the allocation tag of a block. // This is needed by W_CacheLumpNum so that it does not // inadvertently lower the cache level of lump allocations and // cause code which expects them to be static to lose them // int (Z_CheckTag)(void *ptr, __string file, int line) { register memblock_t __near *block = VoidToBlock(ptr); DEBUG_CHECKHEAP(); Z_IDCheck(IDBOOL(block->id != ZONEID), "Z_CheckTag: block doesn't have ZONEID", block, file, line); return block->tag; }
// // Z_Free // void (Z_Free)(void *p, const char *file, int line) { DEBUG_CHECKHEAP(); if(p) { memblock_t *block = (memblock_t *)((byte *) p - header_size); Z_IDCheck(IDBOOL(block->id != ZONEID), "Z_Free: freed a pointer without ZONEID", block, file, line); // haleyjd: permanent blocks are never freed even if the code tries. if(block->tag == PU_PERMANENT) return; IDCHECK(block->id = 0); // Nullify id so another free fails // haleyjd 01/20/09: check invalid tags // catches double frees and possible selective heap corruption if(block->tag == PU_FREE || block->tag >= PU_MAX) { I_FatalError(I_ERR_KILL, "Z_Free: freed a pointer with invalid tag %d\n" "Source: %s:%d\n" #if defined(ZONEVERBOSE) && defined(INSTRUMENTED) "Source of malloc: %s:%d\n" , block->tag, file, line, block->file, block->line #else , block->tag, file, line #endif ); } INSTRUMENT(memorybytag[block->tag] -= block->size); block->tag = PU_FREE; // Mark block freed // scramble memory -- weed out any bugs SCRAMBLER(p, block->size); if(block->user) // Nullify user if one exists *block->user = NULL; if((*block->prev = block->next)) block->next->prev = block->prev; free(block); Z_LogPrintf("* Z_Free(p=%p, file=%s:%d)\n", p, file, line); } }
// // Z_ChangeTag // void (Z_ChangeTag)(void *ptr, int tag, const char *file, int line) { memblock_t *block; DEBUG_CHECKHEAP(); if(!ptr) { I_FatalError(I_ERR_KILL, "Z_ChangeTag: can't change a NULL pointer at %s:%d\n", file, line); } block = (memblock_t *)((byte *) ptr - header_size); Z_IDCheck(IDBOOL(block->id != ZONEID), "Z_ChangeTag: Changed a tag without ZONEID", block, file, line); // haleyjd: permanent blocks are not re-tagged even if the code tries. if(block->tag == PU_PERMANENT) return; Z_IDCheck(IDBOOL(tag >= PU_PURGELEVEL && !block->user), "Z_ChangeTag: an owner is required for purgable blocks", block, file, line); if((*block->prev = block->next)) block->next->prev = block->prev; if((block->next = blockbytag[tag])) block->next->prev = &block->next; block->prev = &blockbytag[tag]; blockbytag[tag] = block; INSTRUMENT(memorybytag[block->tag] -= block->size); INSTRUMENT(memorybytag[tag] += block->size); block->tag = tag; Z_LogPrintf("* Z_ChangeTag(p=%p, tag=%d, file=%s:%d)\n", ptr, tag, file, line); }
// // Z_Realloc // // For the native heap, this can easily behave as a real realloc, and not // just an ignorant copy-and-free. // void *(Z_Realloc)(void *ptr, size_t n, int tag, void **user, const char *file, int line) { void *p; memblock_t *block, *newblock, *origblock; // if not allocated at all, defer to Z_Malloc if(!ptr) return (Z_Malloc)(n, tag, user, file, line); // size == 0 is a special case that cannot be handled below if(n == 0) { (Z_Free)(ptr, file, line); return NULL; } DEBUG_CHECKHEAP(); block = origblock = (memblock_t *)((byte *)ptr - header_size); Z_IDCheck(IDBOOL(block->id != ZONEID), "Z_Realloc: Reallocated a block without ZONEID\n", block, file, line); // haleyjd: realloc cannot change the tag of a permanent block if(block->tag == PU_PERMANENT) tag = PU_PERMANENT; // nullify current user, if any if(block->user) *(block->user) = NULL; // detach from list before reallocation if((*block->prev = block->next)) block->next->prev = block->prev; block->next = NULL; block->prev = NULL; INSTRUMENT(memorybytag[block->tag] -= block->size); if(!(newblock = (memblock_t *)(realloc(block, n + header_size)))) { // haleyjd 07/09/10: Note that unlinking the block above makes this safe // even if the current block is PU_CACHE; Z_FreeTags won't find it. if(blockbytag[PU_CACHE]) { Z_FreeTags(PU_CACHE, PU_CACHE); newblock = (memblock_t *)(realloc(block, n + header_size)); } } if(!(block = newblock)) { if(origblock->size >= n) { block = origblock; // restore original block if size was equal or smaller n = block->size; // keep same size in this event } else { I_FatalError(I_ERR_KILL, "Z_Realloc: Failure trying to allocate %u bytes\n" "Source: %s:%d\n", (unsigned int)n, file, line); } } block->size = n; block->tag = tag; p = (byte *)block + header_size; // set new user, if any block->user = user; if(user) *user = p; // reattach to list at possibly new address, new tag if((block->next = blockbytag[tag])) block->next->prev = &block->next; blockbytag[tag] = block; block->prev = &blockbytag[tag]; INSTRUMENT(memorybytag[tag] += block->size); INSTRUMENT(block->file = file); INSTRUMENT(block->line = line); Z_LogPrintf("* %p = Z_Realloc(ptr=%p, n=%lu, tag=%d, user=%p, source=%s:%d)\n", p, ptr, n, tag, user, file, line); return p; }
// // Z_Free // void (Z_Free)(void *p, __string file, int line) { register memblock_t __near *other, *block; if(!p) return; DEBUG_CHECKHEAP(); block = VoidToBlock(p); Z_IDCheck(IDBOOL(block->id != ZONEID), "Z_Free: freed a pointer without ZONEID", block, file, line); IDCHECK(block->id = 0); // Nullify id so another free fails // haleyjd 01/20/09: check invalid tags // catches double frees and possible selective heap corruption if(block->tag == PU_FREE || block->tag >= PU_MAX) { zonef("Z_Free: freed a pointer with invalid tag %d\nSource: %s:%d\n" #ifdef INSTRUMENTED "Source of malloc: %s:%d\n" , block->tag, file, line, block->file, block->line #else , block->tag, file, line #endif ); abort(); } SCRAMBLER(p, block->size); if(block->user) // Nullify user if one exists *block->user = NULL; #ifdef INSTRUMENTED free_memory += block->size; inactive_memory -= block->extra; if(block->tag >= PU_PURGELEVEL) purgable_memory -= block->size - block->extra; else active_memory -= block->size - block->extra; #endif block->tag = PU_FREE; // Mark block freed if(block != zone) { other = block->prev; // Possibly merge with previous block if(other->tag == PU_FREE) { if(rover == block) // Move back rover if it points at block rover = other; (other->next = block->next)->prev = other; other->size += block->size + HEADER_SIZE; block = other; INSTRUMENT(inactive_memory -= HEADER_SIZE); INSTRUMENT(free_memory += HEADER_SIZE); } } other = block->next; // Possibly merge with next block if(other->tag == PU_FREE && other != zone) { if(rover == other) // Move back rover if it points at next block rover = block; (block->next = other->next)->prev = block; block->size += other->size + HEADER_SIZE; INSTRUMENT(inactive_memory -= HEADER_SIZE); INSTRUMENT(free_memory += HEADER_SIZE); } Z_PrintStats(); // print memory allocation stats Z_LogPrintf("* Z_Free(p=%p, file=%s:%d)\n", p, file, line); }
// // Z_Malloc // // You can pass a NULL user if the tag is < PU_PURGELEVEL. // void *(Z_Malloc)(size_t size, int tag, void **user, __string file, int line) { register memblock_t __near *block, *start; INSTRUMENT(register size_t size_orig = size); // davidph 12/10/12: If zone not initialized, do so now. if(!zone) (Z_Init)(file, line); DEBUG_CHECKHEAP(); Z_IDCheckNB(IDBOOL(tag >= PU_PURGELEVEL && !user), "Z_Malloc: an owner is required for purgable blocks", file, line); if(!size) return user ? *user = NULL : NULL; // malloc(0) returns NULL size = (size+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1); // round to chunk size block = rover; if(block->prev->tag == PU_FREE) block = block->prev; start = block; // haleyjd 01/01/01 (happy new year!): // the first if() inside the loop below contains cph's memory // purging efficiency fix do { // Free purgable blocks; replacement is roughly FIFO if(block->tag >= PU_PURGELEVEL) { start = block->prev; Z_Free((char __near *)block + HEADER_SIZE); // cph - If start->next == block, we did not merge with the previous // If !=, we did, so we continue from start. // Important: we've reset start! if(start->next == block) start = start->next; else block = start; } if(block->tag == PU_FREE && block->size >= size) // First-fit { size_t extra = block->size - size; if(extra >= MIN_BLOCK_SPLIT + HEADER_SIZE) { memblock_t __near *newb = (memblock_t __near *)((char __near *)block + HEADER_SIZE + size); (newb->next = block->next)->prev = newb; (newb->prev = block)->next = newb; // Split up block block->size = size; newb->size = extra - HEADER_SIZE; newb->tag = PU_FREE; INSTRUMENT(inactive_memory += HEADER_SIZE); INSTRUMENT(free_memory -= HEADER_SIZE); } rover = block->next; // set roving pointer for next search #ifdef INSTRUMENTED inactive_memory += block->extra = block->size - size_orig; if(tag >= PU_PURGELEVEL) purgable_memory += size_orig; else active_memory += size_orig; free_memory -= block->size; #endif INSTRUMENT(block->file = file); INSTRUMENT(block->line = line); IDCHECK(block->id = ZONEID);// signature required in block header block->tag = tag; // tag block->user = user; // user block = BlockToVoid(block); if(user) // if there is a user *user = block; // set user to point to new block Z_PrintStats(); // print memory allocation stats // scramble memory -- weed out any bugs SCRAMBLER(block, size); Z_LogPrintf("* %p = Z_Malloc(size=%u, tag=%d, user=%p, source=%s:%d)\n", block, size, tag, user, file, line); return block; } } while((block = block->next) != start); // detect cycles as failure zonef("Z_Malloc: Failure trying to allocate %u bytes\nSource: %s:%d\n", size, file, line); abort(); }