2006-03-20 16:43:15 +00:00
/*
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 <stdio.h>
# include <stdlib.h>
# include <stdarg.h>
# include <string.h>
# include <malloc.h>
# if defined(_DEBUG) && defined(_MSC_VER)
# include <crtdbg.h>
# 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 ;
2006-10-06 00:39:15 +00:00
int show_mem_info = 1 ;
2006-03-20 16:43:15 +00:00
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 ; i + + )
{
free_list [ i ] = i ;
MallocBase [ i ] = 0 ;
MallocSize [ i ] = 0 ;
MallocRealSize [ i ] = 0 ;
Present [ i ] = 0 ;
Filename [ i ] = NULL ;
Varname [ i ] = NULL ;
Line [ i ] = 0 ;
}
SmallestAddress = 0xFFFFFFF ;
LargestAddress = 0x0 ;
num_blocks = 0 ;
LargestIndex = 0 ;
atexit ( mem_display_blocks ) ;
}
void PrintInfo ( int id )
{
//edited 05/17/99 Matt Mueller - use pointer vars/formats instead of typecasting to int -- edited 2000/02/06 Matt Mueller - added size to end.
fprintf ( stderr , " \t Block '%s' created in %s, line %d at %p (sig %u), %i bytes. \n " , Varname [ id ] , Filename [ id ] , Line [ id ] , MallocBase [ id ] , Signature [ id ] , MallocSize [ id ] ) ;
//end edit -MM
}
void * mem_malloc ( unsigned int size , char * var , char * filename , int line , int fill_zero )
{
size_t base ;
int i , id ;
void * ptr ;
char * pc ;
ssize_t * data ;
if ( Initialized = = 0 )
mem_init ( ) ;
if ( num_blocks > = MAX_INDEX ) {
fprintf ( stderr , " \n MEM_OUT_OF_SLOTS: Not enough space in mem.c to hold all the mallocs. \n " ) ;
fprintf ( stderr , " \t Block '%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 , " \n MEM_OUT_OF_SLOTS: Not enough space in mem.c to hold all the mallocs. \n " ) ;
fprintf ( stderr , " \t Block '%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 , " \n MEM_SPACE_USED: Malloc returned a block that is already marked as preset. \n " ) ;
fprintf ( stderr , " \t Block '%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 , " \n MEM_OUT_OF_MEMORY: Malloc returned NULL \n " ) ;
fprintf ( stderr , " \t Block '%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 < CHECKSIZE ; i + + )
pc [ size + i ] = ( char ) CHECKBYTE ;
if ( fill_zero )
memset ( ptr , 0 , size ) ;
#if 0
// print call stack
//if (!strcmp(filename,"..."))
if ( Signature [ id ] = = 378 )
{
# include <stdio.h>
# include <dpmi.h>
# include <sys/segments.h>
# 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 ;
2006-11-21 15:57:43 +00:00
CheckData = ( ubyte * ) ( ( char * ) MallocBase [ block_number ] + MallocSize [ block_number ] ) ;
2006-03-20 16:43:15 +00:00
# ifdef CHECK_DWORD_BELOW
data = ( int * ) ( ( int ) MallocBase [ block_number ] - 4 ) ;
if ( * data ! = MallocRealSize [ block_number ] ) {
fprintf ( stderr , " \n MEM_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 < CHECKSIZE ; i + + )
if ( CheckData [ i ] ! = CHECKBYTE ) {
ErrorCount + + ;
fprintf ( stderr , " OA: %p " , & CheckData [ i ] ) ;
}
if ( ErrorCount & & ( ! out_of_memory ) ) {
fprintf ( stderr , " \n MEM_OVERWRITE: Memory after the end of allocated block overwritten. \n " ) ;
PrintInfo ( block_number ) ;
fprintf ( stderr , " \t %d/%d check bytes were overwritten. \n " , ErrorCount , CHECKSIZE ) ;
}
return ErrorCount ;
}
void * mem_realloc ( void * ptr , unsigned int size , char * var , char * filename , int line , int fill_zero ) {
int id , i ;
ssize_t * data ;
if ( ! ptr )
return mem_malloc ( size , var , filename , line , fill_zero ) ;
id = mem_find_id ( ptr ) ;
if ( id = = - 1 ) {
fprintf ( stderr , " MEM_REALLOC_NOMALLOC: realloc'ing a non-malloced pointer " ) ;
exit ( 1 ) ;
}
mem_check_integrity ( id ) ;
ptr = realloc ( ptr , size + CHECKSIZE ) ;
BytesMalloced + = ( size - MallocSize [ id ] ) ;
if ( BytesMalloced > 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 < CHECKSIZE ; i + + )
( ( char * ) ptr ) [ size + i ] = ( char ) CHECKBYTE ;
return ptr ;
}
void mem_free ( void * buffer )
{
int id ;
if ( Initialized = = 0 )
mem_init ( ) ;
if ( buffer = = NULL & & ( ! out_of_memory ) )
{
fprintf ( stderr , " \n MEM_FREE_NULL: An attempt was made to free the null pointer. \n " ) ;
Warning ( " MEM: Freeing the NULL pointer! " ) ;
Int3 ( ) ;
return ;
}
id = mem_find_id ( buffer ) ;
if ( id = = - 1 & & ( ! out_of_memory ) )
{
fprintf ( stderr , " \n MEM_FREE_NOMALLOC: An attempt was made to free a ptr that wasn't \n allocated with mem.h included. \n " ) ;
Warning ( " MEM: Freeing a non-malloced pointer! " ) ;
Int3 ( ) ;
return ;
}
mem_check_integrity ( id ) ;
BytesMalloced - = MallocSize [ id ] ;
free ( buffer ) ;
Present [ id ] = 0 ;
MallocBase [ id ] = 0 ;
MallocSize [ id ] = 0 ;
free_list [ - - num_blocks ] = id ;
}
void mem_display_blocks ( )
{
int i , numleft ;
if ( Initialized = = 0 ) return ;
numleft = 0 ;
for ( i = 0 ; i < = LargestIndex ; i + + )
{
if ( Present [ i ] = = 1 & & ( ! out_of_memory ) )
{
numleft + + ;
if ( show_mem_info ) {
fprintf ( stderr , " \n MEM_LEAKAGE: Memory block has not been freed. \n " ) ;
PrintInfo ( i ) ;
}
mem_free ( ( void * ) MallocBase [ i ] ) ;
}
}
if ( numleft & & ( ! out_of_memory ) )
{
Warning ( " MEM: %d blocks were left allocated! " , numleft ) ;
}
if ( show_mem_info ) {
# if defined (__WATCOMC__) || defined (WIN32)
fprintf ( stderr , " \n \n MEMORY 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 \n " , ( LargestAddress - ( 4 * 1024 * 1024 ) + 512 ) / 1024 ) ;
# else
# if !defined(NO_ASM) && !defined(_MSC_VER)
extern int end __asm__ ( " end " ) ;
# endif
fprintf ( stderr , " %u Kbytes dynamic data \n " , ( MaxMalloced + 512 ) / 1024 ) ;
# if !defined(NO_ASM) && !defined(_MSC_VER)
fprintf ( stderr , " %u Kbytes code/static data \n " , ( ( unsigned int ) & end + 512 ) / 1024 ) ;
# endif
# endif
}
}
void mem_validate_heap ( )
{
int i ;
for ( i = 0 ; i < LargestIndex ; i + + )
if ( Present [ i ] = = 1 )
mem_check_integrity ( i ) ;
}
void mem_print_all ( )
{
FILE * ef ;
int i , size = 0 ;
ef = fopen ( " DESCENT.MEM " , " wt " ) ;
for ( i = 0 ; i < LargestIndex ; i + + )
if ( Present [ i ] = = 1 ) {
size + = MallocSize [ i ] ;
//fprintf( ef, "Var:%s\t File:%s\t Line:%d\t Size:%d Base:%x\n", Varname[i], Filename[i], Line[i], MallocSize[i], MallocBase[i] );
fprintf ( ef , " %12d bytes in %s declared in %s, line %d \n " , MallocSize [ i ] , Varname [ i ] , Filename [ i ] , Line [ i ] ) ;
}
fprintf ( ef , " %d bytes (%d Kbytes) allocated. \n " , size , size / 1024 ) ;
fclose ( ef ) ;
}
# else
static int Initialized = 0 ;
static unsigned int SmallestAddress = 0xFFFFFFF ;
static unsigned int LargestAddress = 0x0 ;
static unsigned int BytesMalloced = 0 ;
void mem_display_blocks ( ) ;
# define CHECKSIZE 16
# define CHECKBYTE 0xFC
int show_mem_info = 0 ;
void mem_init ( )
{
Initialized = 1 ;
SmallestAddress = 0xFFFFFFF ;
LargestAddress = 0x0 ;
atexit ( mem_display_blocks ) ;
}
void * mem_malloc ( unsigned int size , char * var , char * filename , int line , int fill_zero )
{
unsigned int base ;
void * ptr ;
int * psize ;
if ( Initialized = = 0 )
mem_init ( ) ;
if ( size = = 0 ) {
fprintf ( stderr , " \n MEM_MALLOC_ZERO: Attempting to malloc 0 bytes. \n " ) ;
fprintf ( stderr , " \t Var %s, file %s, line %d. \n " , var , filename , line ) ;
Error ( " MEM_MALLOC_ZERO " ) ;
Int3 ( ) ;
}
# if defined(_DEBUG) && defined(_MSC_VER)
ptr = _malloc_dbg ( size + CHECKSIZE , _CLIENT_BLOCK , filename , line ) ;
# else
ptr = malloc ( size + CHECKSIZE ) ;
# endif
if ( ptr = = NULL ) {
fprintf ( stderr , " \n MEM_OUT_OF_MEMORY: Malloc returned NULL \n " ) ;
fprintf ( stderr , " \t Var %s, file %s, line %d. \n " , var , filename , line ) ;
Error ( " MEM_OUT_OF_MEMORY " ) ;
Int3 ( ) ;
}
base = ( unsigned int ) ptr ;
if ( base < SmallestAddress ) SmallestAddress = base ;
if ( ( base + size ) > 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 , " \n MEM_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 , " \n MEM_OVERWRITE: Memory after the end of allocated block overwritten. \n " ) ;
fprintf ( stderr , " \t Block 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 , " \n MEM_LEAKAGE: %u bytes of memory have not been freed. \n " , BytesMalloced ) ;
}
// fprintf( stderr, " MaxMalloced:%u\n", MaxMalloced);
# ifdef __WATCOMC__
fprintf ( stderr , " \n \n MEMORY 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