v22i112: Debugging malloc() library, Part01/02

Rich Salz rsalz at bbn.com
Sat Jul 14 03:49:32 AEST 1990


Submitted-by: "Conor P. Cahill" <virtech!cpcahil at uunet.uu.net>
Posting-number: Volume 22, Issue 112
Archive-name: debug_malloc/part01

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.

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 include:
 1. The malloced area returned from each call to malloc is filled with
    non-null bytes.
 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.
    And finally, the freed block is filled with a different fill pattern
 3. Whenever a bstring(3)/string(3)/memory(3) function is called, it's 
    parameters are checked.
 4. The operations to perform when an error is detected are specified at
    run time by the use of environment variables.

  This code is already at patchlevel 1.

Conor.

Submitted-by: cpcahil at virtech
Archive-name: Malloclib/part01

#!/bin/sh
# This is Malloclib, a shell archive (shar 3.21)
# made 06/21/1990 14:37 UTC by cpcahil at virtech
# Source directory /usr/local/src/lib/malloclib
#
# existing files will NOT be overwritten
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#   1138 -r--r--r-- Makefile
#   4758 -rw-rw-r-- README
#      2 -rw-rw-rw- patchlevel
#   1481 -r--r--r-- calloc.c
#   2628 -r--r--r-- debug.h
#   3097 -r--r--r-- dump.c
#   4379 -r--r--r-- free.c
#   1751 -r--r--r-- m_init.c
#   1776 -r--r--r-- m_perror.c
#   6694 -r--r--r-- malloc.3
#  12756 -r--r--r-- malloc.c
#   2346 -r--r--r-- malloc.h
#   5125 -r--r--r-- malloc_chk.c
#   3449 -r--r--r-- malloc_chn.c
#   2128 -r--r--r-- mallopt.c
#   2817 -r--r--r-- memory.c
#   4496 -r--r--r-- realloc.c
#   8521 -r--r--r-- string.c
#   3971 -r--r--r-- testmalloc.c
#   2552 -r--r--r-- testmem.c
#   2716 -r--r--r-- tostring.c
#    491 -r--r--r-- tostring.h
#
if touch 2>&1 | fgrep '[-amc]' > /dev/null
 then TOUCH=touch
 else TOUCH=true
fi
# ============= Makefile ==============
if test X"$1" != X"-c" -a -f 'Makefile'; then
	echo "File already exists: skipping 'Makefile'"
else
echo "x - extracting Makefile (Text)"
sed 's/^X//' << 'SHAR_EOF' > Makefile &&
X#
X# (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).  
X# You may copy, distribute, and use this software as long as this
X# copyright statement is not removed.
X#
X#
X# This is the Makefile for the malloc debugging library
X#
X# $Id: Makefile,v 1.3 90/06/21 10:37:06 cpcahil Exp $
X#
XCC=cc
X# for System V systems use this CFLAGS
XCFLAGS=-g -DSYS5
X# else for BSD use:
X#CFLAGS=-g
XSHARCMD=shar -o mallocshar -l50 -x -a -n Malloclib
X
XLIB=libmalloc.a
X
XOBJS=	malloc.o	\
X	free.o		\
X	realloc.o	\
X	calloc.o	\
X	string.o	\
X	malloc_chk.o	\
X	malloc_chn.o	\
X	memory.o	\
X	tostring.o	\
X	m_perror.o	\
X	m_init.o	\
X	mallopt.o	\
X	dump.o
X
XTESTS=testmalloc testmem
X
Xall:	$(LIB) $(TESTS)
X
Xclean:  
X	rm -f $(TESTS) pgm $(LIB) *.o *.ln
X
Xsharfile:
X	$(SHARCMD) Makefile README patchlevel *.[ch3] 
X	
X$(LIB): $(OBJS)
X	ar -ru $(LIB) $(OBJS)
X	-if test -s /bin/ranlib; then /bin/ranlib $(LIB); else exit 0; fi
X	-if test -s /usr/bin/ranlib; then /usr/bin/ranlib $(LIB); else exit 0; fi
X
Xtestmalloc:	$(LIB) testmalloc.o
X	$(CC) -o $@ testmalloc.o $(LIB)
X
Xtestmem:	$(LIB) testmem.o
X	$(CC) -o $@ testmem.o $(LIB)
X
X$(OBJS):	malloc.h
X
Xtostring.o malloc.o dump.o:	tostring.h
SHAR_EOF
$TOUCH -am 0621103790 Makefile &&
chmod 0444 Makefile ||
echo "restore of Makefile failed"
set `wc -c Makefile`;Wc_c=$1
if test "$Wc_c" != "1138"; then
	echo original size 1138, current size $Wc_c
fi
fi
# ============= README ==============
if test X"$1" != X"-c" -a -f 'README'; then
	echo "File already exists: skipping 'README'"
else
echo "x - extracting README (Text)"
sed 's/^X//' << 'SHAR_EOF' > README &&
X# (c) Copyright 1990 Conor P. Cahill. (uunet!virtech!cpcahil) 
X# You may copy, distribute, and use this software as long as this
X# copyright statement is not removed.
X
XThis package is a collection of routines which are a drop-in replacement
Xfor the malloc(3), memory(3), string(3), and bstring(3) library functions.
X
XThe purpose of these programs is to aid the development and/or debugging
Xof programs using these functions by providing a high level of consistancy
Xchecking whenever a malloc pointer is used.  Due to this increased 
Xlevel of consistancy checking, these functions have a considerably larger
Xoverhead than the standard functions, but the extra checking should be
Xwell worth it in a development environment.
X
XTo use these functions all you need to do is compile the library and
Xinclude it on your loader command line.  You do not need to recompile
Xyour code, only a relink is necessary.  
X
XFeatures of this library:
X
X 1. The malloced area returned from each call to malloc is filled with
X    non-null bytes.  This should catch any use of uninitialized malloc
X    area.  The fill pattern for malloced area is 0x01.
X
X 2. When free is called numerous validity checks are made on the 
X    pointer it is passed.  In addition, the data in the malloc block
X    beyound the size requested on the initial malloc is checked to 
X    verify that it is still filled with the original fill characters.
X
X	This is usefull for catching things like:
X
X		ptr = malloc(5);
X		ptr[5] = '\0';
X
X		/*
X		 * You should not that this will be caught when it is
X		 * freed not when it is done
X		 */
X
X    And finally, the freed block is filled with a different fill pattern
X    so that you can easily determine if you are still using free'd space.
X    The fill pattern for free'd areas is 0x02.
X
X	This is usefull for catching things like:
X
X		ptr = malloc(20);
X
X		bptr = ptr+10;
X
X		/* do something usefule with bptr */
X
X		free(ptr);
X
X		/* 
X		 * now try to do something useful with bptr, it should
X		 * be trashed enough that it would cause real problems
X		 * and when you went to debug the problem it would be
X		 * filled with 0x02's and you would then know to look 
X		 * for something free'ing what bptr points to.
X		 */
X		
X
X 3. Whenever a bstring(3)/string(3)/memory(3) function is called, it's 
X    parameters are checked as follows:
X
X	If they point somewhere in the malloc arena
X		If the operation goes beyond requested malloc space
X			call malloc_warning()
X
X	This is usefull for catching things like:
X
X		ptr = malloc(5);
X		strcpy(ptr,"abcde");
X			
X	
X 4. Malloc_warning() and malloc_fatal() are used when an error condition
X    is detected.  If the error is severe, malloc_fatal is called.  
X    Malloc_warning is used otherwise.  The decision about what is fatal
X    and what is a warning was made somewhat arbitrarily.
X
X    Warning messages include:
X
X	Calling free with a bad pointer
X        Calling a bstring/string/memory (3) function which will go beyond
X	    the end of a malloc block (Note that the library function is
X            not modified to refuse the operation.  If malloc warnings are
X	    in the default IGNORE case, the operation will continue and 
X	    at some point cause a real problem).
X
X    Fatal errors are:
X
X	Detectable corruption to the malloc chain.
X	
X
X 5. The operations to perform when an error is detected are specified at
X    run time by the use of environment variables.
X
X	MALLOC_WARN - specifies the warning error message handling
X	MALLOC_FATAL - specifies the fatal error handling
X
X
X	When one of these error conditions occur you will get an error
X	message and the handler will execute based upon what setting
X	is in the environment variables.  Currently understood settings
X	are as follows:
X
X		  0 - continue operations
X		  1 - drop core and exit
X		  2 - just exit
X		  3 - drop core, but continue executing.  Core files will
X	 		be placed into core.[PID].[counter] i.e: core.00123.001
X		128 - dump malloc chain and continue
X		129 - dump malloc chain, dump core, and exit
X		130 - dump malloc chain, exit
X		131 - dump malloc chain, dump core, continue processing
X		
X
X	There is an additional environment variable MALLOC_ERRFILE which
X	is used to indicate the name of the file for error message output.
X
X	For example, to set up the session to generate a core file for
X	every malloc warning, to drop core and exit on a malloc fatal, and 
X	to log all messages to the file "malloc_log" do the following:
X
X		MALLOC_WARN=131
X		MALLOC_FATAL=1
X		MALLOC_ERRFILE=malloc_log
X
X		export MALLOC_WARN MALLOC_FATAL MALLOC_ERRFILE
X
X 6. The function malloc_dump() is available to dump the malloc chain whenever
X    you might want.  It's only argument is a file descriptor to use to write
X    the data.  Review the code if you need to know what data is printed.
SHAR_EOF
$TOUCH -am 0511001190 README &&
chmod 0664 README ||
echo "restore of README failed"
set `wc -c README`;Wc_c=$1
if test "$Wc_c" != "4758"; then
	echo original size 4758, current size $Wc_c
