dxx-rebirth/mem/mem.c
2006-03-20 16:43:15 +00:00

652 lines
16 KiB
C
Executable file

/*
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;
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; 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, "\tBlock '%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,"\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<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;
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<CHECKSIZE; i++ )
if (CheckData[i] != CHECKBYTE ) {
ErrorCount++;
fprintf( stderr, "OA: %p ", &CheckData[i] );
}
if (ErrorCount && (!out_of_memory)) {
fprintf( stderr, "\nMEM_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, "\nMEM_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, "\nMEM_FREE_NOMALLOC: An attempt was made to free a ptr that wasn't\nallocated 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, "\nMEM_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\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\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, "\nMEM_MALLOC_ZERO: Attempting to malloc 0 bytes.\n" );
fprintf( stderr, "\tVar %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, "\nMEM_OUT_OF_MEMORY: Malloc returned NULL\n" );
fprintf( stderr, "\tVar %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, "\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