Debugging library for programs that use malloc
Conor P. Cahill
cpcahil at virtech.uucp
Tue Jan 30 15:47:54 AEST 1990
The following is a "beta" release of a debugging library I have put
together. The purpose of the library is to catch many of the errors
made when using malloc'd memory. See the README for more information.
I have compiled the code on System V, Ultrix, and HP-UX. Check the
Makefile for any system dependent changes that need to be made.
If you use this on your system, I would like some feedback as to
it's usefullness, suggested additions, fixes, complaints, etc.
After a short beta period I will be submitting the package to
comp.sources.unix, so I would appreciate feedback as soon as you can
get it to me.
Good luck and enjoy.
Conor P. Cahill
# This is a shell archive.
# Remove everything above and including the cut line.
# Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: Shell Archiver
# Run the following text with /bin/sh to create:
# Makefile
# README
# calloc.c
# debug.h
# design
# dump.c
# free.c
# func.hdr
# malloc.c
# malloc.h
# malloc_chk.c
# memory.c
# pgm.c
# realloc.c
# string.c
# testmalloc.c
# testmem.c
# toascii.c
# toascii.h
# This archive created: Tue Jan 30 04:28:37 1990
cat << \SHAR_EOF > Makefile
CC=cc
# for System V systems use this CFLAGS
CFLAGS=-g -DSYS5
# else for BSD use:
CFLAGS=-g
LIB=libmalloc.a
OBJS= malloc.o \
free.o \
realloc.o \
calloc.o \
string.o \
malloc_chk.o \
memory.o \
toascii.o \
dump.o
TESTS=testmalloc testmem
all: $(LIB) pgm $(TESTS)
clean:
rm -f $(TESTS) pgm $(LIB) *.o
pgm: $(LIB) pgm.o
$(CC) -o $@ pgm.o $(LIB)
$(LIB): $(OBJS)
ar ru $(LIB) $(OBJS)
-if test -s /bin/ranlib; then /bin/ranlib $(LIB); else exit 0; fi
-if test -s /usr/bin/ranlib; then /usr/bin/ranlib $(LIB); else exit 0; fi
testmalloc: $(LIB) testmalloc.o
$(CC) -o $@ testmalloc.o $(LIB)
testmem: $(LIB) testmem.o
$(CC) -o $@ testmem.o $(LIB)
$(OBJS): malloc.h
toascii.o malloc.o dump.o: toascii.h
SHAR_EOF
cat << \SHAR_EOF > README
This package is a collection of routines which are a drop-in replacement
for the malloc(3), memory(3), string(3), and bstring(3) library functions.
The purpose of these programs is to aid the development and/or debugging
of programs using these functions by providing a high level of consistancy
checking whenever a malloc pointer is used. Due to this increased
level of consistancy checking, these functions have a considerably larger
overhead than the standard functions, but the extra checking should be
well worth it in a development environment.
To use these functions all you need to do is compile the library and
include it on your loader command line. You do not need to recompile
your code, only a relink is necessary.
Features of this library:
1. The malloced area returned from each call to malloc is filled with
non-null bytes. This should catch any use of uninitialized malloc
area. The fill pattern for malloced area is 0x01.
2. When free is called numerous validity checks are made on the
pointer it is passed. In addition, the data in the malloc block
beyound the size requested on the initial malloc is checked to
verify that it is still filled with the original fill characters.
This is usefull for catching things like:
ptr = malloc(5);
ptr[5] = '\0';
/*
* You should not that this will be caught when it is
* freed not when it is done
*/
And finally, the freed block is filled with a different fill pattern
so that you can easily determine if you are still using free'd space.
The fill pattern for free'd areas is 0x02.
This is usefull for catching things like:
ptr = malloc(20);
bptr = ptr+10;
/* do something usefule with bptr */
free(ptr);
/*
* now try to do something useful with bptr, it should
* be trashed enough that it would cause real problems
* and when you went to debug the problem it would be
* filled with 0x02's and you would then know to look
* for something free'ing what bptr points to.
*/
3. Whenever a bstring(3)/string(3)/memory(3) function is called, it's
parameters are checked as follows:
If they point somewhere in the malloc arena
If the operation goes beyond requested malloc space
call malloc_warning()
This is usefull for catching things like:
ptr = malloc(5);
strcpy(ptr,"abcde");
4. Malloc_warning() and malloc_fatal() are used when an error condition
is detected. If the error is severe, malloc_fatal is called.
Malloc_warning is used otherwise. The decision about what is fatal
and what is a warning was made somewhat arbitrarily.
Warning messages include:
Calling free with a bad pointer
Calling a bstring/string/memory (3) function which will go beyond
the end of a malloc block (Note that the library function is
not modified to refuse the operation. If malloc warnings are
in the default IGNORE case, the operation will continue and
at some point cause a real problem).
Fatal errors are:
Detectable corruption to the malloc chain.
5. The operations to perform when an error is detected are specified at
run time by the use of environment variables.
MALLOC_WARN - specifies the warning error message handling
MALLOC_FATAL - specifies the fatal error handling
When one of these error conditions occur you will get an error
message and the handler will execute based upon what setting
is in the environment variables. Currently understood settings
are as follows:
0 - continue operations
1 - drop core and exit
2 - just exit
3 - drop core, but continue executing. Core files will
be placed into core.[PID].[counter] i.e: core.00123.001
128 - dump malloc chain and continue
129 - dump malloc chain, dump core, and exit
130 - dump malloc chain, exit
131 - dump malloc chain, dump core, continue processing
There is an additional environment variable MALLOC_ERRFILE which
is used to indicate the name of the file for error message output.
For example, to set up the session to generate a core file for
every malloc warning, to drop core and exit on a malloc fatal, and
to log all messages to the file "malloc_log" do the following:
MALLOC_WARN=131
MALLOC_FATAL=1
MALLOC_ERRFILE=malloc_log
export MALLOC_WARN MALLOC_FATAL MALLOC_ERRFILE
6. The function malloc_dump() is available to dump the malloc chain whenever
you might want. It's only argument is a file descriptor to use to write
the data. Review the code if you need to know what data is printed.
SHAR_EOF
cat << \SHAR_EOF > calloc.c
#include <stdio.h>
char *
calloc(nelem,elsize)
unsigned int nelem;
unsigned int elsize;
{
char * malloc();
char * ptr;
unsigned int size;
size = elsize * nelem;
if( (ptr = malloc(size)) != NULL)
{
memset(ptr,'\0',size);
}
return(ptr);
}
SHAR_EOF
cat << \SHAR_EOF > debug.h
/* static char SCCSID[] = "%W% %E%"; */
/************************************************************************/
/* */
/* this include sets up some macro functions which can be used while */
/* debugging the program, and then left in the code, but turned of by */
/* just not defining "DEBUG". This way your production version of */
/* the program will not be filled with bunches of debugging junk */
/* */
/************************************************************************/
#ifdef DEBUG
#if DEBUG == 1 /* if default level */
#undef DEBUG
#define DEBUG 100 /* use level 100 */
#endif
#include <stdio.h>
#define DEBUG0(val,str)\
{\
if( DEBUG > val ) \
fprintf(stderr,"%s(%d): %s\n",\
__FILE__,__LINE__,str);\
}
#define DEBUG1(val,str,a1)\
{\
char _debugbuf[100];\
if( DEBUG > val )\
{\
sprintf(_debugbuf,str,a1);\
fprintf(stderr,"%s(%d): %s\n",\
__FILE__,__LINE__,_debugbuf);\
}\
}
#define DEBUG2(val,str,a1,a2)\
{\
char _debugbuf[100];\
if( DEBUG > val )\
{\
sprintf(_debugbuf,str,a1,a2);\
fprintf(stderr,"%s(%d): %s\n",\
__FILE__,__LINE__,_debugbuf);\
}\
}
#define DEBUG3(val,str,a1,a2,a3)\
{\
char _debugbuf[100];\
if( DEBUG > val )\
{\
sprintf(_debugbuf,str,a1,a2,a3);\
fprintf(stderr,"%s(%d): %s\n",\
__FILE__,__LINE__,_debugbuf);\
}\
}
#define DEBUG4(val,str,a1,a2,a3,a4)\
{\
char _debugbuf[100];\
if( DEBUG > val )\
{\
sprintf(_debugbuf,str,a1,a2,a3,a4);\
fprintf(stderr,"%s(%d): %s\n",\
__FILE__,__LINE__,_debugbuf);\
}\
}
#define DEBUG5(val,str,a1,a2,a3,a4,a5)\
{\
char _debugbuf[100];\
if( DEBUG > val )\
{\
sprintf(_debugbuf,str,a1,a2,a3,a4,a5);\
fprintf(stderr,"%s(%d): %s\n",\
__FILE__,__LINE__,_debugbuf);\
}\
}
#else
#define DEBUG0(val,s)
#define DEBUG1(val,s,a1)
#define DEBUG2(val,s,a1,a2)
#define DEBUG3(val,s,a1,a2,a3)
#define DEBUG4(val,s,a1,a2,a3,a4)
#define DEBUG5(val,s,a1,a2,a3,a4,a5)
#endif /* DEBUG */
SHAR_EOF
cat << \SHAR_EOF > design
This malloc library will emulate the standard malloc libraries but in
addition it will include special versions of the following routines which
perform checking of the arguments passed to verify that they do not
extend outside of a malloced area.
These modified routines include:
bcopy, bzero, bcmp
memcpy, memset, memcmp, memccpy, memchr
strcpy, strncpy, strcat, strncat, strdup, strcmp, strncmp,
strchr, strrchr, strpbrk, strspn, strcspn, strtok
These functions will only be different from the standard functions in
that they will call routines in the malloc library to verify that the
data accessed by these routines does not overflow a malloc block.
If an error is detected, the default action is to display a warning
and continue with the function. In other words, it should match
the functionality of the library function with the exception that
the error message is printed.
SHAR_EOF
cat << \SHAR_EOF > dump.c
#include <stdio.h>
#include "malloc.h"
#include "toascii.h"
/*
* Function: malloc_dump()
*
* Purpose: to dump a printed copy of the malloc chain and
* associated data elements
*
* Arguments: fd - file descriptor to write data to
*
* Returns: nothing of any use
*
* Narrative: Just print out all the junk
*
* Notes: This function is implemented using low level calls because
* of the likelyhood that the malloc tree is damaged when it
* is called. (Lots of things in the c library use malloc and
* we don't want to get into a catch-22).
*
* Mod History:
* 90/01/24 cpcahil Initial revision.
*/
#define ERRSTR "I/O Error on malloc dump file descriptor\n"
#define WRITEOUT(fd,str,len) if( write(fd,str,len) != len ) \
{ \
(void) write(2,ERRSTR,strlen(ERRSTR));\
exit(120); \
}
malloc_dump(fd)
FILE * fd;
{
char buffer[512];
int i;
extern char * malloc_data_end;
extern char * malloc_data_start;
extern struct mlist * malloc_end;
extern struct mlist malloc_start;
struct mlist * ptr;
WRITEOUT(fd,"MALLOC CHAIN:\n",14);
WRITEOUT(fd,"-------------------- START ----------------\n",44);
for(i=0; i < 80; i++)
{
buffer[i] = ' ';
}
for(ptr = &malloc_start; ptr; ptr = ptr->next)
{
(void) toascii(buffer, ptr, 8, B_HEX, '0');
(void) toascii(buffer+9, ptr->next, 8, B_HEX, '0');
(void) toascii(buffer+18,ptr->prev, 8, B_HEX, '0');
(void) toascii(buffer+27,ptr->flag, 10, B_HEX, '0');
(void) toascii(buffer+38,ptr->s.size, 8, B_DEC, ' ');
(void) toascii(buffer+47,ptr->s.size, 8, B_HEX, '0');
(void) toascii(buffer+57,ptr->data, 8, B_HEX, '0');
buffer[46] = '(';
buffer[55] = ')';
buffer[65] = '\n';
WRITEOUT(fd,buffer,66);
}
WRITEOUT(fd,"-------------------- DONE -----------------\n",44);
WRITEOUT(fd,"Malloc start: ",19);
(void) toascii(buffer, &malloc_start, 8, B_HEX, '0');
buffer[8] = '\n';
WRITEOUT(fd,buffer,9);
WRITEOUT(fd,"Malloc end: ", 19);
(void) toascii(buffer, malloc_end, 8, B_HEX, '0');
buffer[8] = '\n';
WRITEOUT(fd,buffer,9);
WRITEOUT(fd,"Malloc data start: ", 19);
(void) toascii(buffer, malloc_data_start, 8, B_HEX, '0');
buffer[8] = '\n';
WRITEOUT(fd,buffer,9);
WRITEOUT(fd,"Malloc data end: ", 19);
(void) toascii(buffer, malloc_data_end, 8, B_HEX, '0');
buffer[8] = '\n';
WRITEOUT(fd,buffer,9);
} /* malloc_dump(... */
SHAR_EOF
cat << \SHAR_EOF > free.c
#include <stdio.h>
#include "malloc.h"
#include "debug.h"
void
free(cptr)
char * cptr;
{
int i;
extern struct mlist * malloc_end;
extern char * malloc_data_end;
extern char * malloc_data_start;
struct mlist * oldptr;
struct mlist * ptr;
/*
* First verify that cptr is within the malloc region...
*/
if( cptr < malloc_data_start || cptr > malloc_data_end )
{
malloc_warning("Free called with invalid address...");
return;
}
/*
* convert pointer to mlist struct pointer. To do this we must
* move the pointer backwards the correct number of bytes...
*/
ptr = (struct mlist *) (cptr - M_SIZE);
if( (ptr->flag != (M_MAGIC|M_INUSE)) ||
(ptr->prev && (ptr->prev->next != ptr) ) ||
(ptr->next && (ptr->next->prev != ptr) ) ||
((ptr->next == NULL) && (ptr->prev == NULL)) )
{
malloc_warning(
"Free: called with invalid pointer or corrupted chain");
return;
}
ptr->flag &= ~M_INUSE;
/*
* verify that the user did not overrun the requested number of bytes.
*/
for(i=ptr->r_size; i < ptr->s.size; i++)
{
if( ptr->data[i] != M_FILL )
{
malloc_warning( "data overrun in malloced region" );
break;
}
}
DEBUG3(10,"pointers: prev: 0x%.7x, ptr: 0x%.7x, next: 0x%.7x",
ptr->prev, ptr, ptr->next);
DEBUG3(10,"size: prev: %9d, ptr: %9d, next: %9d",
ptr->prev->s.size, ptr->s.size, ptr->next->s.size);
DEBUG3(10,"flags: prev: 0x%.7x, ptr: 0x%.7x, next: 0x%.7x",
ptr->prev->flag, ptr->flag, ptr->next->flag);
/*
* check to see if this block can be combined with the next and/or
* previous block. Since it may be joined with the previous block
* we will save a pointer to the previous block and test to verify
* if it is joined (it's next ptr will no longer point to ptr).
*/
malloc_join(ptr,ptr->next,0,0);
oldptr = ptr->prev;
malloc_join(ptr->prev, ptr,0,0);
if( oldptr->next != ptr )
{
DEBUG0(10,"Oldptr was changed");
ptr = oldptr;
}
/*
* fill this block with '\02's to ensure that nobody is using a
* pointer to already freed data...
*/
malloc_memset(ptr->data,M_FREE_FILL,ptr->s.size);
}
SHAR_EOF
cat << \SHAR_EOF > func.hdr
/*
* Function: malloc_in_arena()
*
* Purpose: to verify address is within malloc arena.
*
* Arguments: ptr - pointer to verify
*
* Returns: TRUE - if pointer is within malloc area
* FALSE - otherwise
*
* Narrative:
* IF pointer is >= malloc area start AND <= malloc area end
* return TRUE
* ELSE
* return FALSE
*
* Mod History:
* 90/01/24 cpcahil Initial revision.
*/
SHAR_EOF
cat << \SHAR_EOF > malloc.c
#include <stdio.h>
#include <fcntl.h>
#include "malloc.h"
#include "toascii.h"
char * malloc_data_start;
char * malloc_data_end;
struct mlist * malloc_end;
int malloc_errfd = 2;
int malloc_fatal_level = M_HANDLE_CORE;
struct mlist malloc_start;
int malloc_warn_level;
char * malloc(size)
unsigned int size;
{
char * cptr;
char * getenv();
int i;
void malloc_split();
unsigned int need;
struct mlist * oldptr;
struct mlist * ptr;
unsigned int rest;
char * sbrk();
struct mlist * tptr;
/*
* If this is the first call to malloc...
*/
if( malloc_data_start == (char *) 0 )
{
malloc_data_start = sbrk(0);
malloc_data_end = malloc_data_start;
malloc_start.s.size = 0;
malloc_end = &malloc_start;
if( (cptr=getenv("MALLOC_WARN")) != NULL )
{
malloc_warn_level = atoi(cptr);
}
if( (cptr=getenv("MALLOC_FATAL")) != NULL)
{
malloc_fatal_level = atoi(cptr);
}
if( (cptr=getenv("MALLOC_ERRFILE")) != NULL)
{
i = open(cptr,O_CREAT|O_TRUNC|O_WRONLY,0666);
if( i != -1)
{
malloc_errfd = i;
}
}
}
/*
* if they ask for zero bytes, give em at least 1...
*/
if( size == 0 )
{
size = 1;
}
/*
* Now look for a free area of memory of size bytes...
*/
oldptr = NULL;
for(ptr = &malloc_start; ; ptr = ptr->next)
{
/*
* Since the malloc chain is a forward only chain, any
* pointer that we get should always be positioned in
* memory following the previous pointer. If this is not
* so, we must have a corrupted chain.
*/
if( ptr )
{
if(ptr < oldptr )
{
malloc_fatal("Corrupted malloc chain.");
}
oldptr = ptr;
}
else if( oldptr != malloc_end )
{
/*
* This should never happen. If it does, then
* we got a real problem.
*/
malloc_fatal("Corrupted malloc chain 2.");
}
/*
* if this element is already in use...
*/
if( ptr && ((ptr->flag & M_INUSE) != 0) )
{
continue;
}
/*
* if there isn't room for this block..
*/
if( ptr && (ptr->s.size < size) )
{
continue;
}
/*
* If ptr is null, we have run out of memory and must sbrk more
*/
if( ptr == NULL )
{
need = (size + M_SIZE) * (size > 100*1024 ? 1:2);
if( need < M_BLOCKSIZE )
{
need = M_BLOCKSIZE;
}
else if( need & (M_BLOCKSIZE-1) )
{
need &= ~(M_BLOCKSIZE-1);
need += M_BLOCKSIZE;
}
ptr = (struct mlist *) sbrk(need);
if( ptr == (struct mlist *) -1 )
{
malloc_fatal("Can't allocate any more memory");
}
malloc_data_end = sbrk(0);
ptr->prev = oldptr;
ptr->next = (struct mlist *) 0;
ptr->s.size = need - M_SIZE;
ptr->flag = M_MAGIC;
oldptr->next = ptr;
malloc_end = ptr;
} /* if( ptr ==... */
/*
* Now ptr points to a memory location that can store
* this data, so lets go to work.
*/
ptr->r_size = size; /* save requested size */
ptr->flag |= M_INUSE;
/*
* split off unneeded data area in this block, if possible...
*/
malloc_split(ptr);
/*
* just to make sure that noone is misusing malloced
* memory without initializing it, lets set it to
* all '\01's. We call local_memset() because memset()
* may be checking for malloc'd ptrs and this isn't
* a malloc'd ptr yet.
*/
malloc_memset(ptr->data,M_FILL,ptr->s.size);
return( ptr->data);
} /* for(... */
} /* malloc(... */
/*
* Function: malloc_split()
*
* Purpose: to split a malloc segment if there is enough room at the
* end of the segment that isn't being used
*
* Arguments: ptr - pointer to segment to split
*
* Returns: nothing of any use.
*
* Narrative:
*
* Mod History:
* 90/01/27 cpcahil Initial revision.
*/
void
malloc_split(ptr)
struct mlist * ptr;
{
extern struct mlist * malloc_end;
int rest;
int size;
struct mlist * tptr;
void malloc_join();
size = ptr->r_size;
/*
* roundup size to the appropriate boundry
*/
M_ROUNDUP(size);
/*
* figure out how much room is left in the array.
* if there is enough room, create a new mlist
* structure there.
*/
if( ptr->s.size > size )
{
rest = ptr->s.size - size;
}
else
{
rest = 0;
}
if( rest > (M_SIZE+M_RND) )
{
tptr = (struct mlist *) (ptr->data+size);
tptr->prev = ptr;
tptr->next = ptr->next;
tptr->flag = M_MAGIC;
tptr->s.size = rest - M_SIZE;
/*
* If possible, join this segment with the next one
*/
malloc_join(tptr, tptr->next,0,0);
if( tptr->next )
{
tptr->next->prev = tptr;
}
malloc_memset(tptr->data,M_FREE_FILL, tptr->s.size);
ptr->next = tptr;
ptr->s.size = size;
if( malloc_end == ptr )
{
malloc_end = tptr;
}
}
} /* malloc_split(... */
/*
* Function: malloc_join()
*
* Purpose: to join two malloc segments together (if possible)
*
* Arguments: ptr - pointer to segment to join to.
* nextptr - pointer to next segment to join to ptr.
*
* Returns: nothing of any values.
*
* Narrative:
*
* Mod History:
* 90/01/27 cpcahil Initial revision.
*/
void
malloc_join(ptr,nextptr, inuse_override, fill_flag)
struct mlist * ptr;
struct mlist * nextptr;
int inuse_override;
int fill_flag;
{
unsigned int newsize;
if( ptr && ! (inuse_override || (ptr->flag & M_INUSE)) &&
nextptr && ! (nextptr->flag & M_INUSE) &&
((ptr->data+ptr->s.size) == (char *) nextptr) )
{
if( malloc_end == nextptr )
{
malloc_end = ptr;
}
ptr->next = nextptr->next;
newsize = nextptr->s.size + M_SIZE;
/*
* if we are to fill and this segment is in use,
* fill in with M_FILL newly added space...
*/
if(fill_flag && (ptr->flag & M_INUSE) )
{
malloc_memset(ptr->data+ptr->s.size,
M_FILL, nextptr->s.size + M_SIZE);
}
ptr->s.size += newsize;
if( ptr->next )
{
ptr->next->prev = ptr;
}
}
} /* malloc_join(... */
/*
* The following mess is just to ensure that the versions of these functions in
* the current library are included (to make sure that we don't accidentaly get
* the libc versions. (This is the lazy man's -u ld directive)
*/
int free();
int strcmp();
int memcmp();
char * realloc();
int (*malloc_int_funcs[])() =
{
free,
strcmp,
memcmp,
};
char * (*malloc_char_star_funcs[])() =
{
realloc,
};
/*
* This is malloc's own memset which is used without checking the parameters.
*/
malloc_memset(ptr,byte,len)
char * ptr;
char byte;
int len;
{
while(len-- > 0)
{
*ptr++ = byte;
}
} /* malloc_memset(... */
void
malloc_fatal(str)
char * str;
{
char errbuf[128];
int len;
extern int malloc_fatal_level;
char * s;
char * t;
s = errbuf;
t = "Fatal error: ";
while( *s = *t++)
{
s++;
}
t = str;
while( *s = *t++)
{
s++;
}
*(s++) = '\n';
if( write(malloc_errfd,errbuf,(s-errbuf)) != (s-errbuf))
{
write(2,"I/O error to error file\n",24);
exit(110);
}
malloc_err_handler(malloc_fatal_level);
} /* malloc_fatal(... */
void
malloc_warning(str)
char * str;
{
char errbuf[128];
int len;
extern int malloc_warn_level;
char * s;
char * t;
s = errbuf;
t = "Warning: ";
while( *s = *t++)
{
s++;
}
t = str;
while( *s = *t++)
{
s++;
}
*(s++) = '\n';
if( write(malloc_errfd,errbuf,(s-errbuf)) != (s-errbuf))
{
write(2,"I/O error to error file\n",24);
exit(110);
}
malloc_err_handler(malloc_warn_level);
} /* malloc_warning(... */
malloc_err_handler(level)
{
if( malloc_warn_level & M_HANDLE_DUMP )
{
malloc_dump(malloc_errfd);
}
switch( malloc_warn_level & ~M_HANDLE_DUMP )
{
/*
* If we are to drop a core file and exit
*/
case M_HANDLE_ABORT:
abort();
break;
/*
* If we are to exit..
*/
case M_HANDLE_EXIT:
exit(200);
break;
/*
* If we are to dump a core, but keep going on our merry way
*/
case M_HANDLE_CORE:
{
int pid;
int rpid;
/*
* fork so child can abort (and dump core)
*/
if( (pid = fork()) == 0 )
{
write(2,"Child dumping core\n",19);
abort();
}
/*
* wait for child to finish dumping core
*/
while( (rpid=wait((int *)0)) != pid)
{
}
/*
* Move core file to core.pid.cnt so
* multiple cores don't overwrite each
* other.
*/
if( access("core",0) == 0 )
{
static int corecnt;
char filenam[32];
filenam[0] = 'c';
filenam[1] = 'o';
filenam[2] = 'r';
filenam[3] = 'e';
filenam[4] = '.';
(void)toascii(filenam+5,getpid(),
5, B_DEC, '0');
filenam[10] = '.';
(void)toascii(filenam+11,corecnt++,
3, B_DEC, '0');
filenam[14] = '\0';
(void) unlink(filenam);
if( link("core",filenam) == 0)
{
(void) unlink("core");
}
}
}
/*
* If we are to just ignore the error and keep on processing
*/
case M_HANDLE_IGNORE:
break;
} /* switch(... */
} /* malloc_err_handler(... */
SHAR_EOF
cat << \SHAR_EOF > malloc.h
struct mlist
{
struct mlist * next; /* next entry in chain */
struct mlist * prev; /* prev entry in chain */
int flag; /* inuse flag */
unsigned int r_size; /* requested size */
union
{
unsigned int size; /* actual size */
double unused_just_for_alignment;
} s;
char data[4];
};
#define M_SIZE ((int)(char *)((struct mlist *)0)->data)
#define M_RND 0x08
#define M_INUSE 0x01
#define M_MAGIC 0x03156100
#define M_BLOCKSIZE (1024*8)
#define M_FILL '\01'
#define M_FREE_FILL '\02'
#define M_ROUNDUP(size) {\
if( size & (M_RND-1) ) \
{ \
size &= ~(M_RND-1); \
size += M_RND; \
} \
}
/*
* Malloc warning/fatal error handler defines...
*/
#define M_HANDLE_DUMP 0x80 /* 128 */
#define M_HANDLE_IGNORE 0
#define M_HANDLE_ABORT 1
#define M_HANDLE_EXIT 2
#define M_HANDLE_CORE 3
void malloc_warning();
void malloc_fatal();
void malloc_check_data();
void malloc_check_str();
void malloc_verify();
SHAR_EOF
cat << \SHAR_EOF > malloc_chk.c
#include <stdio.h>
#include "malloc.h"
#include "debug.h"
extern struct mlist malloc_start;
extern struct mlist * malloc_end;
extern char * malloc_data_start;
extern char * malloc_data_end;
/*
* Function: malloc_in_arena()
*
* Purpose: to verify address is within malloc arena.
*
* Arguments: ptr - pointer to verify
*
* Returns: TRUE - if pointer is within malloc area
* FALSE - otherwise
*
* Narrative:
* IF pointer is >= malloc area start AND <= malloc area end
* return TRUE
* ELSE
* return FALSE
*
* Mod History:
* 90/01/24 cpcahil Initial revision.
*/
int
malloc_in_arena(ptr)
char * ptr;
{
extern char * malloc_data_start;
extern char * malloc_data_end;
int rtn = 0;
if( ptr >= malloc_data_start && ptr <= malloc_data_end )
{
rtn = 1;
}
return(rtn);
}
/*
* Function: malloc_check_str()
*
* Arguments: func - name of function calling this routine
* str - pointer to area to check
*
* Purpose: to verify that if str is within the malloc arena, the data
* it points to does not extend beyond the applicable region.
*
* Returns: Nothing of any use (function is void).
*
* Narrative:
* IF pointer is within malloc arena
* determin length of string
* call malloc_verify() to verify data is withing applicable region
* return
*
* Mod History:
* 90/01/24 cpcahil Initial revision.
* 90/01/29 cpcahil Added code to ignore recursive calls.
*/
void
malloc_check_str(func,str)
char * func;
char * str;
{
static int layers;
register char * s;
if( (layers++ == 0) && malloc_in_arena(str) )
{
for( s=str; *s; s++)
{
}
malloc_verify(func,str,s-str+1);
}
layers--;
}
/*
* Function: malloc_check_data()
*
* Arguments: func - name of function calling this routine
* ptr - pointer to area to check
* len - length to verify
*
* Purpose: to verify that if ptr is within the malloc arena, the data
* it points to does not extend beyond the applicable region.
*
* Returns: Nothing of any use (function is void).
*
* Narrative:
* IF pointer is within malloc arena
* call malloc_verify() to verify data is withing applicable region
* return
*
* Mod History:
* 90/01/24 cpcahil Initial revision.
* 90/01/29 cpcahil Added code to ignore recursive calls.
*/
void
malloc_check_data(func,ptr,len)
char * func;
char * ptr;
int len;
{
static int layers;
if( layers++ == 0 )
{
DEBUG3(40,"malloc_check_data(%s,0x%x,%d) called...",
func,ptr,len);
if( malloc_in_arena(ptr) )
{
DEBUG0(10,"pointer in malloc arena, verifying...");
malloc_verify(func,ptr,len);
}
}
layers--;
}
/*
* Function: malloc_verify()
*
* Arguments: func - name of function calling the malloc check routines
* ptr - pointer to area to check
* len - length to verify
*
* Purpose: to verify that the data ptr points to does not extend beyond
* the applicable malloc region. This function is only called
* if it has been determined that ptr points into the malloc arena.
*
* Returns: Nothing of any use (function is void).
*
* Narrative:
*
* Mod History:
* 90/01/24 cpcahil Initial revision.
*/
void
malloc_verify(func,ptr,len)
char * func;
char * ptr;
int len;
{
extern struct mlist malloc_start;
extern struct mlist * malloc_end;
struct mlist * mptr;
DEBUG3(40,"malloc_verify(%s,0x%x,%d) called...", func,ptr,len);
/*
* Find the malloc block that includes this pointer
*/
mptr = &malloc_start;
while( mptr &&
! (((char *)mptr < ptr) && ((mptr->data+mptr->s.size) > ptr) ) )
{
mptr = mptr->next;
}
/*
* if ptr was not in a malloc block, it must be part of
* some direct sbrk() stuff, so just return.
*/
if( ! mptr )
{
DEBUG1(10,"ptr (0x%x) not found in malloc search", ptr);
return;
}
/*
* Now we have a valid malloc block that contains the indicated
* pointer. We must verify that it is withing the requested block
* size (as opposed to the real block size which is rounded up to
* allow for correct alignment).
*/
DEBUG4(60,"Checking 0x%x-0x%x, 0x%x-0x%x",
ptr, ptr+len, mptr->data, mptr->data+mptr->r_size);
if( (ptr < mptr->data) || ((ptr+len) > (mptr->data+mptr->r_size)) )
{
char errstr[512];
DEBUG4(0,"pointer not within region 0x%x-0x%x, 0x%x-0x%x",
ptr, ptr+len, mptr->data, mptr->data+mptr->r_size);
sprintf(errstr,"%s %s, %s 0x%x %s '%.2x %.2x %.2x %.2x %.2x'",
"Malloced memory overflow detected in function",
func, "address:", ptr, "Data: ",
*ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4));
malloc_fatal(errstr);
}
return;
}
SHAR_EOF
cat << \SHAR_EOF > memory.c
char *
memccpy(ptr1, ptr2, ch, len)
register char * ptr1;
register char * ptr2;
int len;
int ch;
{
register int i;
char * rtn;
/*
* I know that the assignment could be done in the following, but
* I wanted to perform a check before any assignment, so first I
* determine the length, check the pointers and then do the assignment.
*/
for( i=0; (i < len) && (ptr2[i] != ch); i++)
{
}
malloc_check_data("memccpy", ptr1, i);
malloc_check_data("memccpy", ptr2, i);
/*
* if we found the character...
*/
if( i < len )
{
rtn = ptr1+i+1;
}
else
{
rtn = (char *) 0;
}
while( i-- )
{
*(ptr1++) = *(ptr2++);
}
return(rtn);
}
char *
memchr(ptr1,ch,len)
register char * ptr1;
register int ch;
int len;
{
int i;
for( i=0; (i < len) && (ptr1[i] != ch); i++)
{
}
malloc_check_data("memchr", ptr1, i);
if( i < len )
{
return( ptr1+i );
}
else
{
return( (char *) 0);
}
}
char *
memcpy(ptr1, ptr2, len)
register char * ptr1;
register char * ptr2;
register int len;
{
char * rtn = ptr1;
malloc_check_data("memcpy", ptr1, len);
malloc_check_data("memcpy", ptr2, len);
while( len-- )
{
*(ptr1++) = *(ptr2++);
}
return(rtn);
}
int
memcmp(ptr1, ptr2, len)
register char * ptr1;
register char * ptr2;
register int len;
{
malloc_check_data("memcpy", ptr1, len);
malloc_check_data("memcpy", ptr2, len);
while( --len && (*ptr1 == *ptr2) )
{
ptr1++;
ptr2++;
}
return( *ptr1 - *ptr2 );
}
char *
memset(ptr1, ch, len)
register char * ptr1;
register int ch;
register int len;
{
char * rtn = ptr1;
malloc_check_data("memcpy", ptr1, len);
while( len-- )
{
*(ptr1++) = ch;
}
return(rtn);
}
bcopy(ptr2,ptr1,len)
{
memcpy(ptr1,ptr2,len);
}
bzero(ptr1,len)
{
memset(ptr1,'\0',len);
}
int
bcmp(ptr2, ptr1, len)
{
return( memcmp(ptr1,ptr2,len) );
}
SHAR_EOF
cat << \SHAR_EOF > pgm.c
#include <stdio.h>
main(argc,argv)
int argc;
char * argv[];
{
int i;
char * malloc();
char * ptr[10];
char * realloc();
ptr[0] = malloc(2034);
printf("malloc() returned 0x%x\n", ptr[0]);
ptr[1] = malloc(2034);
printf("malloc() returned 0x%x\n", ptr[1]);
ptr[2] = malloc(14321);
printf("malloc() returned 0x%x\n", ptr[2]);
malloc_dump(2);
getchar();
memset(ptr[1],' ',2034);
ptr[5] = realloc(ptr[1],20300);
/* fprintf(stderr,"value at position 200 after realloc: 0x%x\n", ptr[3][200]);
*/
malloc_dump(2);
getchar();
memset(ptr[2],'\0',14321);
free(ptr[2]);
malloc_dump(2);
getchar();
free(ptr[0]);
malloc_dump(2);
getchar();
ptr[3] = malloc(2034);
printf("malloc() returned 0x%x\n", ptr[3]);
ptr[4] = malloc(234);
printf("malloc() returned 0x%x\n", ptr[4]);
malloc_dump(2);
getchar();
for(i=0; i < 10; i++)
{
free(ptr[i]);
malloc_dump(2);
}
}
SHAR_EOF
cat << \SHAR_EOF > realloc.c
#include <stdio.h>
#include "malloc.h"
char *
realloc(cptr,size)
char * cptr;
unsigned int size;
{
int i;
char * malloc();
extern struct mlist * malloc_end;
extern char * malloc_data_end;
extern char * malloc_data_start;
char * new_cptr;
struct mlist * ptr;
int r_size;
int rest;
struct mlist * tptr;
/*
* First verify that cptr is within the malloc region...
*/
if( cptr < malloc_data_start || cptr > malloc_data_end )
{
malloc_warning("realloc called with invalid address...");
return;
}
/*
* convert pointer to mlist struct pointer. To do this we must
* move the pointer backwards the correct number of bytes...
*/
ptr = (struct mlist *) (cptr - M_SIZE);
if( (ptr->flag != (M_MAGIC|M_INUSE)) ||
(ptr->prev && (ptr->prev->next != ptr) ) ||
(ptr->next && (ptr->next->prev != ptr) ) ||
((ptr->next == NULL) && (ptr->prev == NULL)) )
{
malloc_warning(
"realloc: called with invalid pointer or corrupted chain");
return(NULL);
}
r_size = size;
M_ROUNDUP(size);
if( size > ptr->s.size )
{
malloc_join(ptr,ptr->next,1,1);
}
if( size < ptr->s.size )
{
rest = ptr->s.size - size;
}
else
{
/*
* else we can't combine it, so lets allocate a new chunk,
* copy the data and free the old chunk...
*/
new_cptr = malloc(size);
if( new_cptr == (char *) 0)
{
return(new_cptr);
}
if( r_size < ptr->r_size )
{
i = r_size;
}
else
{
i = ptr->r_size;
}
memcpy(new_cptr,ptr->data,i);
free(cptr);
return(new_cptr);
} /* else... */
/*
* save amount of real data in new segment (this will be used in the
* memset later) and then save requested size of this segment.
*/
if( ptr->r_size < r_size )
{
i = ptr->r_size;
}
else
{
i = r_size;
}
ptr->r_size = r_size;
/*
* split off extra free space at end of this segment, if possible...
*/
malloc_split(ptr);
malloc_memset( ptr->data+i, M_FILL, ptr->s.size - i);
return(ptr->data);
} /* realloc(... */
SHAR_EOF
cat << \SHAR_EOF > string.c
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include "malloc.h"
int malloc_checking = 0;
char *
strcat(str1,str2)
register char * str1;
register char * str2;
{
char * rtn;
int len;
/*
* check pointers agains malloc region. The malloc* functions
* will properly handle the case where a pointer does not
* point into malloc space.
*/
malloc_checking = 1;
len = strlen(str2);
malloc_check_str("strcat", str2);
len += strlen(str1) + 1;
malloc_checking = 0;
malloc_check_data("strcat", str1, len);
rtn = str1;
while( *str1 )
{
str1++;
}
while( (*str1 = *str2) != '\0' )
{
str1++;
str2++;
}
return(rtn);
}
char *
strdup(str1)
register char * str1;
{
char * malloc();
char * rtn;
register char * str2;
malloc_check_str("strdup", str1);
rtn = str2 = malloc(strlen(str1));
while( (*str2 = *str1) != '\0' )
{
str1++;
str2++;
}
return(rtn);
}
char *
strncat(str1,str2,len)
register char * str1;
register char * str2;
register int len;
{
int len1;
int len2;
char * rtn;
malloc_checking = 1;
len2 = strlen(str2) + 1;
len1 = strlen(str1);
malloc_checking = 0;
malloc_check_data("strncat", str2,len2);
if( (len+1) < len2 )
{
len1 += len + 1;
}
else
{
len1 += len2;
}
malloc_check_data("strncat", str1, len1);
rtn = str1;
while( *str1 )
{
str1++;
}
while( len-- && ((*str1++ = *str2++) != '\0') )
{
}
if( ! len )
{
*str1 = '\0';
}
return(rtn);
}
int
strcmp(str1,str2)
register char * str1;
register char * str2;
{
malloc_check_str("strcmp", str1);
malloc_check_str("strcmp", str2);
while( *str1 && (*str1 == *str2) )
{
str1++;
str2++;
}
return( *str1 - *str2 );
}
int
strncmp(str1,str2,len)
register char * str1;
register char * str2;
register int len;
{
malloc_check_str("strncmp", str1);
malloc_check_str("strncmp", str2);
while( --len && *str1 && (*str1 == *str2) )
{
str1++;
str2++;
}
return( *str1 - *str2 );
}
char *
strcpy(str1,str2)
register char * str1;
register char * str2;
{
char * rtn;
int len;
malloc_checking = 1;
len = strlen(str2) + 1;
malloc_checking = 0;
malloc_check_data("strcpy", str1, len);
malloc_check_data("strcpy", str2, len);
rtn = str1;
while( (*str1++ = *str2++) != '\0')
{
}
return(rtn);
}
char *
strncpy(str1,str2,len)
register char * str1;
register char * str2;
register int len;
{
int i;
extern int malloc_checking;
char * rtn;
malloc_check_data("strncpy", str1, len);
malloc_checking = 1;
i = strlen(str2);
malloc_checking = 0;
if( i > len )
{
i = len;
}
malloc_check_data("strncpy", str2, i);
rtn = str1;
while(len-- && (*str1++ = *str2++) != '\0')
{
}
while( len-- )
{
*str1++ = '\0';
}
return(rtn);
}
int
strlen(str1)
register char * str1;
{
register char * s;
if(! malloc_checking )
{
malloc_check_str("strlen", str1);
}
for( s = str1; *s; s++)
{
}
return( s - str1 );
}
char *
strchr(str1,c)
register char * str1;
register int c;
{
malloc_check_str("strchr", str1);
while( *str1 && (*str1 != (char) c) )
{
str1++;
}
if(! *str1 )
{
str1 = (char *) 0;
}
return(str1);
}
char *
strrchr(str1,c)
register char * str1;
register int c;
{
register char * rtn = (char *) 0;
malloc_check_str("strrchr", str1);
while( *str1 )
{
if(*str1 == (char) c )
{
rtn = str1;
}
str1++;
}
return(rtn);
}
char *
index(str1,c)
{
return( strchr(str1,c) );
}
char *
rindex(str1,c)
{
return( strrchr(str1,c) );
}
char *
strpbrk(str1,str2)
register char * str1;
register char * str2;
{
register char * tmp;
malloc_check_str("strpbrk", str1);
malloc_check_str("strpbrk", str2);
while(*str1)
{
for( tmp=str2; *tmp && *tmp != *str1; tmp++)
{
}
if( *tmp )
{
break;
}
str1++;
}
if( ! *str1 )
{
str1 = (char *) 0;
}
return(str1);
}
int
strspn(str1,str2)
register char * str1;
register char * str2;
{
register char * tmp;
char * orig = str1;
malloc_check_str("strspn", str1);
malloc_check_str("strspn", str2);
while(*str1)
{
for( tmp=str2; *tmp && *tmp != *str1; tmp++)
{
}
if(! *tmp )
{
break;
}
str1++;
}
return( (int) (str1 - orig) );
}
int
strcspn(str1,str2)
register char * str1;
register char * str2;
{
register char * tmp;
char * orig = str1;
malloc_check_str("strcspn", str1);
malloc_check_str("strcspn", str2);
while(*str1)
{
for( tmp=str2; *tmp && *tmp != *str1; tmp++)
{
}
if( *tmp )
{
break;
}
str1++;
}
return( (int) (str1 - orig) );
}
/*
* strtok() source taken from that posted to comp.lang.c by Chris Torek
* in Jan 1990.
*/
/*
* Copyright (c) 1989 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
/*
* Get next token from string s (NULL on 2nd, 3rd, etc. calls),
* where tokens are nonempty strings separated by runs of
* chars from delim. Writes NULs into s to end tokens. delim need not
* remain constant from call to call.
*
* Modified by cpc: changed variable names to conform with naming
* conventions used in rest of code. Added malloc pointer
* check calls.
*/
char *
strtok(str1, str2)
char * str1;
char * str2;
{
static char * last;
char * strtoken();
if( str1 )
{
malloc_check_str("strtok", str1);
last = str1;
}
malloc_check_str("strtok", str2);
return (strtoken(&last, str2, 1));
}
/*
* Get next token from string *stringp, where tokens are (possibly empty)
* strings separated by characters from delim. Tokens are separated
* by exactly one delimiter iff the skip parameter is false; otherwise
* they are separated by runs of characters from delim, because we
* skip over any initial `delim' characters.
*
* Writes NULs into the string at *stringp to end tokens.
* delim will usually, but need not, remain constant from call to call.
* On return, *stringp points past the last NUL written (if there might
* be further tokens), or is NULL (if there are definitely no more tokens).
*
* If *stringp is NULL, strtoken returns NULL.
*/
char *
strtoken(stringp, delim, skip)
register char **stringp;
register char *delim;
int skip;
{
register char *s;
register char *spanp;
register int c, sc;
char *tok;
if ((s = *stringp) == NULL)
return (NULL);
if (skip) {
/*
* Skip (span) leading delimiters (s += strspn(s, delim)).
*/
cont:
c = *s;
for (spanp = delim; (sc = *spanp++) != 0;) {
if (c == sc) {
s++;
goto cont;
}
}
if (c == 0) { /* no token found */
*stringp = NULL;
return (NULL);
}
}
/*
* Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
* Note that delim must have one NUL; we stop if we see that, too.
*/
for (tok = s;;) {
c = *s++;
spanp = delim;
do {
if ((sc = *spanp++) == c) {
if (c == 0)
s = NULL;
else
s[-1] = 0;
*stringp = s;
return (tok);
}
} while (sc != 0);
}
/* NOTREACHED */
}
SHAR_EOF
cat << \SHAR_EOF > testmalloc.c
/* NOT copyright by SoftQuad Inc. -- msb, 1988 */
#ifndef lint
static char *SQ_SccsId = "@(#)mtest3.c 1.2 88/08/25";
#endif
#include <stdio.h>
/*
** looptest.c -- intensive allocator tester
**
** Usage: looptest
**
** History:
** 4-Feb-1987 rtech!daveb
*/
# ifdef i386
# define SYS5
# endif
# ifdef SYS5
# define random rand
# else
# include <sys/vadvise.h>
# endif
# include <stdio.h>
# include <signal.h>
# include <setjmp.h>
# define MAXITER 1000000 /* main loop iterations */
# define MAXOBJS 1000 /* objects in pool */
# define BIGOBJ 90000 /* max size of a big object */
# define TINYOBJ 80 /* max size of a small object */
# define BIGMOD 100 /* 1 in BIGMOD is a BIGOBJ */
# define STATMOD 10000 /* interation interval for status */
main( argc, argv )
int argc;
char **argv;
{
register int **objs; /* array of objects */
register int *sizes; /* array of object sizes */
register int n; /* iteration counter */
register int i; /* object index */
register int size; /* object size */
register int r; /* random number */
int objmax; /* max size this iteration */
int cnt; /* number of allocated objects */
int nm = 0; /* number of mallocs */
int nre = 0; /* number of reallocs */
int nal; /* number of allocated objects */
int nfre; /* number of free list objects */
long alm; /* memory in allocated objects */
long frem; /* memory in free list */
long startsize; /* size at loop start */
long endsize; /* size at loop exit */
long maxiter = 0; /* real max # iterations */
extern char end; /* memory before heap */
char *calloc();
char *malloc();
char *sbrk();
long atol();
# ifndef SYS5
/* your milage may vary... */
vadvise( VA_ANOM );
# endif
if (argc > 1)
maxiter = atol (argv[1]);
if (maxiter <= 0)
maxiter = MAXITER;
printf("MAXITER %d MAXOBJS %d ", maxiter, MAXOBJS );
printf("BIGOBJ %d, TINYOBJ %d, nbig/ntiny 1/%d\n",
BIGOBJ, TINYOBJ, BIGMOD );
fflush( stdout );
if( NULL == (objs = (int **)calloc( MAXOBJS, sizeof( *objs ) ) ) )
{
fprintf(stderr, "Can't allocate memory for objs array\n");
exit(1);
}
if( NULL == ( sizes = (int *)calloc( MAXOBJS, sizeof( *sizes ) ) ) )
{
fprintf(stderr, "Can't allocate memory for sizes array\n");
exit(1);
}
/* as per recent discussion on net.lang.c, calloc does not
** necessarily fill in NULL pointers...
*/
for( i = 0; i < MAXOBJS; i++ )
objs[ i ] = NULL;
startsize = sbrk(0) - &end;
printf( "Memory use at start: %d bytes\n", startsize );
fflush(stdout);
printf("Starting the test...\n");
fflush(stdout);
for( n = 0; n < maxiter ; n++ )
{
if( !(n % STATMOD) )
{
printf("%d iterations\n", n);
fflush(stdout);
}
/* determine object of interst and it's size */
r = random();
objmax = ( r % BIGMOD ) ? TINYOBJ : BIGOBJ;
size = r % objmax;
i = r % (MAXOBJS - 1);
/* either replace the object of get a new one */
if( objs[ i ] == NULL )
{
objs[ i ] = (int *)malloc( size );
nm++;
}
else
{
/* don't keep bigger objects around */
if( size > sizes[ i ] )
{
objs[ i ] = (int *)realloc( objs[ i ], size );
nre++;
}
else
{
free( objs[ i ] );
objs[ i ] = (int *)malloc( size );
nm++;
}
}
sizes[ i ] = size;
if( objs[ i ] == NULL )
{
printf("\nCouldn't allocate %d byte object!\n",
size );
break;
}
} /* for() */
printf( "\n" );
cnt = 0;
for( i = 0; i < MAXOBJS; i++ )
if( objs[ i ] )
cnt++;
printf( "Did %d iterations, %d objects, %d mallocs, %d reallocs\n",
n, cnt, nm, nre );
printf( "Memory use at end: %d bytes\n", sbrk(0) - &end );
fflush( stdout );
/* free all the objects */
for( i = 0; i < MAXOBJS; i++ )
if( objs[ i ] != NULL )
free( objs[ i ] );
endsize = sbrk(0) - &end;
printf( "Memory use after free: %d bytes\n", endsize );
fflush( stdout );
if( startsize != endsize )
printf("startsize %d != endsize %d\n", startsize, endsize );
free( objs );
free( sizes );
malloc_dump();
exit( 0 );
}
SHAR_EOF
cat << \SHAR_EOF > testmem.c
#include <stdio.h>
/*
* These tests test the memory functions...
*/
main()
{
char buffer[500];
int exitval = 0;
char * memccpy();
char * memchr();
char * ptr1;
char * ptr2;
fprintf(stdout,"Begining memory(3) tests...\n");
/*
* test memccpy()...
*/
ptr1 = "abcdefghijklmn";
ptr2 = memccpy(buffer,ptr1,'d',3);
if( ptr2 != (char *) 0)
{
fprintf(stdout,"memccpy() failed to use passed length\n");
exitval++;
}
ptr2 = memccpy(buffer,ptr1,'d',4);
if( ptr2 != (buffer+4) )
{
fprintf(stdout,"memccpy() failed to find byte in data\n");
exitval++;
}
/*
* Test memchr()...
*/
ptr1 = "abcdefghijklmn";
ptr2 = memchr(ptr1,'c',10);
if( ptr2 != (ptr1+2) )
{
fprintf(stdout,"memchr() failed to find byte in data\n");
exitval++;
}
ptr2 = memchr(ptr1,'j',10);
if( ptr2 != (ptr1+9) )
{
fprintf(stdout,"memchr() failed to find byte in data\n");
exitval++;
}
ptr2 = memchr(ptr1,'k',10);
if( ptr2 != (char *) 0)
{
fprintf(stdout,"memchr() failed to obey length argument\n");
exitval++;
}
fprintf(stdout,"Memory tests complete!\n");
exit(exitval);
}
SHAR_EOF
cat << \SHAR_EOF > toascii.c
#include "toascii.h"
/*
* Function: toascii()
*
* Purpose: to convert an integer to an ascii display string
*
* Arguments: buf - place to put the
* val - integer to convert
* len - length of output field (0 if just enough to hold data)
* base - base for number conversion (only works for base <= 16)
* fill - fill char when len > # digits
*
* Returns: length of string
*
* Narrative: IF fill character is non-blank
* Determine base
* If base is HEX
* add "0x" to begining of string
* IF base is OCTAL
* add "0" to begining of string
*
* While value is greater than zero
* use val % base as index into xlation str to get cur char
* divide val by base
*
* Determine fill-in length
*
* Fill in fill chars
*
* Copy in number
*
*
* Mod History:
* 90/01/24 cpcahil Initial revision.
*/
#define T_LEN 10
int
toascii(buf,val,len,base,fill)
int base;
char * buf;
char fill;
int len;
int val;
{
char * bufstart = buf;
int i = T_LEN;
char * xbuf = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char tbuf[T_LEN];
/*
* if we are filling with non-blanks, make sure the
* proper start string is added
*/
if( fill != ' ' )
{
switch(base)
{
case B_HEX:
*(buf++) = '0';
*(buf++) = 'x';
if( len )
{
len -= 2;
}
break;
case B_OCTAL:
*(buf++) = fill;
if( len )
{
len--;
}
break;
default:
break;
}
}
while( val > 0 )
{
tbuf[--i] = xbuf[val % base];
val = val / base;
}
if( len )
{
len -= (T_LEN - i);
if( len > 0 )
{
while(len-- > 0)
{
*(buf++) = fill;
}
}
else
{
/*
* string is too long so we must truncate
* off some characters. We do this the easiest
* way by just incrementing i. This means the
* most significant digits are lost.
*/
while( len++ < 0 )
{
i++;
}
}
}
while( i < T_LEN )
{
*(buf++) = tbuf[i++];
}
return( (int) (buf - bufstart) );
} /* toascii(... */
SHAR_EOF
cat << \SHAR_EOF > toascii.h
#define B_BIN 2
#define B_DEC 10
#define B_HEX 16
#define B_OCTAL 8
SHAR_EOF
# End of shell archive
exit 0
--
+-----------------------------------------------------------------------+
| Conor P. Cahill uunet!virtech!cpcahil 703-430-9247 !
| Virtual Technologies Inc., P. O. Box 876, Sterling, VA 22170 |
+-----------------------------------------------------------------------+
More information about the Alt.sources
mailing list