fi
fi
# ============= patchlevel ==============
if test X"$1" != X"-c" -a -f 'patchlevel'; then
	echo "File already exists: skipping 'patchlevel'"
else
echo "x - extracting patchlevel (Text)"
sed 's/^X//' << 'SHAR_EOF' > patchlevel &&
X1
SHAR_EOF
$TOUCH -am 0621103390 patchlevel &&
chmod 0666 patchlevel ||
echo "restore of patchlevel failed"
set `wc -c patchlevel`;Wc_c=$1
if test "$Wc_c" != "2"; then
	echo original size 2, current size $Wc_c
fi
fi
# ============= calloc.c ==============
if test X"$1" != X"-c" -a -f 'calloc.c'; then
	echo "File already exists: skipping 'calloc.c'"
else
echo "x - extracting calloc.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > calloc.c &&
X/*
X * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).  
X * You may copy, distribute, and use this software as long as this
X * copyright statement is not removed.
X */
X#include <stdio.h>
X
X/*
X * Function:	calloc()
X *
X * Purpose:	to allocate and nullify a data area
X *
X * Arguments:	nelem	- number of elements
X *		elsize	- size of each element
X *
X * Returns:	NULL	- if malloc fails
X *		or pointer to allocated space
X *
X * Narrative:	determine size of area to malloc
X *		malloc area.
X *		if malloc succeeds
X *		    fill area with nulls
X *		return ptr to malloc'd region
X */
X#ifndef lint
Xstatic char rcs_header[] = "$Id: calloc.c,v 1.6 90/05/11 00:13:07 cpcahil Exp $";
X#endif
X
Xchar *
Xcalloc(nelem,elsize)
X	unsigned int 	  nelem;
X	unsigned int 	  elsize;
X{
X	char		* malloc();
X	char		* memset();
X	char		* ptr;
X	unsigned int	  size;
X
X	size = elsize * nelem;
X
X	if( (ptr = malloc(size)) != NULL)
X	{
X		(void) memset(ptr,'\0',(int)size);
X	}
X
X	return(ptr);
X}
X
X
X/*
X * $Log:	calloc.c,v $
X * Revision 1.6  90/05/11  00:13:07  cpcahil
X * added copyright statment
X * 
X * Revision 1.5  90/02/24  20:41:57  cpcahil
X * lint changes.
X * 
X * Revision 1.4  90/02/24  17:25:47  cpcahil
X * changed $header to $id so full path isn't included.
X * 
X * Revision 1.3  90/02/24  13:32:24  cpcahil
X * added function header.  moved log to end of file.
X * 
X * Revision 1.2  90/02/22  23:08:26  cpcahil
X * fixed rcs_header line
X * 
X * Revision 1.1  90/02/22  23:07:38  cpcahil
X * Initial revision
X * 
X */
SHAR_EOF
$TOUCH -am 0511001490 calloc.c &&
chmod 0444 calloc.c ||
echo "restore of calloc.c failed"
set `wc -c calloc.c`;Wc_c=$1
if test "$Wc_c" != "1481"; then
	echo original size 1481, current size $Wc_c
fi
fi
# ============= debug.h ==============
if test X"$1" != X"-c" -a -f 'debug.h'; then
	echo "File already exists: skipping 'debug.h'"
else
echo "x - extracting debug.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > debug.h &&
X/*
X * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).  
X * You may copy, distribute, and use this software as long as this
X * copyright statement is not removed.
X */
X/************************************************************************/
X/*									*/
X/* this include sets up some macro functions which can be used while	*/
X/* debugging the program, and then left in the code, but turned of by	*/
X/* just not defining "DEBUG".  This way your production version of 	*/
X/* the program will not be filled with bunches of debugging junk	*/
X/*									*/
X/************************************************************************/
X/*
X * $Id: debug.h,v 1.2 90/05/11 00:13:08 cpcahil Exp $
X */
X
X#ifdef DEBUG
X
X#if DEBUG == 1			/* if default level			*/
X#undef DEBUG
X#define DEBUG	100		/*   use level 100			*/
X#endif
X
X#include <stdio.h>
X
X#define DEBUG0(val,str)\
X				{\
X				  if( DEBUG > val ) \
X				    fprintf(stderr,"%s(%d): %s\n",\
X						__FILE__,__LINE__,str);\
X				}
X#define DEBUG1(val,str,a1)\
X			        {\
X				  char _debugbuf[100];\
X				  if( DEBUG > val )\
X				   {\
X				    sprintf(_debugbuf,str,a1);\
X				    fprintf(stderr,"%s(%d): %s\n",\
X						__FILE__,__LINE__,_debugbuf);\
X				   }\
X		       		}
X
X#define DEBUG2(val,str,a1,a2)\
X			        {\
X				 char _debugbuf[100];\
X				  if( DEBUG > val )\
X				   {\
X				    sprintf(_debugbuf,str,a1,a2);\
X				    fprintf(stderr,"%s(%d): %s\n",\
X						__FILE__,__LINE__,_debugbuf);\
X				   }\
X		       		}
X
X#define DEBUG3(val,str,a1,a2,a3)\
X			        {\
X				  char _debugbuf[100];\
X				  if( DEBUG > val )\
X				   {\
X				    sprintf(_debugbuf,str,a1,a2,a3);\
X				    fprintf(stderr,"%s(%d): %s\n",\
X						__FILE__,__LINE__,_debugbuf);\
X				   }\
X		       		}
X
X#define DEBUG4(val,str,a1,a2,a3,a4)\
X			         {\
X				  char _debugbuf[100];\
X				  if( DEBUG > val )\
X				   {\
X				    sprintf(_debugbuf,str,a1,a2,a3,a4);\
X				    fprintf(stderr,"%s(%d): %s\n",\
X						__FILE__,__LINE__,_debugbuf);\
X				   }\
X		       		}
X
X#define DEBUG5(val,str,a1,a2,a3,a4,a5)\
X			         {\
X				  char _debugbuf[100];\
X				  if( DEBUG > val )\
X				   {\
X				    sprintf(_debugbuf,str,a1,a2,a3,a4,a5);\
X				    fprintf(stderr,"%s(%d): %s\n",\
X						__FILE__,__LINE__,_debugbuf);\
X				   }\
X		       		}
X
X#else
X
X#define DEBUG0(val,s)
X#define DEBUG1(val,s,a1)
X#define DEBUG2(val,s,a1,a2)
X#define DEBUG3(val,s,a1,a2,a3)
X#define DEBUG4(val,s,a1,a2,a3,a4)
X#define DEBUG5(val,s,a1,a2,a3,a4,a5)
X
X#endif /* DEBUG */
X
X
X/*
X * $Log:	debug.h,v $
X * Revision 1.2  90/05/11  00:13:08  cpcahil
X * added copyright statment
X * 
X * Revision 1.1  90/02/23  07:09:01  cpcahil
X * Initial revision
X * 
X */
SHAR_EOF
$TOUCH -am 0511001490 debug.h &&
chmod 0444 debug.h ||
echo "restore of debug.h failed"
set `wc -c debug.h`;Wc_c=$1
if test "$Wc_c" != "2628"; then
	echo original size 2628, current size $Wc_c
