2006-12-19 22:56:18 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
** Zmalloc, a simple memory-allocation monitor.
|
|
|
|
**
|
|
|
|
** Version 2. added detection for writing off the end or beginning
|
|
|
|
** of buffers, freeing the same block multiple times. Also now use the
|
|
|
|
** env variable to set the name of a file to write output to.
|
|
|
|
**
|
|
|
|
**
|
|
|
|
** Copyright 1996,1998,1999,2000 Eric Murray, ericm@lne.com
|
|
|
|
**
|
|
|
|
** You may make free use of this code but please give me credit.
|
|
|
|
**
|
|
|
|
**
|
|
|
|
** Documentation: http://www.lne.com/ericm/zmalloc
|
|
|
|
**
|
|
|
|
** $Id: zmalloc.c,v 1.3 2000/06/26 18:38:53 ericm Exp $
|
|
|
|
** $Log: zmalloc.c,v $
|
|
|
|
** Revision 1.3 2000/06/26 18:38:53 ericm
|
|
|
|
** updated copyright
|
|
|
|
** fixed a bug in the test code
|
|
|
|
** added a test for unfreed memory
|
|
|
|
**
|
|
|
|
** Revision 1.2 1998/05/25 16:38:22 ericm
|
|
|
|
** added more checking: multiple frees, overwriting buffers
|
|
|
|
** use env variable to set output to stdin, stdout, file
|
|
|
|
**
|
|
|
|
** Revision 1.1 1998/05/25 16:31:35 ericm
|
|
|
|
** Initial revision
|
|
|
|
**
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/* protect our calloc() and free() calls from recursive redefinition: */
|
|
|
|
#define ZMALLOC_H
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
//#define NO_MEMORY_PADDING
|
|
|
|
|
|
|
|
#ifndef NO_MEMORY_PADDING
|
|
|
|
static unsigned char beginPad[4] = {
|
|
|
|
0xde, 0xad, 0xde, 0xad };
|
|
|
|
|
|
|
|
static unsigned char endPad[4] = {
|
|
|
|
0xde, 0xad, 0xde, 0xad };
|
|
|
|
#endif
|
|
|
|
|
|
|
|
extern int errno;
|
|
|
|
|
|
|
|
FILE * zfd;
|
|
|
|
|
|
|
|
typedef struct meminfo {
|
|
|
|
struct meminfo *next;
|
|
|
|
int size; /* number of bytes malloced */
|
|
|
|
long addr; /* address of memory returned */
|
|
|
|
int frees; /* number of times that 'free' was called on this memory */
|
|
|
|
char *file; /* file where malloc was called */
|
|
|
|
int line; /* line in the code where malloc was called */
|
|
|
|
} meminfo;
|
|
|
|
|
|
|
|
static meminfo memlist;
|
|
|
|
/* -1 not checked yet, 0 = no zmalloc, 1 = zmalloc */
|
|
|
|
int zmallocstatus = -1;
|
|
|
|
|
|
|
|
/* functions: */
|
|
|
|
int getzmallocstatus(void);
|
|
|
|
int * zmalloc(int len,char * file,int line);
|
|
|
|
void zfree_special(int * what, char * file,int line);
|
|
|
|
void zfree(int * what, char * file,int line);
|
|
|
|
char *zstrdup(const char *src, char *file, int line);
|
|
|
|
void zmalloc_check( void );
|
|
|
|
void pad_check(meminfo *m);
|
|
|
|
void zmalloc_free_list(meminfo *m);
|
|
|
|
|
|
|
|
/* a chopped down version that works */
|
|
|
|
int getzmallocstatus()
|
|
|
|
{
|
|
|
|
if (zmallocstatus == -1) {
|
|
|
|
zfd = fopen("test.log","w+");
|
|
|
|
zmallocstatus = 1;
|
|
|
|
}
|
|
|
|
return(zmallocstatus);
|
|
|
|
}
|
|
|
|
|
|
|
|
int * zmalloc(int len,char * file,int line)
|
|
|
|
{
|
|
|
|
unsigned char * ret;
|
|
|
|
meminfo *m;
|
|
|
|
|
|
|
|
if (!zmallocstatus) {
|
|
|
|
/* zmalloc turned off */
|
|
|
|
ret = (unsigned char *)calloc(1,len);
|
|
|
|
return((int *)ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef NO_MEMORY_PADDING
|
|
|
|
ret = (unsigned char *)calloc(1,len + sizeof(beginPad) + sizeof(endPad));
|
|
|
|
#else
|
|
|
|
ret = (unsigned char *)calloc(1,len);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!ret)
|
|
|
|
fprintf(zfd,"zmalloc: malloc FAILED");
|
|
|
|
|
|
|
|
#ifndef NO_MEMORY_PADDING
|
|
|
|
/* insert begin and end padding to detect buffer under/overruns: */
|
|
|
|
memcpy(ret,beginPad,sizeof(beginPad));
|
|
|
|
ret += sizeof(beginPad); /* make ret skip begin pad */
|
|
|
|
memcpy(ret + len,endPad,sizeof(endPad));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (getzmallocstatus() > 1)
|
|
|
|
fprintf(zfd,"zmalloc: 0x%4.4x %d bytes %s:%d\n",(int)ret,len,file,line);
|
|
|
|
|
|
|
|
m = (meminfo *)calloc(1,sizeof(meminfo));
|
|
|
|
if (!m) {
|
|
|
|
fprintf(zfd,"zmalloc: FAILED mem alloc for zmalloc struct... bailing!\n");
|
|
|
|
return((int*)0);
|
|
|
|
}
|
|
|
|
m->next = &memlist;
|
|
|
|
m->addr = (long)ret;
|
|
|
|
m->size = (int)len;
|
|
|
|
m->file = (char *)strdup(file);
|
|
|
|
m->frees = 0;
|
|
|
|
if (!m->file) {
|
|
|
|
fprintf(zfd,"zmalloc: FAILED mem alloc for zmalloc struct... bailing!\n");
|
|
|
|
return((int*)0);
|
|
|
|
}
|
|
|
|
m->line = line;
|
|
|
|
return((int *)ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
void zfree_special(int * what, char * file,int line)
|
|
|
|
{
|
|
|
|
meminfo *m, *old;
|
|
|
|
unsigned char *addr;
|
|
|
|
int gotit = 0;
|
|
|
|
|
|
|
|
if (what == 0) {
|
|
|
|
fprintf(zfd,"zmalloc: Null pointer free'd: %s:%d\n", file, line);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!getzmallocstatus()) {
|
|
|
|
free(what);
|
|
|
|
} else {
|
|
|
|
/* look up allocated mem in list: */
|
|
|
|
old = m = &memlist;
|
|
|
|
if (m == (meminfo *)0) {
|
|
|
|
/* no memlist */
|
|
|
|
free(what);
|
|
|
|
} else {
|
|
|
|
for(; m ; m = m->next) {
|
|
|
|
if (m->addr == (long)what) {
|
|
|
|
/* got it. Print it if verbose: */
|
|
|
|
addr = (unsigned char *)m->addr;
|
|
|
|
|
|
|
|
fprintf(zfd,"zmalloc: Freed 0x%4.4x %d bytes mallocd@%s:%d\n",
|
|
|
|
(int)addr,m->size,m->file,m->line);
|
|
|
|
fprintf(zfd," free'd from %s:%d\n",
|
|
|
|
file, line);
|
|
|
|
|
|
|
|
|
|
|
|
/* check the padding: */
|
|
|
|
pad_check(m);
|
|
|
|
|
|
|
|
/* note that we freed the memory */
|
|
|
|
m->frees++;
|
|
|
|
|
|
|
|
/* check to see if it was freed > once */
|
|
|
|
if (m->frees > 1) {
|
|
|
|
fprintf(zfd," ERR: multiple frees! 0x%4.4x %d bytes: %s:%d\n",
|
|
|
|
(int)addr, m->size, m->file, m->line);
|
|
|
|
fprintf(zfd," free'd from %s:%d\n",
|
|
|
|
file, line);
|
|
|
|
}
|
|
|
|
gotit++;
|
|
|
|
if (!m)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!gotit && m) {
|
|
|
|
fprintf(zfd,"zmalloc: ERR: Freed unallocated memory");
|
|
|
|
fprintf(zfd," @0x%4.4x %d bytes %s:%d\n",
|
|
|
|
(int)what,m->size,m->file,m->line);
|
|
|
|
}
|
|
|
|
else if (gotit > 1) {
|
|
|
|
/* this shouldn't happen, eh? */
|
|
|
|
fprintf(zfd," ERR: Multiply-allocd memory!\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void zfree(int * what, char * file,int line)
|
|
|
|
{
|
|
|
|
meminfo *m, *old;
|
|
|
|
unsigned char *addr;
|
|
|
|
int gotit = 0;
|
|
|
|
|
|
|
|
if (what == 0) {
|
|
|
|
fprintf(zfd,"zmalloc: Null pointer free'd: %s:%d\n", file, line);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!getzmallocstatus()) {
|
|
|
|
free(what);
|
|
|
|
} else {
|
|
|
|
/* look up allocated mem in list: */
|
|
|
|
old = m = &memlist;
|
|
|
|
if (m == (meminfo *)0) {
|
|
|
|
/* no memlist */
|
|
|
|
free(what);
|
|
|
|
} else {
|
|
|
|
for(; m ; m = m->next) {
|
|
|
|
if (m->addr == (long)what) {
|
|
|
|
/* got it. Print it if verbose: */
|
|
|
|
addr = (unsigned char *)m->addr;
|
|
|
|
if (getzmallocstatus() > 1)
|
|
|
|
fprintf(zfd,"zmalloc: Freed 0x%4.4x %d bytes mallocd@%s:%d\n",
|
|
|
|
(int)addr,m->size,m->file,m->line);
|
|
|
|
|
|
|
|
/* check the padding: */
|
|
|
|
pad_check(m);
|
|
|
|
|
|
|
|
/* note that we freed the memory */
|
|
|
|
m->frees++;
|
|
|
|
|
|
|
|
/* check to see if it was freed > once */
|
|
|
|
if (m->frees > 1) {
|
|
|
|
fprintf(zfd," ERR: multiple frees! 0x%4.4x %d bytes: %s:%d\n",
|
|
|
|
(int)addr, m->size, m->file, m->line);
|
|
|
|
fprintf(zfd," free'd from %s:%d\n",
|
|
|
|
file, line);
|
|
|
|
}
|
|
|
|
gotit++;
|
|
|
|
if (!m)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!gotit && m) {
|
|
|
|
fprintf(zfd,"zmalloc: ERR: Freed unallocated memory");
|
|
|
|
fprintf(zfd," @0x%4.4x %d bytes %s:%d\n",
|
|
|
|
(int)what,m->size,m->file,m->line);
|
|
|
|
}
|
|
|
|
else if (gotit > 1) {
|
|
|
|
/* this shouldn't happen, eh? */
|
|
|
|
fprintf(zfd," ERR: Multiply-allocd memory!\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* zstrdup */
|
|
|
|
char *zstrdup(const char *src, char *file, int line)
|
|
|
|
{
|
|
|
|
char *result;
|
|
|
|
#ifndef NO_MEMORY_STRDUP
|
|
|
|
if (!getzmallocstatus()) {
|
|
|
|
result = (char*)malloc(strlen(src) + 1);
|
|
|
|
if (result == (char*)0)
|
|
|
|
return (char*)0;
|
|
|
|
strcpy(result, src); /* strcpy ok, size checked above */
|
|
|
|
return result;
|
|
|
|
} else {
|
|
|
|
result = (char*)zmalloc(strlen(src) + 1, file, line);
|
|
|
|
if (result == (char*)0)
|
|
|
|
return (char*)0;
|
|
|
|
strcpy(result, src);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
result = (char*)malloc(strlen(src) + 1);
|
|
|
|
if (result == (char*)0)
|
|
|
|
return (char*)0;
|
|
|
|
strcpy(result, src); /* strcpy ok, size checked above */
|
|
|
|
return result;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void zmalloc_check()
|
|
|
|
{
|
|
|
|
meminfo *m;
|
|
|
|
char *admonishemnt;
|
|
|
|
int total_leak = 0;
|
|
|
|
int num_leaks = 0;
|
|
|
|
|
|
|
|
if (getzmallocstatus() > 0) {
|
|
|
|
/* look up allocated mem in list: */
|
|
|
|
for(m = &memlist; m ; m = m->next) {
|
|
|
|
if (m->addr != 0 && m->frees <= 0) {
|
|
|
|
fprintf(zfd,"zmalloc: UNfreed memory 0x%4.4x %d bytes mallocd at %s:%d\n",
|
|
|
|
(int)m->addr,m->size,m->file,m->line);
|
|
|
|
|
|
|
|
/* check padding on un-freed memory too: */
|
|
|
|
pad_check(m);
|
|
|
|
|
|
|
|
total_leak += m->size;
|
|
|
|
num_leaks ++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (total_leak) {
|
|
|
|
if (total_leak > 10000)
|
|
|
|
admonishemnt = "you must work for Microsoft.";
|
|
|
|
else if (total_leak > 5000)
|
|
|
|
admonishemnt = "you should be ashamed!";
|
|
|
|
else if (total_leak > 2000)
|
|
|
|
admonishemnt = "you call yourself a programmer?";
|
|
|
|
else if (total_leak > 1000)
|
|
|
|
admonishemnt = "the X consortium has a job for you...";
|
|
|
|
else
|
|
|
|
admonishemnt = "close, but not there yet.";
|
|
|
|
fprintf(zfd,"zmalloc: %d leaks totalling %d bytes... %s\n",num_leaks,total_leak,
|
|
|
|
admonishemnt);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
fprintf(zfd,"zmalloc: Congratulations: leak-free code!\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* free up our own internal list */
|
|
|
|
zmalloc_free_list(&memlist);
|
|
|
|
}
|
|
|
|
|
|
|
|
void pad_check(meminfo *m)
|
|
|
|
{
|
|
|
|
#ifndef NO_MEMORY_PADDING
|
|
|
|
unsigned char *addr = (unsigned char *)m->addr;
|
|
|
|
|
|
|
|
/* check the padding: */
|
|
|
|
if (memcmp((int *)(addr - sizeof(beginPad)),
|
|
|
|
beginPad, sizeof(beginPad)) != 0)
|
|
|
|
fprintf(zfd," ERR: beginPad was modified!\n");
|
|
|
|
if (memcmp((int *)(addr + m->size),endPad,
|
|
|
|
sizeof(endPad)) != 0)
|
|
|
|
fprintf(zfd," ERR: endPad was modified!\n");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void zmalloc_free_list(meminfo *m)
|
|
|
|
{
|
|
|
|
meminfo *old;
|
|
|
|
for( m = m->next ; m ; ) {
|
|
|
|
old = m;
|
|
|
|
m = m->next;
|
|
|
|
free(old->file);
|
|
|
|
free(old);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef ZTEST
|
|
|
|
#undef ZMALLOC_H
|
|
|
|
|
|
|
|
#include "zmalloc.h"
|
|
|
|
|
|
|
|
main()
|
|
|
|
{
|
2006-12-27 21:16:28 +00:00
|
|
|
unsigned char * tmp;
|
2006-12-19 22:56:18 +00:00
|
|
|
|
|
|
|
|
|
|
|
printf("Testing Zmalloc.\n");
|
|
|
|
printf("Malloc test..");
|
|
|
|
printf("You should see no error here.\n");
|
2006-12-27 21:16:28 +00:00
|
|
|
tmp = (unsigned char*)malloc(200);
|
|
|
|
free(tmp);
|
2006-12-19 22:56:18 +00:00
|
|
|
|
|
|
|
printf("Free free mem test...\n");
|
|
|
|
printf("You should see an ERR: multiple frees here\n");
|
2006-12-27 21:16:28 +00:00
|
|
|
tmp = (unsigned char*)malloc(200);
|
|
|
|
free(tmp);
|
|
|
|
free(tmp);
|
2006-12-19 22:56:18 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
fprintf(zfd,"\nFree unallocated mem test \n");
|
2006-12-27 21:16:28 +00:00
|
|
|
tmp += 4;
|
|
|
|
free(tmp);
|
2006-12-19 22:56:18 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
printf("Unfreed mem test...\n");
|
|
|
|
printf("You should see an \"UNfreed mem at line %d\" (at end) because of this\n",__LINE__+1);
|
2006-12-27 21:16:28 +00:00
|
|
|
tmp = (unsigned char*)malloc(200);
|
2006-12-19 22:56:18 +00:00
|
|
|
|
|
|
|
printf("Buffer overrun test 1...\n");
|
|
|
|
printf("You should see an ERR:endPad here\n");
|
2006-12-27 21:16:28 +00:00
|
|
|
tmp = (unsigned char*)malloc(200);
|
|
|
|
tmp[200] = 0xfa;
|
|
|
|
free(tmp);
|
2006-12-19 22:56:18 +00:00
|
|
|
|
|
|
|
printf("Buffer overrun test 2...\n");
|
|
|
|
printf("You should see an ERR:endPad here\n");
|
2006-12-27 21:16:28 +00:00
|
|
|
tmp = (unsigned char*)malloc(200);
|
|
|
|
tmp[215] = 0xbb;
|
|
|
|
free(tmp);
|
2006-12-19 22:56:18 +00:00
|
|
|
|
|
|
|
printf("Buffer underrun test 1...\n");
|
|
|
|
printf("You should see an ERR:beginPad here\n");
|
2006-12-27 21:16:28 +00:00
|
|
|
tmp = (unsigned char*)malloc(200);
|
|
|
|
tmp[-10] = 0x0f;
|
|
|
|
free(tmp);
|
2006-12-19 22:56:18 +00:00
|
|
|
|
|
|
|
printf("Buffer underrun test 2...\n");
|
|
|
|
printf("You should see an ERR:beginPad here\n");
|
2006-12-27 21:16:28 +00:00
|
|
|
tmp = (unsigned char*)malloc(200);
|
|
|
|
tmp[-1] = 0x00;
|
|
|
|
free(tmp);
|
2006-12-19 22:56:18 +00:00
|
|
|
|
|
|
|
|
|
|
|
zmalloc_check();
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
#endif /* ZTEST */
|