/* * Portions of this file are copyright Rebirth contributors and licensed as * described in COPYING.txt. * Portions of this file are copyright Parallax Software and licensed * according to the Parallax license below. * See COPYING.txt for license details. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Files for debugging memory allocator * * */ #include #include #include #include "pstypes.h" #include "dxxerror.h" #include "args.h" #include "console.h" #include "u_mem.h" #include namespace dcx { #define MEMSTATS 0 #define FULL_MEM_CHECKING 1 #ifdef DEBUG_MEMORY_ALLOCATIONS #if defined(FULL_MEM_CHECKING) #define CHECKSIZE 16 #define CHECKBYTE 0xFC #define MAX_INDEX 10000 static std::array MallocBase; static std::array MallocSize; static std::array Present; static std::array Filename; static std::array Varname; static std::array LineNum; static int BytesMalloced = 0; static int free_list[MAX_INDEX]; static int num_blocks = 0; static int Initialized = 0; static int LargestIndex = 0; static int out_of_memory = 0; void mem_init() { Initialized = 1; MallocBase = {}; MallocSize = {}; Present = {}; Filename = {}; Varname = {}; LineNum = {}; for (int i=0; i= MAX_INDEX ) { con_printf(CON_CRITICAL,"\nMEM_OUT_OF_SLOTS: Not enough space in mem.c to hold all the mallocs." ); con_printf(CON_CRITICAL, "\tBlock '%s' created in %s, line %d.", var, filename, line ); Error( "MEM_OUT_OF_SLOTS" ); } id = free_list[ num_blocks++ ]; if (id > LargestIndex ) LargestIndex = id; if (id==-1) { con_printf(CON_CRITICAL,"\nMEM_OUT_OF_SLOTS: Not enough space in mem.c to hold all the mallocs." ); //con_printf(CON_CRITICAL, "\tBlock '%s' created in %s, line %d.", Varname[id], Filename[id], LineNum[id] ); Error( "MEM_OUT_OF_SLOTS" ); } ptr = malloc(size + DXX_DEBUG_BIAS_MEMORY_ALLOCATION + CHECKSIZE); if (ptr==NULL) { out_of_memory = 1; con_printf(CON_CRITICAL, "\nMEM_OUT_OF_MEMORY: Malloc returned NULL" ); con_printf(CON_CRITICAL, "\tBlock '%s' created in %s, line %d.", Varname[id], Filename[id], LineNum[id] ); Error( "MEM_OUT_OF_MEMORY" ); } ptr = reinterpret_cast(ptr) + DXX_DEBUG_BIAS_MEMORY_ALLOCATION; MallocBase[id] = ptr; MallocSize[id] = size; Varname[id] = var; Filename[id] = filename; LineNum[id] = line; Present[id] = 1; pc = reinterpret_cast(ptr); BytesMalloced += size; for (int i=0; i= threshold) { /* possible overflow condition */ if (request / size != nmemb) request = ~static_cast(0); } void *ptr = mem_malloc(request, var, filename, line); if (ptr) memset( ptr, 0, request ); return ptr; } static int mem_find_id( void * buffer ) { for (int i=0; i<=LargestIndex; i++ ) if (Present[i]==1) if (MallocBase[i] == buffer ) return i; // Didn't find id. return -1; } static int mem_check_integrity( int block_number ) { int ErrorCount; uint8_t * CheckData; CheckData = reinterpret_cast(reinterpret_cast(MallocBase[block_number]) + MallocSize[block_number]); ErrorCount = 0; for (int i=0; i(buffer) - DXX_DEBUG_BIAS_MEMORY_ALLOCATION; free( buffer ); Present[id] = 0; MallocBase[id] = 0; MallocSize[id] = 0; free_list[ --num_blocks ] = id; } void *mem_realloc(void *buffer, size_t size, const char *var, const char *filename, unsigned line) { void *newbuffer; int id; if (Initialized==0) mem_init(); if (size == 0) { mem_free(buffer); newbuffer = NULL; } else if (buffer == NULL) { newbuffer = mem_malloc(size, var, filename, line); } else { newbuffer = mem_malloc(size, var, filename, line); if (newbuffer != NULL) { id = mem_find_id(buffer); if (MallocSize[id] < size) size = MallocSize[id]; memcpy(newbuffer, buffer, size); mem_free(buffer); } } return newbuffer; } void mem_display_blocks() { int numleft; if (Initialized==0) return; #if MEMSTATS { if (sMemStatsFileInitialized) { unsigned long theFreeMem = 0; theFreeMem = FreeMem(); fprintf(sMemStatsFile, "\n%9u bytes free before closing MEMSTATS file.", theFreeMem); fprintf(sMemStatsFile, "\nMemory Stats File Closed."); fclose(sMemStatsFile); } } #endif // end of ifdef memstats numleft = 0; for (int i=0; i<=LargestIndex; i++ ) { if (Present[i]==1 && (!out_of_memory)) { numleft++; if (CGameArg.DbgShowMemInfo) { con_printf(CON_CRITICAL, "\nMEM_LEAKAGE: Memory block has not been freed." ); PrintInfo( i ); } } } if (numleft && (!out_of_memory)) { Warning( "MEM: %d blocks were left allocated!\n", numleft ); } } void mem_validate_heap() { for (int i=0; i