fi
fi
# ============= dump.c ==============
if test X"$1" != X"-c" -a -f 'dump.c'; then
	echo "File already exists: skipping 'dump.c'"
else
echo "x - extracting dump.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > dump.c &&
X/*
X * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).  
X * You may copy, distribute, and use this software as long as this
X * copyright statement is not removed.
X */
X#include <stdio.h>
X#include "malloc.h"
X#include "tostring.h"
X
X/*
X * Function:	malloc_dump()
X *
X * Purpose:	to dump a printed copy of the malloc chain and
X *		associated data elements
X *
X * Arguments:	fd	- file descriptor to write data to
X *
X * Returns:	nothing of any use
X *
X * Narrative:	Just print out all the junk
X *
X * Notes:	This function is implemented using low level calls because
X * 		of the likelyhood that the malloc tree is damaged when it
X *		is called.  (Lots of things in the c library use malloc and
X *		we don't want to get into a catch-22).
X *
X */
X
X#ifndef lint
Xstatic
Xchar rcs_hdr[] = "$Id: dump.c,v 1.4 90/05/11 00:13:08 cpcahil Exp $";
X#endif
X
X
X#define ERRSTR	"I/O Error on malloc dump file descriptor\n"
X
X#define WRITEOUT(fd,str,len)	if( write(fd,str,(unsigned)len) != len ) \
X				{ \
X					(void) write(2,ERRSTR,\
X						     (unsigned)strlen(ERRSTR));\
X					exit(120); \
X				}
X
Xmalloc_dump(fd)
X	int		fd;
X{
X	char			  buffer[512];
X	void			  exit();
X	int			  i;
X	extern char		* malloc_data_end;
X	extern char		* malloc_data_start;
X	extern struct mlist 	* malloc_end;
X	extern struct mlist	  malloc_start;
X	struct mlist 		* ptr;
X
X	WRITEOUT(fd,"MALLOC CHAIN:\n",14);
X	WRITEOUT(fd,"-------------------- START ----------------\n",44);
X
X	for(i=0; i < 80; i++)
X	{
X		buffer[i] = ' ';
X	}
X
X	for(ptr = &malloc_start; ptr; ptr = ptr->next)
X	{
X		(void) tostring(buffer,	   (int)ptr,	     8,	B_HEX,	'0');
X		(void) tostring(buffer+9,  (int)ptr->next,   8,	B_HEX,	'0');
X		(void) tostring(buffer+18, (int)ptr->prev,   8,	B_HEX,	'0');
X		(void) tostring(buffer+27, (int)ptr->flag,  10,	B_HEX,	'0');
X		(void) tostring(buffer+38, (int)ptr->s.size, 8,	B_DEC,	' ');
X		(void) tostring(buffer+47, (int)ptr->s.size, 8,	B_HEX,	'0');
X		(void) tostring(buffer+57, (int)ptr->data,   8,	B_HEX,	'0');
X		buffer[46] = '(';
X		buffer[55] = ')';
X		buffer[65] = '\n';
X		WRITEOUT(fd,buffer,66);
X	}
X	WRITEOUT(fd,"-------------------- DONE -----------------\n",44);
X
X	WRITEOUT(fd,"Malloc start:      ",19);
X	(void) tostring(buffer, (int) &malloc_start, 8, B_HEX, '0');
X	buffer[8] = '\n';
X	WRITEOUT(fd,buffer,9);
X
X	WRITEOUT(fd,"Malloc end:        ", 19);
X	(void) tostring(buffer, (int) malloc_end, 8, B_HEX, '0');
X	buffer[8] = '\n';
X	WRITEOUT(fd,buffer,9);
X
X	WRITEOUT(fd,"Malloc data start: ", 19);
X	(void) tostring(buffer, (int) malloc_data_start, 8, B_HEX, '0');
X	buffer[8] = '\n';
X	WRITEOUT(fd,buffer,9);
X
X	WRITEOUT(fd,"Malloc data end:   ", 19);
X	(void) tostring(buffer, (int) malloc_data_end, 8, B_HEX, '0');
X	buffer[8] = '\n';
X	WRITEOUT(fd,buffer,9);
X	
X} /* malloc_dump(... */
X
X
X/*
X * $Log:	dump.c,v $
X * Revision 1.4  90/05/11  00:13:08  cpcahil
X * added copyright statment
X * 
X * Revision 1.3  90/02/24  21:50:07  cpcahil
X * lots of lint fixes
X * 
X * Revision 1.2  90/02/24  17:27:48  cpcahil
X * changed $header to $Id to remove full path from rcs id string
X * 
X * Revision 1.1  90/02/22  23:17:43  cpcahil
X * Initial revision
X * 
X */
SHAR_EOF
$TOUCH -am 0511001490 dump.c &&
chmod 0444 dump.c ||
echo "restore of dump.c failed"
set `wc -c dump.c`;Wc_c=$1
if test "$Wc_c" != "3097"; then
	echo original size 3097, current size $Wc_c
fi
fi
# ============= free.c ==============
if test X"$1" != X"-c" -a -f 'free.c'; then
	echo "File already exists: skipping 'free.c'"
