/* 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-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * $Source: /cvsroot/dxx-rebirth/d1x-rebirth/mem/mem.c,v $ * $Revision: 1.1.1.1 $ * $Author: zicodxx $ * $Date: 2006/03/17 19:39:19 $ * * Files for debugging memory allocator * * $Log: mem.c,v $ * Revision 1.1.1.1 2006/03/17 19:39:19 zicodxx * initial import * * Revision 1.4 2000/02/07 07:31:08 donut * added memsize to printinfo (unfree'd blocks report) * * Revision 1.3 1999/10/15 05:22:15 donut * typedef'd ssize_t on windows * * Revision 1.2 1999/10/14 04:48:21 donut * alpha fixes, and gl_font args * * Revision 1.1.1.1 1999/06/14 22:13:45 donut * Import of d1x 1.37 source. * * Revision 1.18 1995/01/24 20:49:18 matt * Made some stuff return when get errors * * Revision 1.17 1994/11/29 15:40:38 matt * Added extra newline after message * * Revision 1.16 1994/11/15 18:27:56 john * Took away show mem info by default. * * Revision 1.15 1994/11/10 10:00:37 john * Made it show_mem_info by default. * * Revision 1.14 1994/11/10 09:53:06 john * Put in more efficient, but less debugging info version. * * Revision 1.13 1994/10/27 00:56:45 john * Reduced number of blocks; made show mem usage by default. * * Revision 1.12 1994/10/06 19:15:17 john * Upped the number of blocks. * * * Revision 1.11 1994/07/27 20:04:22 john * Neatend printed output. * * Revision 1.10 1994/07/20 10:22:17 yuan * Added overwrite error * * Revision 1.9 1994/03/23 12:58:43 john * Made message global. * * Revision 1.8 1994/03/15 11:12:59 john * Made calloc fill block with zeros like it's * supposed to. * * Revision 1.7 1994/02/18 12:43:21 john * Only print mem debugging info if show_mem_info * is true. Need to set in debugger, btw. * * Revision 1.6 1994/02/17 17:01:34 john * Took out MEM_LEAKAGE warning! * * Revision 1.5 1994/01/24 16:04:47 john * Added mem_print_all function to dump all * allocated memory to inferno.mem file. * * * Revision 1.4 1994/01/18 11:01:41 john * *** empty log message *** * * Revision 1.3 1993/12/10 12:20:50 john * Speed up by replacing mem_find_unused_id with a table lookup. * * Revision 1.2 1993/12/08 12:38:22 mike * Change 10000 to MAX_INDEX * Use LargestIndex in place of MAX_INDEX as appropriate. * * Revision 1.1 1993/11/02 17:45:28 john * Initial revision * * */ #ifdef RCS static char rcsid[] = "$Id: mem.c,v 1.1.1.1 2006/03/17 19:39:19 zicodxx Exp $"; #endif #if defined(__DJGPP__) || defined(__WATCOMC__) #define CHECK_DWORD_BELOW #endif // Warning( "MEM: Too many malloc's!" ); // Warning( "MEM: Malloc returnd an already alloced block!" ); // Warning( "MEM: Malloc Failed!" ); // Warning( "MEM: Freeing the NULL pointer!" ); // Warning( "MEM: Freeing a non-malloced pointer!" ); // Warning( "MEM: %d/%d check bytes were overwritten at the end of %8x", ec, CHECKSIZE, buffer ); // Warning( "MEM: %d blocks were left allocated!", numleft ); #include #include #include #include #include #if defined(_DEBUG) && defined(_MSC_VER) #include #endif #include "mono.h" #include "error.h" #include "types.h" #if !defined(_DEBUG) && !defined(_MSC_VER) #define FULL_MEM_CHECKING #endif #ifdef FULL_MEM_CHECKING #define CHECKSIZE 16 #define CHECKBYTE 0xFC #define MAX_INDEX 10000 //edited 05/17/99 Matt Mueller - use pointer vars/formats instead of typecasting to int static char * MallocBase[MAX_INDEX]; //end edit -MM static unsigned int MallocSize[MAX_INDEX]; static unsigned int MallocRealSize[MAX_INDEX]; static unsigned int Signature[MAX_INDEX]; static unsigned char Present[MAX_INDEX]; static char * Filename[MAX_INDEX]; static char * Varname[MAX_INDEX]; static int Line[MAX_INDEX]; static int BytesMalloced = 0; static int MaxMalloced = 0; static unsigned int LastSignature = 0; static unsigned int SmallestAddress = 0xFFFFFFF; static unsigned int LargestAddress = 0x0; int show_mem_info = 0; static int free_list[MAX_INDEX]; static int num_blocks = 0; static int Initialized = 0; static int LargestIndex = 0; int out_of_memory = 0; void mem_display_blocks(void); void mem_init() { int i; Initialized = 1; for (i=0; i= MAX_INDEX ) { fprintf( stderr,"\nMEM_OUT_OF_SLOTS: Not enough space in mem.c to hold all the mallocs.\n" ); fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", var, filename, line ); Error( "MEM_OUT_OF_SLOTS" ); } id = free_list[ num_blocks++ ]; if (id > LargestIndex ) LargestIndex = id; if (id==-1) { fprintf( stderr,"\nMEM_OUT_OF_SLOTS: Not enough space in mem.c to hold all the mallocs.\n" ); fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], Line[id] ); Error( "MEM_OUT_OF_SLOTS" ); } ptr = malloc( size+CHECKSIZE ); //this is a bit noisy.. printf("malloc'd %i+%i (%i) at %p id %i\n",size,CHECKSIZE,size+CHECKSIZE,ptr,id); /* for (j=0; j<=LargestIndex; j++ ) { if (Present[j] && MallocBase[j] == (unsigned int)ptr ) { fprintf( stderr,"\nMEM_SPACE_USED: Malloc returned a block that is already marked as preset.\n" ); fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[j], Filename[j], Line[j] ); Warning( "MEM_SPACE_USED" ); Int3(); } } */ if (ptr==NULL) { out_of_memory = 1; fprintf( stderr, "\nMEM_OUT_OF_MEMORY: Malloc returned NULL\n" ); fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], Line[id] ); Error( "MEM_OUT_OF_MEMORY" ); Int3(); } base = (size_t)ptr; if ( base < SmallestAddress ) SmallestAddress = base; if ( (base+size) > LargestAddress ) LargestAddress = base+size; //edited 05/17/99 Matt Mueller - use pointer vars/formats instead of typecasting to int MallocBase[id] = ptr; //end edit -MM data = (ssize_t *)((ssize_t)MallocBase[id]-4); MallocRealSize[id] = *data; MallocSize[id] = size; Varname[id] = var; Filename[id] = filename; Line[id] = line; Present[id] = 1; Signature[id] = (LastSignature++); pc = (char *)ptr; BytesMalloced += size; if (BytesMalloced > MaxMalloced) MaxMalloced = BytesMalloced; for (i=0; i #include #include #define get_frame_pointer() ({ int ret; asm("mov %%ebp,%0" : "=r" (ret)); (unsigned int *)ret; }) int i; unsigned int maxaddr; unsigned int *fp = get_frame_pointer(); maxaddr = __dpmi_get_segment_limit(_my_ds()); PrintInfo( id ); for (i=0;i<10;i++) { if (!fp || (unsigned int)fp > maxaddr) break; fprintf(stderr, "%x ", fp[1]); fp = (unsigned int *)fp[0]; } fprintf(stderr, "\n"); } #endif return ptr; } int mem_find_id( void * buffer ) { int i; for (i=0; i<=LargestIndex; i++ ) if (Present[i]==1) //edited 05/17/99 Matt Mueller - use pointer vars/formats instead of typecasting to int if (MallocBase[i] == buffer ) //end edit -MM return i; // Didn't find id. return -1; } int mem_check_integrity( int block_number ) { #ifdef CHECK_DWORD_BELOW int * data; #endif int i, ErrorCount; unsigned char * CheckData; CheckData = (char *)(MallocBase[block_number] + MallocSize[block_number]); #ifdef CHECK_DWORD_BELOW data = (int *)((int)MallocBase[block_number]-4); if ( *data != MallocRealSize[block_number] ) { fprintf( stderr, "\nMEM_BAD_LENGTH: The length field of an allocated block was overwritten.\n" ); PrintInfo( block_number ); //Int3(); *data = MallocRealSize[block_number]; } #endif ErrorCount = 0; for (i=0; i MaxMalloced) MaxMalloced = BytesMalloced; MallocSize[id] = size; //edited 05/17/99 Matt Mueller - use pointer vars/formats instead of typecasting to int MallocBase[id] = ptr; //end edit -MM data = (ssize_t *)((ssize_t)MallocBase[id]-4); MallocRealSize[id] = *data; Filename[id] = filename; Line[id] = line; for (i=0; i LargestAddress ) LargestAddress = base+size; psize = (int *)ptr; psize--; BytesMalloced += *psize; if (fill_zero) memset( ptr, 0, size ); return ptr; } void mem_free( void * buffer ) { int ErrorCount; int * psize = (int *)buffer; psize--; if (Initialized==0) mem_init(); if (buffer==NULL) { fprintf( stderr, "\nMEM_FREE_NULL: An attempt was made to free the null pointer.\n" ); Warning( "MEM: Freeing the NULL pointer!" ); Int3(); return; } ErrorCount = 0; if (ErrorCount) { fprintf( stderr, "\nMEM_OVERWRITE: Memory after the end of allocated block overwritten.\n" ); fprintf( stderr, "\tBlock at 0x%p, size %d\n", buffer, *psize ); fprintf( stderr, "\t%d/%d check bytes were overwritten.\n", ErrorCount, CHECKSIZE ); } BytesMalloced -= *psize; #if defined(_DEBUG) && defined(_MSC_VER) _free_dbg( buffer, _CLIENT_BLOCK); #else free( buffer ); #endif } void mem_display_blocks() { if (Initialized==0) return; if (show_mem_info) { if (BytesMalloced != 0 ) { fprintf( stderr, "\nMEM_LEAKAGE: %u bytes of memory have not been freed.\n", BytesMalloced ); } // fprintf( stderr, " MaxMalloced:%u\n", MaxMalloced); #ifdef __WATCOMC__ fprintf( stderr, "\n\nMEMORY USAGE:\n" ); fprintf( stderr, " %u Kbytes dynamic data\n", (LargestAddress-SmallestAddress+512)/1024 ); fprintf( stderr, " %u Kbytes code/static data.\n", (SmallestAddress-(4*1024*1024)+512)/1024 ); fprintf( stderr, " ---------------------------\n" ); fprintf( stderr, " %u Kbytes required.\n", (LargestAddress-(4*1024*1024)+512)/1024 ); #else { #ifndef NO_ASM extern int end __asm__("end"); #endif // fprintf( stderr, " %u Kbytes dynamic data\n", (MaxMalloced + 512) / 1024); // fprintf( stderr, " %u Kbytes code/static data\n", ((unsigned int)&end + 512) / 1024); } #endif } } void mem_validate_heap() { } void mem_print_all() { } #endif