home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
cproto.zip
/
cproto46
/
trace.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-01-18
|
6KB
|
319 lines
/* $Id: trace.c,v 4.2 1998/01/19 00:49:33 cthuang Exp $
*
* Simple malloc debugging (for finding leaks)
*
* This is a cut-down version of a module I wrote originally for 'vile', it
* requires an ANSI compiler. Its main purpose is to allow tracing problems in
* a repeatable test, including malloc/free bugs -- dickey@clark.net
*/
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include <trace.h> /* interface of this module */
#include <stdlib.h>
#include <stdio.h>
#if TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
#define BEFORE 0 /* padding "before" allocated area */
#define AFTER 0 /* padding "after" allocated area */
#include <stdarg.h>
#if DOALLOC
#undef malloc
#undef realloc
#undef free
#endif /* DOALLOC */
void
Trace(char *format, ...)
{
static FILE *fp;
va_list ap;
if (!fp)
fp = fopen("Trace.out", "w");
if (!fp)
abort();
va_start(ap,format);
if (format != 0) {
vfprintf(fp, format, ap);
va_end(ap);
(void)fflush(fp);
} else {
(void)fclose(fp);
(void)fflush(stdout);
(void)fflush(stderr);
}
}
#define SECS(tv) (tv.tv_sec + (tv.tv_usec / 1.0e6))
void
Elapsed(char *msg)
{
#if HAVE_GETTIMEOFDAY
static struct timeval tv0, tv1;
static struct timezone tz0, tz1;
static int init;
if (!init++)
gettimeofday(&tv0, &tz0);
gettimeofday(&tv1, &tz1);
Trace("%10.6f %s\n", SECS(tv1) - SECS(tv0), msg);
tv0 = tv1;
#endif
}
#ifdef apollo
static
int contains(char *ref, char *tst)
{
size_t len = strlen(ref);
while (*tst) {
if (!strncmp(ref,tst++,len))
return TRUE;
}
return FALSE;
}
#endif /* apollo */
void
WalkBack(void)
{
#ifdef apollo
static char *first = "\"WalkBack\"",
*last = "\"unix_$main\"";
auto FILE *pp;
auto char bfr[BUFSIZ];
auto int ok = FALSE;
static int count;
Trace("%s %d\n", first, ++count);
sprintf(bfr, "/com/tb %d", getpid());
if (!(pp = popen(bfr, "r")))
perror(bfr);
while (fgets(bfr, sizeof(bfr), pp)) {
if (ok && contains(last, bfr))
break;
else if (contains(first, bfr))
ok = TRUE;
else if (ok)
Trace("%s", bfr);
}
(void)fclose(pp);
#endif /* apollo */
}
static long count_alloc,
count_freed;
void
fail_alloc(char *msg, char *ptr)
{
Trace("%s: %p\n", msg, ptr);
Trace("allocs %ld, frees %ld\n", count_alloc, count_freed);
WalkBack();
#if NO_LEAKS
show_alloc();
#endif
Trace((char *)0);
abort();
}
#if DOALLOC
#undef malloc
#undef realloc
#undef free
typedef struct {
long size; /* ...its size */
char *text; /* the actual segment */
int note; /* ...last value of 'count_alloc' */
} AREA;
static AREA area[DOALLOC];
static long maxAllocated, /* maximum # of bytes allocated */
nowAllocated, /* current # of bytes allocated */
nowPending, /* current end of 'area[]' table */
maxPending; /* maximum # of segments allocated */
static
int FindArea(char *ptr)
{
register int j;
for (j = 0; j < DOALLOC; j++)
if (area[j].text == ptr) {
if (j >= nowPending) {
nowPending = j+1;
if (nowPending > maxPending)
maxPending = nowPending;
}
return j;
}
return -1;
}
static
int record_freed(char *ptr)
{
register int j;
if ((j = FindArea(ptr)) >= 0) {
nowAllocated -= area[j].size;
/*memset(ptr, 0xdf, area[j].size); -* poison */
area[j].size = 0;
area[j].text = 0;
area[j].note = count_freed;
if ((j+1) == nowPending) {
register int k;
for (k = j; (k >= 0) && !area[k].size; k--)
nowPending = k;
}
}
return j;
}
static
int record_alloc(char *newp, char *oldp, unsigned len)
{
register int j;
if (newp == oldp) {
if ((j = FindArea(oldp)) >= 0) {
nowAllocated -= area[j].size;
area[j].size = len;
area[j].note = count_alloc;
} else
fail_alloc("could not find", oldp);
} else {
if (oldp != 0)
record_freed(oldp);
if ((j = FindArea((char *)0)) >= 0) {
area[j].text = newp;
area[j].size = len;
area[j].note = count_alloc;
} else
fail_alloc("no room in table", newp);
}
nowAllocated += len;
if (nowAllocated > maxAllocated)
maxAllocated = nowAllocated;
return len;
}
#define OK_ALLOC(p,q,n) ((p != 0) && (record_alloc(p,q,n) >= 0))
#define OK_FREE(p) ((p != 0) && (record_freed(p) >= 0))
#else
#define OK_ALLOC(p,q,n) (p != 0)
#define OK_FREE(p) (p != 0)
#endif /* DOALLOC */
#ifdef DEBUG2
#define LOG_PTR(msg,num) Trace("%s %p\n", msg, num);
#define LOG_LEN(msg,num) Trace("%s %d\n", msg, num);
#else
#define LOG_PTR(msg,num)
#define LOG_LEN(msg,num)
#endif
/************************************************************************
* public entrypoints *
************************************************************************/
#if DOALLOC
void *
doalloc (void *oldp, unsigned amount)
{
register void *newp;
if (oldp != 0)
oldp -= BEFORE;
count_alloc += (oldp == 0);
#if 0
if ((count_alloc > 99914 && count_alloc < 99920)) {
Trace("doalloc #%d\n", count_alloc);
WalkBack();
}
#endif
LOG_LEN("allocate", amount)
LOG_PTR(" old = ", oldp)
amount += (BEFORE+AFTER); /* patch */
newp = (oldp != 0) ? realloc(oldp, amount) : malloc(amount);
if (!OK_ALLOC(newp,oldp,amount)) {
perror("doalloc");
fail_alloc("doalloc", oldp);
/*NOT REACHED*/
}
LOG_PTR(" new = ", newp)
return (newp+BEFORE);
}
/*
* Entrypoint so we can validate pointers
*/
void
dofree(void *oldp)
{
oldp -= BEFORE;
count_freed++;
LOG_PTR("dealloc ", oldp)
if (OK_FREE(oldp)) {
free(oldp);
return;
}
fail_alloc("free (not found)", oldp);
}
#endif
void
show_alloc(void)
{
#if DOALLOC
static char *format = ".. %-24.24s %10ld\n";
Trace("** allocator metrics:\n");
Trace(format, "allocs:", count_alloc);
Trace(format, "frees:", count_freed);
{
register int j, count = 0;
register long total = 0;
for (j = 0; j < nowPending; j++) {
if (area[j].text) {
if (count++ < 10)
Trace("...%d) %ld bytes in alloc #%d:%p\n",
j,
area[j].size,
area[j].note,
area[j].text);
total += area[j].size;
}
}
Trace(format, "total bytes allocated:", total);
Trace(format, "current bytes allocated:", nowAllocated);
Trace(format, "maximum bytes allocated:", maxAllocated);
Trace(format, "segment-table length:", nowPending);
Trace(format, "current # of segments:", (long)count);
Trace(format, "maximum # of segments:", maxPending);
}
#endif
}