else
echo "x - extracting free.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > free.c &&
X/*
X * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).  
X * You may copy, distribute, and use this software as long as this
X * copyright statement is not removed.
X */
X#include <stdio.h>
X#include "malloc.h"
X#include "debug.h"
X
X/*
X * Function:	free()
X *
X * Purpose:	to deallocate malloced data
X *
X * Arguments:	ptr	- pointer to data area to deallocate
X *
X * Returns:	nothing of any value
X *
X * Narrative:
X *		verify pointer is within malloc region
X *		get mlist pointer from passed address
X *		verify magic number
X *		verify inuse flag
X *		verify pointer connections with surrounding segments
X *		turn off inuse flag
X *		verify no data overrun into non-malloced area at end of segment
X *		IF possible join segment with next segment
X *		IF possible join segment with previous segment
X *		Clear all data in segment (to make sure it isn't reused)
X *
X */
X#ifndef lint
Xstatic
Xchar rcs_hdr[] = "$Id: free.c,v 1.8 90/05/11 00:13:08 cpcahil Exp $";
X#endif
X
Xvoid
Xfree(cptr)
X	char	* cptr;
X{
X	char			* func = "free";
X	int			  i;
X	extern int		  malloc_checking;
X	extern struct mlist	* malloc_end;
X	extern int		  malloc_errno;
X	extern char		* malloc_data_end;
X	extern char		* malloc_data_start;
X	struct mlist		* oldptr;
X	struct mlist		* ptr;
X
X	/*
X	 * IF malloc chain checking is on, go do it.
X	 */
X	if( malloc_checking )
X	{
X		(void) malloc_chain_check(1);
X	}
X
X	/*
X	 * verify that cptr is within the malloc region...
X	 */
X	if( cptr < malloc_data_start || cptr > malloc_data_end )
X	{
X		malloc_errno = M_CODE_BAD_PTR;
X		malloc_warning(func);
X		return;
X	}
X
X	/* 
X	 * convert pointer to mlist struct pointer.  To do this we must 
X	 * move the pointer backwards the correct number of bytes...
X	 */
X	
X	ptr = (struct mlist *) (cptr - M_SIZE);
X	
X	if( (ptr->flag&M_MAGIC) != M_MAGIC )
X	{
X		malloc_errno = M_CODE_BAD_MAGIC;
X		malloc_warning(func);
X		return;
X	}
X
X	if( ! (ptr->flag & M_INUSE) )
X	{
X		malloc_errno = M_CODE_NOT_INUSE;
X		malloc_warning(func);
X		return;
X	}
X
X 	if( (ptr->prev && (ptr->prev->next != ptr) ) ||
X	    (ptr->next && (ptr->next->prev != ptr) ) ||
X	    ((ptr->next == NULL) && (ptr->prev == NULL)) )
X	{
X		malloc_errno = M_CODE_BAD_CONNECT;
X		malloc_warning(func);
X		return;
X	}
X
X	ptr->flag &= ~M_INUSE;
X
X	/*
X	 * verify that the user did not overrun the requested number of bytes.
X	 */
X	for(i=ptr->r_size; i < ptr->s.size; i++)
X	{
X		if( ptr->data[i] != M_FILL )
X		{
X			malloc_errno = M_CODE_OVERRUN;
X			malloc_warning(func);
X			break;
X		}
X	}
X
X	DEBUG3(10,"pointers: prev: 0x%.7x,  ptr: 0x%.7x, next: 0x%.7x",
X			ptr->prev, ptr, ptr->next);
X	
X	DEBUG3(10,"size:     prev: %9d,  ptr: %9d, next: %9d",
X			ptr->prev->s.size, ptr->s.size, ptr->next->s.size);
X	
X	DEBUG3(10,"flags:    prev: 0x%.7x,  ptr: 0x%.7x, next: 0x%.7x",
X			ptr->prev->flag, ptr->flag, ptr->next->flag);
X	
X	/*
X	 * check to see if this block can be combined with the next and/or
X	 * previous block.  Since it may be joined with the previous block
X	 * we will save a pointer to the previous block and test to verify
X	 * if it is joined (it's next ptr will no longer point to ptr).
X 	 */
X	malloc_join(ptr,ptr->next,0,0);
X	
X	oldptr = ptr->prev;
X
X	malloc_join(ptr->prev, ptr,0,0);
X
X	if( oldptr->next != ptr )
X	{
X		DEBUG0(10,"Oldptr was changed");
X		ptr = oldptr;
X	}
X	
X	/*
X	 * fill this block with '\02's to ensure that nobody is using a 
X	 * pointer to already freed data...
X	 */
X	malloc_memset(ptr->data,M_FREE_FILL,ptr->s.size);
X
X}
X
X/*
X * $Log:	free.c,v $
X * Revision 1.8  90/05/11  00:13:08  cpcahil
X * added copyright statment
X * 
X * Revision 1.7  90/02/25  11:00:18  cpcahil
X * added support for malloc chain checking.
X * 
X * Revision 1.6  90/02/24  21:50:18  cpcahil
X * lots of lint fixes
X * 
X * Revision 1.5  90/02/24  17:29:13  cpcahil
X * changed $Header to $Id so full path wouldnt be included as part of rcs 
X * id string
X * 
X * Revision 1.4  90/02/24  15:15:32  cpcahil
X * 1. changed ALREADY_FREE errno to NOT_INUSE so that the same errno could
X *    be used by both free and realloc (since it was the same error).
X * 2. fixed coding bug
X * 
X * Revision 1.3  90/02/24  14:23:45  cpcahil
X * fixed malloc_warning calls
X * 
X * Revision 1.2  90/02/24  13:59:10  cpcahil
X * added function header.
X * Modified calls to malloc_warning/malloc_fatal to use new code error messages
X * Added support for malloc_errno setting of error codes.
X * 
X * Revision 1.1  90/02/22  23:17:43  cpcahil
X * Initial revision
X * 
X */
SHAR_EOF
$TOUCH -am 0511001490 free.c &&
chmod 0444 free.c ||
echo "restore of free.c failed"
set `wc -c free.c`;Wc_c=$1
if test "$Wc_c" != "4379"; then
	echo original size 4379, current size $Wc_c
fi
fi
# ============= m_init.c ==============
if test X"$1" != X"-c" -a -f 'm_init.c'; then
	echo "File already exists: skipping 'm_init.c'"
else
echo "x - extracting m_init.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > m_init.c &&
X/*
X * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).  
X * You may copy, distribute, and use this software as long as this
X * copyright statement is not removed.
X */
X#include <stdio.h>
X#include "malloc.h"
X
X/*
X * Function:	malloc_init()
X *
X * Purpose:	to initialize the pointers and variables use by the
X *		malloc() debugging library
X *
X * Arguments:	none
X *
X * Returns:	nothing of any value
X *
X * Narrative:	Just initialize all the needed variables.  Use mallopt
X *		to set options taken from the environment.
X *
X */
X#ifndef lint
Xstatic
Xchar rcs_hdr[] = "$Id: m_init.c,v 1.4 90/05/11 15:53:35 cpcahil Exp $";
X#endif
X
Xvoid
Xmalloc_init()
X{
X	char			* cptr;
X	char			* getenv();
X	extern char		* malloc_data_end;
X	extern char		* malloc_data_start;
X	extern struct mlist	* malloc_end;
X	extern struct mlist	  malloc_start;
X	char			* sbrk();
X
X	/*
X 	 * If already initialized...
X	 */
X	if( malloc_data_start != (char *) 0)
X	{
X		return;
X	}
X
X
X	malloc_data_start = sbrk(0);
X	malloc_data_end = malloc_data_start;
X	malloc_start.s.size = 0;
X	malloc_end = &malloc_start;
X	
X	if( (cptr=getenv("MALLOC_WARN")) != NULL )
X	{
X		mallopt(MALLOC_WARN,atoi(cptr));
X	}
X
X	if( (cptr=getenv("MALLOC_FATAL")) != NULL)
X	{
X		mallopt(MALLOC_FATAL,atoi(cptr));
X	}
X
X	if( (cptr=getenv("MALLOC_CKCHAIN")) != NULL)
X	{
X		mallopt(MALLOC_CKCHAIN,atoi(cptr));
X	}
X
X	if( (cptr=getenv("MALLOC_ERRFILE")) != NULL)
X	{
X		mallopt(MALLOC_ERRFILE,cptr);
X	}
X
X}
X
X/*
X * $Log:	m_init.c,v $
X * Revision 1.4  90/05/11  15:53:35  cpcahil
X * fixed bug in initialization code.
X * 
X * Revision 1.3  90/05/11  00:13:08  cpcahil
X * added copyright statment
X * 
X * Revision 1.2  90/02/24  21:50:20  cpcahil
X * lots of lint fixes
X * 
X * Revision 1.1  90/02/24  17:10:53  cpcahil
X * Initial revision
X * 
X */
SHAR_EOF
$TOUCH -am 0511155390 m_init.c &&
chmod 0444 m_init.c ||
echo "restore of m_init.c failed"
set `wc -c m_init.c`;Wc_c=$1
if test "$Wc_c" != "1751"; then
	echo original size 1751, current size $Wc_c
fi
fi
# ============= m_perror.c ==============
if test X"$1" != X"-c" -a -f 'm_perror.c'; then
	echo "File already exists: skipping 'm_perror.c'"
else
echo "x - extracting m_perror.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > m_perror.c &&
X/*
X * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).  
X * You may copy, distribute, and use this software as long as this
X * copyright statement is not removed.
X */
X
X#ifndef lint
Xstatic
Xchar rcsid[] = "$Id: m_perror.c,v 1.4 90/05/11 00:13:08 cpcahil Exp $";
X#endif
X
X/*
X * malloc errno error strings...
X */
X
Xchar *malloc_err_strings[] = 
X{
X	"No errors",
X	"Malloc chain is corrupted, pointers out of order",
X	"Malloc chain is corrupted, end before end pointer",
X	"Pointer is not within malloc area",
X	"Malloc region does not have valid magic number in header",
X	"Pointers between this segment and ajoining segments are invalid",
X	"Data has overrun beyond requested number of bytes",
X	"Data in free'd area has been modified",
X	"Data are is not in use (can't be freed or realloced)",
X	"Unable to get additional memory from the system",
X	(char *) 0
X};
X
X/*
X * Function:	malloc_perror()
X *
X * Purpose:	to print malloc_errno error message
X *
X * Arguments:	str	- string to print with error message
X *
X * Returns:	nothing of any value
X *
X * Narrative:
X */
Xvoid
Xmalloc_perror(str)
X	char	* str;
X{
X	extern int	  malloc_errno;
X	register char 	* s;
X	register char 	* t;
X
X	if( str && *str)
X	{
X		for(s=str; *s; s++)
X		{
X			/* do nothing */;
X		}
X
X		(void) write(2,str,(unsigned)(s-str));
X		(void) write(2,": ",(unsigned)2);
X	}
X
X	t = malloc_err_strings[malloc_errno];
X
X	for(s=t; *s; s++)
X	{
X		/* do nothing */;
X	}
X
X	(void) write(2,t,(unsigned)(s-t));
X
X	(void) write(2,"\n",(unsigned)1);
X}
X
X/*
X * $Log:	m_perror.c,v $
X * Revision 1.4  90/05/11  00:13:08  cpcahil
X * added copyright statment
X * 
X * Revision 1.3  90/02/24  21:50:21  cpcahil
X * lots of lint fixes
X * 
X * Revision 1.2  90/02/24  17:39:55  cpcahil
X * 1. added function header
X * 2. added rcs id and log strings.
X * 
X */
SHAR_EOF
$TOUCH -am 0511001490 m_perror.c &&
chmod 0444 m_perror.c ||
echo "restore of m_perror.c failed"
set `wc -c m_perror.c`;Wc_c=$1
if test "$Wc_c" != "1776"; then
	echo original size 1776, current size $Wc_c
fi
fi
# ============= malloc.3 ==============
if test X"$1" != X"-c" -a -f 'malloc.3'; then
	echo "File already exists: skipping 'malloc.3'"
else
echo "x - extracting malloc.3 (Text)"
sed 's/^X//' << 'SHAR_EOF' > malloc.3 &&
X.TH MALLOC 3 "" "" "1.0"
X.ds ]T 
X.\"/*
X.\" * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).  
X.\" * You may copy, distribute, and use this software as long as this
X.\" * copyright statement is not removed.
X.\" */
X.\" $Id: malloc.3,v 1.1 90/05/11 15:53:20 cpcahil Exp $
X.SH NAME
Xmalloc \t- debugging malloc library
X.SH SYNOPSIS
X.ft B
X.nf
X#include <malloc.h>
X
Xchar	* calloc(nelem,elsize);
Xvoid	  free(ptr);
Xchar	* malloc(size);
Xint	  malloc_chain_check(flag);
Xvoid	  malloc_dump(fd);
Xint	  mallopt(cmd,value)
Xchar	* realloc(ptr,size);
X
Xint		  cmd,fd,flag;
Xunsigned	  elsize,nelem,size;
Xchar		* ptr;
Xunion val	  value;
X
X.fi
X.ft R
X.SH DESCRIPTION
XThis malloc library is a replacement for the standard library to be used
Xduring software development/debugging.  See the standard malloc(3) pages
Xfor more information on the use of the following functions:
X.nf
X.in +.5i
Xcalloc(), free(), malloc(), realloc()
X.in -.5i
X.fi
X.sp
XThis library differs from the standard malloc library in the
Xfollowing ways:
X.P
X1. Each malloc segment contains a magic number so that free can 
Xverify that the pointer passed points to a valid malloc segment.
X.P
X2. Each malloc segment is filled with a non-zero pattern so that code that
Xdepends upon malloc segments being null will fail.
X.P
X3. The size of each segment will be at least 1 byte larger than requested
Xand the extra bytes will be filled with a non-zero pattern.  When free is
Xcalled, it will verify that you did not go beyond the number of bytes 
Xyou asked for.
X.P
X4. When a segment is freed, it will be filled with a different non-zero pattern
Xto ensure that the program doesn't depend upon the use of already freed data.
X.P
X5. Whenever any of the string or memory functions (str*, b*, mem*) are 
Xcalled with a pointer that is within the malloc arena,  the operation is
Xchecked to verify that it does not overrun the malloced segment.  A failure
Xof this check is considered a "warning level error" (described later) and
Xis handled accordingly.
X.P
X7. Run time checking can include verification of the malloc chain at each
Xand every call to one of the malloc functions or manually by calling the
Xmalloc_chain_check function.
X.P
X6. When a problem is found, the action taken is specified at runtime by
Xenvironment variables or at compile time by the use of the mallopt()
Xfunction.
X.P
XThere are two arbitrary levels of errors, warning and fatal, that this
Xlibrary will detect.  They are broken down as follows:
X.P
X.nf
X.in +.25i
XWarning messages include:
X.sp
X.in +.5i
X.ti -.25i
XCalling free with a bad pointer
X.br
X.ti -.25i
XCalling a bstring/string/memory (3) function which will go beyond
Xthe end of a malloc block. Note that the library function is
Xnot modified to refuse the operation.
X.sp
X.in -.5i
XFatal errors are:
X.in +.5i
X.ti -.25i
XDetectable corruption to the malloc chain.
X.in -.5i
X.in -.25i
X.P
XThe error handling for each level (warning or fatal) are specified using
Xenvironment variables or mallopt().  The coding for the error handling is
Xas follows:
X.sp
X.nf
X.in +.5i
X.ti -.25i
X  0 - continue operations
X.ti -.25i
X  1 - drop core and exit
X.ti -.25i
X  2 - just exit
X.ti -.25i
X  3 - drop core, but continue executing.  Core files will
Xbe placed into core.[PID].[counter] i.e: core.00123.001
X.ti -.25i
X128 - dump malloc chain and continue
X.ti -.25i
X129 - dump malloc chain, dump core, and exit
X.ti -.25i
X130 - dump malloc chain, exit
X.ti -.25i
X131 - dump malloc chain, dump core, continue processing
X.in -.5i
X.P
XIn addition error messages can be placed into an error file.
X.P
X\fBmalloc_opt\fP() is used to set the malloc debugging options. The
Xfollowing options can be set:
X.br
X.sp
X.in +.5i
XMALLOC_WARN - set the error handling for warning level errors.  \fBval\fP is
Xan integer that can contain any one of the following values:
X.sp
X.in +.5i
XM_HANDLE_IGNORE - ignore error
X.br
XM_HANDLE_ABORT - drop core and exit
X.br
XM_HANDLE_EXIT - just exit (no core drop)
X.br
XM_HANDLE_CORE - drop core, but keep on going
X.br
X.in -.5i
X.sp
XIn addition, M_HANDLE_DUMP may be or'd in to cause a dump of the current
Xmalloc chain.
X.br
X.sp
XMALLOC_FATAL - set the error handling for fatal level errors.  \fBval\fP is
Xequivalent to \fBval\fP for MALLOC_WARN.
X.br
X.sp
XMALLOC_ERRFILE - set the destination for malloc error messages.  \fBval\fP is
Xa pointer to a character string containing the name of the file to be used
Xfor error messages.
X.br
X.sp
XMALLOC_CKCHAIN - set the malloc chain checking flag.  If \fBval\fP is
Xnon-zero, chain checking at every call to malloc is turned on.
X.br
X.sp
XFor example, to set up the session to generate a core file for
Xevery malloc warning, to drop core and exit on a malloc fatal, and 
Xto log all messages to the file "malloc_log" do the following:
X.sp
X.nf
X.in +.5i
X#include <malloc.h>
Xmalloc_opt(MALLOC_WARN,131);
Xmalloc_opt(MALLOC_FATAL,1);
Xmalloc_opt(MALLOC_ERRFILE,"malloc_log");
X.in -.5i
X.fi
X.in -.5i
X.sp
X\fBmalloc_opt\fP() can be used to set/alter the debugging options at any
Xtime.
X.P
X\fBmalloc_dump\fP() will dump a table of the malloc arena showing all
Xallocated/freed segments and the first few bytes of data in each segment.
X\fBfd\fP is the file descriptor to write the data to.
X.P
X\fBmalloc_chain_check\fP() will check the status of the malloc arena.
XIf \fBflag\fP is non-zero, an error found in the chain will cause a 
Xfatal error.  \fBmalloc_chain_check\fP() returns zero when there are no
Xproblems found in the malloc chain, non-zero otherwise.
X.SH "ENVIRONMENT VARIABLES"
XEnvironment variables can be used to control error handling, error logging
Xand malloc chain checking at run time.  The following environment variables
Xare used:
X.P
XMALLOC_WARN - specifies the error handling for warning errors
X.br
XMALLOC_FATAL - specifies the error handling for fatal errors
X.br
XMALLOC_ERRFILE - specifies the error log file for error messages.  
X.br
XMALLOC_CKCHAIN - if 1, turns on malloc chain checking at every call to any
Xof the malloc functions.
X.P
XFor example, to set up the session to generate a core file for
Xevery malloc warning, to drop core and exit on a malloc fatal, and 
Xto log all messages to the file "malloc_log" do the following:
X.sp
X.nf
X.in +.5i
XMALLOC_WARN=131
XMALLOC_FATAL=1
XMALLOC_ERRFILE=malloc_log
X
Xexport MALLOC_WARN MALLOC_FATAL MALLOC_ERRFILE
X.in -.5i
X.fi
X.SH WARNINGS
XThis malloc library and it's associated string and memory functions are
Xmuch less efficient than the standard functions due in part to the extra
Xerror checking.  You do not want to use this library when generating a
Xproduction (i.e. releasable) version of your software.  It should only
Xbe used during development and testing.
X.SH SEE ALSO
Xstat(2)
X.SH AUTHOR
XConor P. Cahill
XVirtual Technologies Incorporated
X.sp
Xuunet!virtech!cpcahil
SHAR_EOF
$TOUCH -am 0511155390 malloc.3 &&
chmod 0444 malloc.3 ||
echo "restore of malloc.3 failed"
set `wc -c malloc.3`;Wc_c=$1
if test "$Wc_c" != "6694"; then
	echo original size 6694, current size $Wc_c
fi
fi
# ============= malloc.c ==============
if test X"$1" != X"-c" -a -f 'malloc.c'; then
	echo "File already exists: skipping 'malloc.c'"
else
echo "x - extracting malloc.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > malloc.c &&
X/*
X * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).  
X * You may copy, distribute, and use this software as long as this
X * copyright statement is not removed.
X */
X#include <stdio.h>
X#include <fcntl.h>
X#include "malloc.h"
X#include "tostring.h"
X
X/*
X * Function:	malloc()
X *
X * Purpose:	memory allocator
X *
X * Arguments:	size	- size of data area needed
X *
X * Returns:	pointer to allocated area, or NULL if unable
X *		to allocate addtional data.
X *
X * Narrative:
X *
X */
X#ifndef lint
Xstatic
Xchar rcs_hdr[] = "$Id: malloc.c,v 1.6 90/05/11 00:13:09 cpcahil Exp $";
X#endif
X
Xint		  malloc_checking;
Xchar		* malloc_data_start;
Xchar		* malloc_data_end;
Xstruct mlist 	* malloc_end;
Xint		  malloc_errfd = 2;
Xint		  malloc_errno;
Xint		  malloc_fatal_level = M_HANDLE_CORE;
Xstruct mlist	  malloc_start;
Xint		  malloc_warn_level;
X
Xchar *
Xmalloc(size)
X	unsigned int	  size;
X{
X	char		* func = "malloc";
X	char		* getenv();
X	void		  malloc_fatal();
X	void		  malloc_init();
X	void		  malloc_memset();
X	void		  malloc_split();
X	void		  malloc_warning();
X	unsigned int	  need;
X	struct mlist	* oldptr;
X	struct mlist	* ptr;
X	char		* sbrk();
X
X	/*
X	 * If this is the first call to malloc...
X	 */
X	if( malloc_data_start == (char *) 0 )
X	{
X		malloc_init();
X	}
X
X	/*
X	 * If malloc chain checking is on, go do it.
X	 */
X	if( malloc_checking )
X	{
X		(void) malloc_chain_check(1);
X	}
X
X	/*
X	 * always make sure there is at least on extra byte in the malloc
X	 * area so that we can verify that the user does not overrun the
X	 * data area.
X	 */
X	size++;
X
X	/*
X	 * Now look for a free area of memory of size bytes...
X	 */
X	oldptr = NULL;
X	for(ptr = &malloc_start; ; ptr = ptr->next)
X	{
X		/*
X		 * Since the malloc chain is a forward only chain, any
X		 * pointer that we get should always be positioned in 
X		 * memory following the previous pointer.  If this is not
X		 * so, we must have a corrupted chain.
X		 */
X		if( ptr )
X		{
X			if(ptr < oldptr )
X			{
X				malloc_errno = M_CODE_CHAIN_BROKE;
X				malloc_fatal(func);
X				return(NULL);
X			}
X			oldptr = ptr;
X		}
X		else if( oldptr != malloc_end )
X		{
X			/*
X			 * This should never happen.  If it does, then
X			 * we got a real problem.
X			 */
X			malloc_errno = M_CODE_NO_END;
X			malloc_fatal(func);
X			return(NULL);
X		}
X		
X
X		/*
X		 * if this element is already in use...
X		 */
X		if( ptr && ((ptr->flag & M_INUSE) != 0) )
X		{
X			continue;
X		}
X
X		/*
X		 * if there isn't room for this block..
X		 */
X		if( ptr && (ptr->s.size < size) )
X		{
X			continue;
X		}
X
X		/*
X		 * If ptr is null, we have run out of memory and must sbrk more
X		 */
X		if( ptr == NULL )
X		{
X			need = (size + M_SIZE) * (size > 100*1024 ? 1:2);
X			if( need < M_BLOCKSIZE )
X			{
X				need = M_BLOCKSIZE;
X			}
X			else if( need & (M_BLOCKSIZE-1) )
X			{
X				need &= ~(M_BLOCKSIZE-1);
X				need += M_BLOCKSIZE;
X			}
X			ptr = (struct mlist *) sbrk((int)need);
X			if( ptr == (struct mlist *) -1 )
X			{
X				malloc_errno = M_CODE_NOMORE_MEM;
X				malloc_fatal(func);
X			}
X			malloc_data_end = sbrk((int)0);
X
X			ptr->prev   = oldptr;
X			ptr->next   = (struct mlist *) 0;
X			ptr->s.size = need - M_SIZE;
X			ptr->flag  = M_MAGIC;
X
X			oldptr->next = ptr;
X			malloc_end = ptr;
X
X
X		} /* if( ptr ==... */
X
X		/*
X	 	 * Now ptr points to a memory location that can store
X		 * this data, so lets go to work.
X		 */
X
X		ptr->r_size = size;		/* save requested size	*/
X		ptr->flag |= M_INUSE;
X
X		/*
X	 	 * split off unneeded data area in this block, if possible...
X		 */
X		malloc_split(ptr);
X
X		/*
X		 * re-adjust the requested size so that it is what the user
X		 * actually requested...
X		 */
X
X		ptr->r_size--;
X
X		/*
X		 * just to make sure that noone is misusing malloced
X	 	 * memory without initializing it, lets set it to
X		 * all '\01's.  We call local_memset() because memset()
X		 * may be checking for malloc'd ptrs and this isn't
X		 * a malloc'd ptr yet.
X		 */
X		malloc_memset(ptr->data,M_FILL,(int)ptr->s.size);
X
X		return( ptr->data);
X
X	} /* for(... */
X
X} /* malloc(... */
X
X/*
X * Function:	malloc_split()
X *
X * Purpose:	to split a malloc segment if there is enough room at the
X *		end of the segment that isn't being used
X *
X * Arguments:	ptr	- pointer to segment to split
X *
X * Returns:	nothing of any use.
X *
X * Narrative:
X *		get the needed size of the module
X * 		round the size up to appropriat boundry
X *		calculate amount of left over space
X *		if there is enough left over space
X *		    create new malloc block out of remainder
X *		    if next block is free 
X *			join the two blocks together
X *		    fill new empty block with free space filler
X * 		    re-adjust pointers and size of current malloc block
X *		
X *		
X *
X * Mod History:	
X *   90/01/27	cpcahil		Initial revision.
X */
Xvoid
Xmalloc_split(ptr)
X	struct mlist		* ptr;
X{
X	extern struct mlist	* malloc_end;
X	void			  malloc_join();
X	void			  malloc_memset();
X	int			  rest;
X	int			  size;
X	struct mlist		* tptr;
X
X	size = ptr->r_size;
X
X	/*
X	 * roundup size to the appropriate boundry
X	 */
X
X	M_ROUNDUP(size);
X
X	/*
X	 * figure out how much room is left in the array.
X	 * if there is enough room, create a new mlist 
X	 *     structure there.
X	 */
X
X	if( ptr->s.size > size )
X	{
X		rest = ptr->s.size - size;
X	}
X	else
X	{
X		rest = 0;
X	}
X	
X	if( rest > (M_SIZE+M_RND) )
X	{
X		tptr = (struct mlist *) (ptr->data+size);
X		tptr->prev = ptr;
X		tptr->next = ptr->next;
X		tptr->flag = M_MAGIC;
X		tptr->s.size = rest - M_SIZE;
X
X		/*
X		 * If possible, join this segment with the next one
X		 */
X
X		malloc_join(tptr, tptr->next,0,0);
X
X		if( tptr->next )
X		{
X			tptr->next->prev = tptr;
X		}
X
X		malloc_memset(tptr->data,M_FREE_FILL, (int)tptr->s.size);
X
X		ptr->next = tptr;
X		ptr->s.size = size;
X
X		if( malloc_end == ptr )
X		{
X			malloc_end = tptr;
X		}
X	}
X
X} /* malloc_split(... */
X
X/*
X * Function:	malloc_join()
X *
X * Purpose:	to join two malloc segments together (if possible)
X *
X * Arguments:	ptr	- pointer to segment to join to.
X * 		nextptr	- pointer to next segment to join to ptr.
X *
X * Returns:	nothing of any values.
X *
X * Narrative:
X *
X * Mod History:	
X *   90/01/27	cpcahil		Initial revision.
X */
Xvoid
Xmalloc_join(ptr,nextptr, inuse_override, fill_flag)
X	struct mlist	* ptr;
X	struct mlist	* nextptr;
X	int		  inuse_override;
X	int		  fill_flag;
X{
X	unsigned int	  newsize;
X
X	if( 	ptr     && ! (inuse_override || (ptr->flag & M_INUSE)) && 
X		nextptr && ! (nextptr->flag & M_INUSE) &&
X		((ptr->data+ptr->s.size) == (char *) nextptr) )
X	{
X		if( malloc_end == nextptr )
X		{
X			malloc_end = ptr;
X		}
X		ptr->next = nextptr->next;
X		newsize = nextptr->s.size + M_SIZE;
X
X		/*
X		 * if we are to fill and this segment is in use,
X		 *   fill in with M_FILL newly added space...
X	 	 */
X
X		if(fill_flag && (ptr->flag & M_INUSE) )
X		{
X			malloc_memset(ptr->data+ptr->s.size,
X				      M_FILL, (int)(nextptr->s.size + M_SIZE));
X		}
X
X		ptr->s.size += newsize;
X		if( ptr->next )
X		{
X			ptr->next->prev = ptr;
X		}
X	}
X
X} /* malloc_join(... */
X
X
X/*
X * The following mess is just to ensure that the versions of these functions in
X * the current library are included (to make sure that we don't accidentaly get 
X * the libc versions. (This is the lazy man's -u ld directive)
X */
X
Xvoid free();
Xint strcmp();
Xint memcmp();
Xchar	* realloc();
X
Xvoid		(*malloc_void_funcs[])() =
X{
X	free,
X};
X
Xint		(*malloc_int_funcs[])() =
X{
X	strcmp,
X	memcmp,
X};
X
Xchar		* (*malloc_char_star_funcs[])() =
X{
X	realloc,
X};
X
X/*
X * This is malloc's own memset which is used without checking the parameters.
X */
X
Xvoid
Xmalloc_memset(ptr,byte,len)
X	char		* ptr;
X	char		  byte;
X	int		  len;
X{
X
X	while(len-- > 0)
X	{
X		*ptr++ = byte;
X	}
X
X} /* malloc_memset(... */
X
X/*
X * Function:	malloc_fatal()
X *
X * Purpose:	to display fatal error message and take approrpriate action
X *
X * Arguments:	funcname - name of function calling this routine
X *
X * Returns:	nothing of any value
X *
X * Narrative:
X *
X * Notes:	This routine does not make use of any libc functions to build
X *		and/or disply the error message.  This is due to the fact that
X *		we are probably at a point where malloc is having a real problem
X *		and we don't want to call any function that may use malloc.
X */
Xvoid
Xmalloc_fatal(funcname)
X	char		* funcname;
X{
X	char		  errbuf[128];
X	void		  exit();
X	void		  malloc_err_handler();
X	extern char	* malloc_err_strings[];
X	extern int	  malloc_errno;
X	extern int	  malloc_fatal_level;
X	char		* s;
X	char		* t;
X
X	s = errbuf;
X	t = "Fatal error: ";
X	while( *s = *t++)
X	{
X		s++;
X	}
X	t = funcname;
X	while( *s = *t++)
X	{
X		s++;
X	}
X
X	t = "(): ";
X	while( *s = *t++)
X	{
X		s++;
X	}
X
X	t = malloc_err_strings[malloc_errno];
X	while( *s = *t++)
X	{
X		s++;
X	}
X
X	*(s++) = '\n';
X
X	if( write(malloc_errfd,errbuf,(unsigned)(s-errbuf)) != (s-errbuf))
X	{
X		(void) write(2,"I/O error to error file\n",(unsigned)24);
X		exit(110);
X	}
X	malloc_err_handler(malloc_fatal_level);
X
X} /* malloc_fatal(... */
X
X/*
X * Function:	malloc_warning()
X *
X * Purpose:	to display warning error message and take approrpriate action
X *
X * Arguments:	funcname - name of function calling this routine
X *
X * Returns:	nothing of any value
X *
X * Narrative:
X *
X * Notes:	This routine does not make use of any libc functions to build
X *		and/or disply the error message.  This is due to the fact that
X *		we are probably at a point where malloc is having a real problem
X *		and we don't want to call any function that may use malloc.
X */
Xvoid
Xmalloc_warning(funcname)
X	char		* funcname;
X{
X	char		  errbuf[128];
X	void		  exit();
X	void		  malloc_err_handler();
X	extern char	* malloc_err_strings[];
X	extern int	  malloc_errno;
X	extern int	  malloc_warn_level;
X	char		* s;
X	char		* t;
X
X	s = errbuf;
X	t = "Warning: ";
X	while( *s = *t++)
X	{
X		s++;
X	}
X	t = funcname;
X	while( *s = *t++)
X	{
X		s++;
X	}
X
X	t = "(): ";
X	while( *s = *t++)
X	{
X		s++;
X	}
X
X	t = malloc_err_strings[malloc_errno];
X	while( *s = *t++)
X	{
X		s++;
X	}
X
X	*(s++) = '\n';
X
X	if( write(malloc_errfd,errbuf,(unsigned)(s-errbuf)) != (s-errbuf))
X	{
X		(void) write(2,"I/O error to error file\n",(unsigned)24);
X		exit(110);
X	}
X
X	malloc_err_handler(malloc_warn_level);
X
X} /* malloc_warning(... */
X
X/*
X * Function:	malloc_err_handler()
X *
X * Purpose:	to take the appropriate action for warning and/or fatal 
X *		error conditions.
X *
X * Arguments:	level - error handling level 
X *
X * Returns:	nothing of any value
X *
X * Narrative:
X *
X * Notes:	This routine does not make use of any libc functions to build
X *		and/or disply the error message.  This is due to the fact that
X *		we are probably at a point where malloc is having a real problem
X *		and we don't want to call any function that may use malloc.
X */
Xvoid
Xmalloc_err_handler(level)
X{
X	void		  exit();
X	void		  malloc_dump();
X	extern int	  malloc_errfd;
X
X	if( level & M_HANDLE_DUMP )
X	{
X		malloc_dump(malloc_errfd);
X	}
X
X	switch( level & ~M_HANDLE_DUMP )
X	{
X		/*
X		 * If we are to drop a core file and exit
X		 */
X		case M_HANDLE_ABORT:
X			(void) abort();
X			break;
X
X		/*
X		 * If we are to exit..
X		 */
X		case M_HANDLE_EXIT:
X			exit(200);
X			break;
X
X		/*
X		 * If we are to dump a core, but keep going on our merry way
X		 */
X		case M_HANDLE_CORE:
X			{
X				int	  pid;
X
X				/*
X				 * fork so child can abort (and dump core)
X				 */
X				if( (pid = fork()) == 0 )
X				{
X					(void) write(2,"Child dumping core\n",
X							(unsigned)9);
X					(void) abort();
X				}
X
X				/*
X 				 * wait for child to finish dumping core
X				 */
X				while( wait((int *)0) != pid)
X				{
X				}
X
X				/*
X				 * Move core file to core.pid.cnt so 
X				 * multiple cores don't overwrite each
X				 * other.
X				 */
X				if( access("core",0) == 0 )
X				{
X					static int	  corecnt;
X					char	  	  filenam[32];
X					filenam[0] = 'c';
X					filenam[1] = 'o';
X					filenam[2] = 'r';
X					filenam[3] = 'e';
X					filenam[4] = '.';
X					(void)tostring(filenam+5,getpid(),
X						5, B_DEC, '0');
X					filenam[10] = '.';
X					(void)tostring(filenam+11,corecnt++,
X						3, B_DEC, '0');
X					filenam[14] = '\0';
X					(void) unlink(filenam);
X					if( link("core",filenam) == 0)
X					{
X						(void) unlink("core");
X					}
X				}
X			}
X
X
X		/* 
X		 * If we are to just ignore the error and keep on processing
X		 */
X		case M_HANDLE_IGNORE:
X			break;
X
X	} /* switch(... */
X
X} /* malloc_err_handler(... */
X
X/*
X * $Log:	malloc.c,v $
X * Revision 1.6  90/05/11  00:13:09  cpcahil
X * added copyright statment
X * 
X * Revision 1.5  90/02/25  11:01:18  cpcahil
X * added support for malloc chain checking.
X * 
X * Revision 1.4  90/02/24  21:50:21  cpcahil
X * lots of lint fixes
X * 
X * Revision 1.3  90/02/24  14:51:18  cpcahil
X * 1. changed malloc_fatal and malloc_warn to use malloc_errno and be passed
X *    the function name as a parameter.
X * 2. Added several function headers.
X * 3. Changed uses of malloc_fatal/warning to conform to new usage.
X * 
X * Revision 1.2  90/02/23  18:05:23  cpcahil
X * fixed open of error log to use append mode.
X * 
X * Revision 1.1  90/02/22  23:17:43  cpcahil
X * Initial revision
X * 
X */
SHAR_EOF
$TOUCH -am 0511001490 malloc.c &&
chmod 0444 malloc.c ||
echo "restore of malloc.c failed"
set `wc -c malloc.c`;Wc_c=$1
if test "$Wc_c" != "12756"; then
	echo original size 12756, current size $Wc_c
fi
fi
echo "End of part 1, continue with part 2"
exit 0

exit 0 # Just in case...
-- 
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.



More information about the Comp.sources.unix mailing list