summaryrefslogtreecommitdiff
path: root/dmake/dbug/malloc
diff options
context:
space:
mode:
Diffstat (limited to 'dmake/dbug/malloc')
-rw-r--r--dmake/dbug/malloc/_changes9
-rw-r--r--dmake/dbug/malloc/_readme133
-rw-r--r--dmake/dbug/malloc/calloc.c49
-rw-r--r--dmake/dbug/malloc/debug.h99
-rw-r--r--dmake/dbug/malloc/dump.c103
-rw-r--r--dmake/dbug/malloc/free.c150
-rw-r--r--dmake/dbug/malloc/m_init.c79
-rw-r--r--dmake/dbug/malloc/m_perror.c73
-rw-r--r--dmake/dbug/malloc/makefile77
-rw-r--r--dmake/dbug/malloc/malloc.3223
-rw-r--r--dmake/dbug/malloc/malloc.c627
-rw-r--r--dmake/dbug/malloc/malloc.h85
-rw-r--r--dmake/dbug/malloc/mallopt.c98
-rw-r--r--dmake/dbug/malloc/memory.c195
-rw-r--r--dmake/dbug/malloc/mlc_chk.c256
-rw-r--r--dmake/dbug/malloc/mlc_chn.c188
-rw-r--r--dmake/dbug/malloc/patchlev1
-rw-r--r--dmake/dbug/malloc/realloc.c180
-rw-r--r--dmake/dbug/malloc/string.c533
-rw-r--r--dmake/dbug/malloc/testmem.c646
-rw-r--r--dmake/dbug/malloc/testmlc.c176
-rw-r--r--dmake/dbug/malloc/tostring.c132
-rw-r--r--dmake/dbug/malloc/tostring.h13
23 files changed, 4125 insertions, 0 deletions
diff --git a/dmake/dbug/malloc/_changes b/dmake/dbug/malloc/_changes
new file mode 100644
index 000000000000..888a47a8dfb5
--- /dev/null
+++ b/dmake/dbug/malloc/_changes
@@ -0,0 +1,9 @@
+I made the following changes to the malloc package as found in
+comp.sources.unix:
+
+ 1. created this file _changes.
+ 2. moved README to _readme (facilitates transfer to DOS and back to
+ unix)
+ 3. renamed testmalloc.c, malloc_chk.c, and malloc_chn.c to testmlc.c,
+ mlc_chk.c, and mlc_chn.c respectively. Again DOS has trouble with
+ long basenames in filenames.
diff --git a/dmake/dbug/malloc/_readme b/dmake/dbug/malloc/_readme
new file mode 100644
index 000000000000..b78b1fd6bbcd
--- /dev/null
+++ b/dmake/dbug/malloc/_readme
@@ -0,0 +1,133 @@
+# (c) Copyright 1990 Conor P. Cahill. (uunet!virtech!cpcahil)
+# You may copy, distribute, and use this software as long as this
+# copyright statement is not removed.
+
+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.
diff --git a/dmake/dbug/malloc/calloc.c b/dmake/dbug/malloc/calloc.c
new file mode 100644
index 000000000000..1469b200cbf2
--- /dev/null
+++ b/dmake/dbug/malloc/calloc.c
@@ -0,0 +1,49 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+#include <stdio.h>
+
+/*
+ * Function: calloc()
+ *
+ * Purpose: to allocate and nullify a data area
+ *
+ * Arguments: nelem - number of elements
+ * elsize - size of each element
+ *
+ * Returns: NULL - if malloc fails
+ * or pointer to allocated space
+ *
+ * Narrative: determine size of area to malloc
+ * malloc area.
+ * if malloc succeeds
+ * fill area with nulls
+ * return ptr to malloc'd region
+ */
+#ifndef lint
+static char rcs_header[] = "$Id: calloc.c,v 1.2 2006-07-25 10:07:11 rt Exp $";
+#endif
+
+char *
+calloc(nelem,elsize)
+ unsigned int nelem;
+ unsigned int elsize;
+{
+ char * malloc();
+ char * memset();
+ char * ptr;
+ unsigned int size;
+
+ size = elsize * nelem;
+
+ if( (ptr = malloc(size)) != NULL)
+ {
+ (void) memset(ptr,'\0',(int)size);
+ }
+
+ return(ptr);
+}
+
+
diff --git a/dmake/dbug/malloc/debug.h b/dmake/dbug/malloc/debug.h
new file mode 100644
index 000000000000..069d1dc77639
--- /dev/null
+++ b/dmake/dbug/malloc/debug.h
@@ -0,0 +1,99 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+/************************************************************************/
+/* */
+/* 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 */
+/* */
+/************************************************************************/
+/*
+ * $Id: debug.h,v 1.2 2006-07-25 10:07:24 rt Exp $
+ */
+
+#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 */
+
+
diff --git a/dmake/dbug/malloc/dump.c b/dmake/dbug/malloc/dump.c
new file mode 100644
index 000000000000..70c8ac30c2d8
--- /dev/null
+++ b/dmake/dbug/malloc/dump.c
@@ -0,0 +1,103 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+#include <stdio.h>
+#include "malloc.h"
+#include "tostring.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).
+ *
+ */
+
+#ifndef lint
+static
+char rcs_hdr[] = "$Id: dump.c,v 1.2 2006-07-25 10:07:38 rt Exp $";
+#endif
+
+
+#define ERRSTR "I/O Error on malloc dump file descriptor\n"
+
+#define WRITEOUT(fd,str,len) if( write(fd,str,(unsigned)len) != len ) \
+ { \
+ (void) write(2,ERRSTR,\
+ (unsigned)strlen(ERRSTR));\
+ exit(120); \
+ }
+
+void
+malloc_dump(fd)
+ int fd;
+{
+ char buffer[512];
+ void exit();
+ 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) tostring(buffer, (int)ptr, 8, B_HEX, '0');
+ (void) tostring(buffer+9, (int)ptr->next, 8, B_HEX, '0');
+ (void) tostring(buffer+18, (int)ptr->prev, 8, B_HEX, '0');
+ (void) tostring(buffer+27, (int)ptr->flag, 10, B_HEX, '0');
+ (void) tostring(buffer+38, (int)ptr->s.size, 8, B_DEC, ' ');
+ (void) tostring(buffer+47, (int)ptr->s.size, 8, B_HEX, '0');
+ (void) tostring(buffer+57, (int)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) tostring(buffer, (int) &malloc_start, 8, B_HEX, '0');
+ buffer[8] = '\n';
+ WRITEOUT(fd,buffer,9);
+
+ WRITEOUT(fd,"Malloc end: ", 19);
+ (void) tostring(buffer, (int) malloc_end, 8, B_HEX, '0');
+ buffer[8] = '\n';
+ WRITEOUT(fd,buffer,9);
+
+ WRITEOUT(fd,"Malloc data start: ", 19);
+ (void) tostring(buffer, (int) malloc_data_start, 8, B_HEX, '0');
+ buffer[8] = '\n';
+ WRITEOUT(fd,buffer,9);
+
+ WRITEOUT(fd,"Malloc data end: ", 19);
+ (void) tostring(buffer, (int) malloc_data_end, 8, B_HEX, '0');
+ buffer[8] = '\n';
+ WRITEOUT(fd,buffer,9);
+
+} /* malloc_dump(... */
+
+
diff --git a/dmake/dbug/malloc/free.c b/dmake/dbug/malloc/free.c
new file mode 100644
index 000000000000..a8fc3ca259b6
--- /dev/null
+++ b/dmake/dbug/malloc/free.c
@@ -0,0 +1,150 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+#include <stdio.h>
+#include "malloc.h"
+#include "debug.h"
+
+/*
+ * Function: free()
+ *
+ * Purpose: to deallocate malloced data
+ *
+ * Arguments: ptr - pointer to data area to deallocate
+ *
+ * Returns: nothing of any value
+ *
+ * Narrative:
+ * verify pointer is within malloc region
+ * get mlist pointer from passed address
+ * verify magic number
+ * verify inuse flag
+ * verify pointer connections with surrounding segments
+ * turn off inuse flag
+ * verify no data overrun into non-malloced area at end of segment
+ * IF possible join segment with next segment
+ * IF possible join segment with previous segment
+ * Clear all data in segment (to make sure it isn't reused)
+ *
+ */
+#ifndef lint
+static
+char rcs_hdr[] = "$Id: free.c,v 1.2 2006-07-25 10:07:53 rt Exp $";
+#endif
+
+void
+free(cptr)
+ char * cptr;
+{
+ char * func = "free";
+ int i;
+ extern int malloc_checking;
+ extern struct mlist * malloc_end;
+ extern int malloc_errno;
+ extern char * malloc_data_end;
+ extern char * malloc_data_start;
+ void malloc_join();
+ void malloc_memset();
+ struct mlist * oldptr;
+ struct mlist * ptr;
+
+ /*
+ * IF malloc chain checking is on, go do it.
+ */
+ if( malloc_checking )
+ {
+ (void) malloc_chain_check(1);
+ }
+
+ /*
+ * verify that cptr is within the malloc region...
+ */
+ if( cptr < malloc_data_start || cptr > malloc_data_end )
+ {
+ malloc_errno = M_CODE_BAD_PTR;
+ malloc_warning(func);
+ 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_MAGIC )
+ {
+ malloc_errno = M_CODE_BAD_MAGIC;
+ malloc_warning(func);
+ return;
+ }
+
+ if( ! (ptr->flag & M_INUSE) )
+ {
+ malloc_errno = M_CODE_NOT_INUSE;
+ malloc_warning(func);
+ return;
+ }
+
+ if( (ptr->prev && (ptr->prev->next != ptr) ) ||
+ (ptr->next && (ptr->next->prev != ptr) ) ||
+ ((ptr->next == NULL) && (ptr->prev == NULL)) )
+ {
+ malloc_errno = M_CODE_BAD_CONNECT;
+ malloc_warning(func);
+ 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_errno = M_CODE_OVERRUN;
+ malloc_warning(func);
+ 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,(int)ptr->s.size);
+
+}
+
diff --git a/dmake/dbug/malloc/m_init.c b/dmake/dbug/malloc/m_init.c
new file mode 100644
index 000000000000..d4fdc0788f4b
--- /dev/null
+++ b/dmake/dbug/malloc/m_init.c
@@ -0,0 +1,79 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+#include <stdio.h>
+#include "malloc.h"
+
+/*
+ * Function: malloc_init()
+ *
+ * Purpose: to initialize the pointers and variables use by the
+ * malloc() debugging library
+ *
+ * Arguments: none
+ *
+ * Returns: nothing of any value
+ *
+ * Narrative: Just initialize all the needed variables. Use mallopt
+ * to set options taken from the environment.
+ *
+ */
+#ifndef lint
+static
+char rcs_hdr[] = "$Id: m_init.c,v 1.2 2006-07-25 10:08:07 rt Exp $";
+#endif
+
+void
+malloc_init()
+{
+ char * cptr;
+ char * getenv();
+ union malloptarg m;
+ extern char * malloc_data_end;
+ extern char * malloc_data_start;
+ extern struct mlist * malloc_end;
+ extern struct mlist malloc_start;
+ char * sbrk();
+
+ /*
+ * If already initialized...
+ */
+ if( malloc_data_start != (char *) 0)
+ {
+ return;
+ }
+
+
+ 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 )
+ {
+ m.i = atoi(cptr);
+ (void) mallopt(MALLOC_WARN,m);
+ }
+
+ if( (cptr=getenv("MALLOC_FATAL")) != NULL)
+ {
+ m.i = atoi(cptr);
+ (void) mallopt(MALLOC_FATAL,m);
+ }
+
+ if( (cptr=getenv("MALLOC_CKCHAIN")) != NULL)
+ {
+ m.i = atoi(cptr);
+ (void) mallopt(MALLOC_CKCHAIN,m);
+ }
+
+ if( (cptr=getenv("MALLOC_ERRFILE")) != NULL)
+ {
+ m.str = cptr;
+ (void) mallopt(MALLOC_ERRFILE,m);
+ }
+
+}
+
diff --git a/dmake/dbug/malloc/m_perror.c b/dmake/dbug/malloc/m_perror.c
new file mode 100644
index 000000000000..b5620182ac4e
--- /dev/null
+++ b/dmake/dbug/malloc/m_perror.c
@@ -0,0 +1,73 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+
+#ifndef lint
+static
+char rcsid[] = "$Id: m_perror.c,v 1.2 2006-07-25 10:08:21 rt Exp $";
+#endif
+
+/*
+ * malloc errno error strings...
+ */
+
+char *malloc_err_strings[] =
+{
+ "No errors",
+ "Malloc chain is corrupted, pointers out of order",
+ "Malloc chain is corrupted, end before end pointer",
+ "Pointer is not within malloc area",
+ "Malloc region does not have valid magic number in header",
+ "Pointers between this segment and ajoining segments are invalid",
+ "Data has overrun beyond requested number of bytes",
+ "Data in free'd area has been modified",
+ "Data are is not in use (can't be freed or realloced)",
+ "Unable to get additional memory from the system",
+ "Pointer within malloc region, but outside of malloc data bounds",
+ (char *) 0
+};
+
+/*
+ * Function: malloc_perror()
+ *
+ * Purpose: to print malloc_errno error message
+ *
+ * Arguments: str - string to print with error message
+ *
+ * Returns: nothing of any value
+ *
+ * Narrative:
+ */
+void
+malloc_perror(str)
+ char * str;
+{
+ extern int malloc_errno;
+ register char * s;
+ register char * t;
+
+ if( str && *str)
+ {
+ for(s=str; *s; s++)
+ {
+ /* do nothing */;
+ }
+
+ (void) write(2,str,(unsigned)(s-str));
+ (void) write(2,": ",(unsigned)2);
+ }
+
+ t = malloc_err_strings[malloc_errno];
+
+ for(s=t; *s; s++)
+ {
+ /* do nothing */;
+ }
+
+ (void) write(2,t,(unsigned)(s-t));
+
+ (void) write(2,"\n",(unsigned)1);
+}
+
diff --git a/dmake/dbug/malloc/makefile b/dmake/dbug/malloc/makefile
new file mode 100644
index 000000000000..88395c7b8f6c
--- /dev/null
+++ b/dmake/dbug/malloc/makefile
@@ -0,0 +1,77 @@
+#
+# (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+# You may copy, distribute, and use this software as long as this
+# copyright statement is not removed.
+#
+#
+# This is the Makefile for the malloc debugging library
+#
+# $Id: makefile,v 1.1.1.1 2000-09-22 15:33:26 hr Exp $
+#
+CC=cc
+# for System V systems use this CFLAGS
+#CFLAGS=-g -DSYS5
+# else for BSD use:
+#CFLAGS=-g
+LINT=lint
+SHARCMD=shar -o mallocshar -l50 -x -a -n Malloclib
+SHELL=/bin/sh
+
+LIB=libmalloc.a
+
+SRCS= malloc.c \
+ free.c \
+ realloc.c \
+ calloc.c \
+ string.c \
+ mlc_chk.c \
+ mlc_chn.c \
+ memory.c \
+ tostring.c \
+ m_perror.c \
+ m_init.c \
+ mallopt.c \
+ dump.c
+
+OBJS= malloc.o \
+ free.o \
+ realloc.o \
+ calloc.o \
+ string.o \
+ mlc_chk.o \
+ mlc_chn.o \
+ memory.o \
+ tostring.o \
+ m_perror.o \
+ m_init.o \
+ mallopt.o \
+ dump.o
+
+TESTS=testmlc testmem
+
+all: $(LIB) $(TESTS)
+
+clean:
+ rm -f $(TESTS) pgm $(LIB) *.o *.ln
+
+sharfile:
+ $(SHARCMD) Makefile README patchlevel *.[ch3]
+
+$(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
+
+testmlc: $(LIB) testmlc.o
+ $(CC) -o $@ testmlc.o $(LIB)
+
+testmem: $(LIB) testmem.o
+ $(CC) -o $@ testmem.o $(LIB)
+
+lint:
+ $(LINT) $(CFLAGS) $(SRCS) testmlc.c testmem.c
+
+
+$(OBJS): malloc.h
+
+tostring.o malloc.o dump.o: tostring.h
diff --git a/dmake/dbug/malloc/malloc.3 b/dmake/dbug/malloc/malloc.3
new file mode 100644
index 000000000000..f5e1d2dc0dab
--- /dev/null
+++ b/dmake/dbug/malloc/malloc.3
@@ -0,0 +1,223 @@
+.TH MALLOC 3 "" "" "1.0"
+.ds ]T
+.\"/*
+.\" * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+.\" * You may copy, distribute, and use this software as long as this
+.\" * copyright statement is not removed.
+.\" */
+.\" $Id: malloc.3,v 1.1.1.1 2000-09-22 15:33:26 hr Exp $
+.SH NAME
+malloc \t- debugging malloc library
+.SH SYNOPSIS
+.ft B
+.nf
+#include <malloc.h>
+
+char * calloc(nelem,elsize);
+void free(ptr);
+char * malloc(size);
+int malloc_chain_check(flag);
+void malloc_dump(fd);
+int mallopt(cmd,val)
+char * realloc(ptr,size);
+
+int cmd,fd,flag;
+unsigned elsize,nelem,size;
+char * ptr;
+union malloptarg val;
+
+.fi
+.ft R
+.SH DESCRIPTION
+This malloc library is a replacement for the standard library to be used
+during software development/debugging. See the standard malloc(3) pages
+for more information on the use of the following functions:
+.nf
+.in +.5i
+calloc(), free(), malloc(), realloc()
+.in -.5i
+.fi
+.sp
+This library differs from the standard malloc library in the
+following ways:
+.P
+1. Each malloc segment contains a magic number so that free can
+verify that the pointer passed points to a valid malloc segment.
+.P
+2. Each malloc segment is filled with a non-zero pattern so that code that
+depends upon malloc segments being null will fail.
+.P
+3. The size of each segment will be at least 1 byte larger than requested
+and the extra bytes will be filled with a non-zero pattern. When free is
+called, it will verify that you did not go beyond the number of bytes
+you asked for.
+.P
+4. When a segment is freed, it will be filled with a different non-zero pattern
+to ensure that the program doesn't depend upon the use of already freed data.
+.P
+5. Whenever any of the string or memory functions (str*, b*, mem*) are
+called with a pointer that is within the malloc arena, the operation is
+checked to verify that it does not overrun the malloced segment. A failure
+of this check is considered a "warning level error" (described later) and
+is handled accordingly.
+.P
+7. Run time checking can include verification of the malloc chain at each
+and every call to one of the malloc functions or manually by calling the
+malloc_chain_check function.
+.P
+6. When a problem is found, the action taken is specified at runtime by
+environment variables or at compile time by the use of the mallopt()
+function.
+.P
+There are two arbitrary levels of errors, warning and fatal, that this
+library will detect. They are broken down as follows:
+.P
+.nf
+.in +.25i
+Warning messages include:
+.sp
+.in +.5i
+.ti -.25i
+Calling free with a bad pointer
+.br
+.ti -.25i
+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.
+.sp
+.in -.5i
+Fatal errors are:
+.in +.5i
+.ti -.25i
+Detectable corruption to the malloc chain.
+.in -.5i
+.in -.25i
+.P
+The error handling for each level (warning or fatal) are specified using
+environment variables or mallopt(). The coding for the error handling is
+as follows:
+.sp
+.nf
+.in +.5i
+.ti -.25i
+ 0 - continue operations
+.ti -.25i
+ 1 - drop core and exit
+.ti -.25i
+ 2 - just exit
+.ti -.25i
+ 3 - drop core, but continue executing. Core files will
+be placed into core.[PID].[counter] i.e: core.00123.001
+.ti -.25i
+128 - dump malloc chain and continue
+.ti -.25i
+129 - dump malloc chain, dump core, and exit
+.ti -.25i
+130 - dump malloc chain, exit
+.ti -.25i
+131 - dump malloc chain, dump core, continue processing
+.in -.5i
+.P
+In addition error messages can be placed into an error file.
+.P
+\fBmalloc_opt\fP() is used to set the malloc debugging options. The
+following options can be set:
+.br
+.sp
+.in +.5i
+MALLOC_WARN - set the error handling for warning level errors. \fBval.i\fP is
+an integer that can contain any one of the following values:
+.sp
+.in +.5i
+M_HANDLE_IGNORE - ignore error
+.br
+M_HANDLE_ABORT - drop core and exit
+.br
+M_HANDLE_EXIT - just exit (no core drop)
+.br
+M_HANDLE_CORE - drop core, but keep on going
+.br
+.in -.5i
+.sp
+In addition, M_HANDLE_DUMP may be or'd in to cause a dump of the current
+malloc chain.
+.br
+.sp
+MALLOC_FATAL - set the error handling for fatal level errors. \fBval.i\fP is
+equivalent to \fBval.i\fP for MALLOC_WARN.
+.br
+.sp
+MALLOC_ERRFILE - set the destination for malloc error messages. \fBval.str\fP
+is a pointer to a character string containing the name of the file to be used
+for error messages.
+.br
+.sp
+MALLOC_CKCHAIN - set the malloc chain checking flag. If \fBval.i\fP is
+non-zero, chain checking at every call to malloc is turned on.
+.br
+.sp
+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:
+.sp
+.nf
+.in +.5i
+#include <malloc.h>
+malloc_opt(MALLOC_WARN,131);
+malloc_opt(MALLOC_FATAL,1);
+malloc_opt(MALLOC_ERRFILE,"malloc_log");
+.in -.5i
+.fi
+.in -.5i
+.sp
+\fBmalloc_opt\fP() can be used to set/alter the debugging options at any
+time.
+.P
+\fBmalloc_dump\fP() will dump a table of the malloc arena showing all
+allocated/freed segments and the first few bytes of data in each segment.
+\fBfd\fP is the file descriptor to write the data to.
+.P
+\fBmalloc_chain_check\fP() will check the status of the malloc arena.
+If \fBflag\fP is non-zero, an error found in the chain will cause a
+fatal error. \fBmalloc_chain_check\fP() returns zero when there are no
+problems found in the malloc chain, non-zero otherwise.
+.SH "ENVIRONMENT VARIABLES"
+Environment variables can be used to control error handling, error logging
+and malloc chain checking at run time. The following environment variables
+are used:
+.P
+MALLOC_WARN - specifies the error handling for warning errors
+.br
+MALLOC_FATAL - specifies the error handling for fatal errors
+.br
+MALLOC_ERRFILE - specifies the error log file for error messages.
+.br
+MALLOC_CKCHAIN - if 1, turns on malloc chain checking at every call to any
+of the malloc functions.
+.P
+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:
+.sp
+.nf
+.in +.5i
+MALLOC_WARN=131
+MALLOC_FATAL=1
+MALLOC_ERRFILE=malloc_log
+
+export MALLOC_WARN MALLOC_FATAL MALLOC_ERRFILE
+.in -.5i
+.fi
+.SH WARNINGS
+This malloc library and it's associated string and memory functions are
+much less efficient than the standard functions due in part to the extra
+error checking. You do not want to use this library when generating a
+production (i.e. releasable) version of your software. It should only
+be used during development and testing.
+.SH SEE ALSO
+stat(2)
+.SH AUTHOR
+Conor P. Cahill
+Virtual Technologies Incorporated
+.sp
+uunet!virtech!cpcahil
diff --git a/dmake/dbug/malloc/malloc.c b/dmake/dbug/malloc/malloc.c
new file mode 100644
index 000000000000..ff84e3efce9f
--- /dev/null
+++ b/dmake/dbug/malloc/malloc.c
@@ -0,0 +1,627 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+#include <stdio.h>
+#include <fcntl.h>
+#include "malloc.h"
+#include "tostring.h"
+
+/*
+ * Function: malloc()
+ *
+ * Purpose: memory allocator
+ *
+ * Arguments: size - size of data area needed
+ *
+ * Returns: pointer to allocated area, or NULL if unable
+ * to allocate addtional data.
+ *
+ * Narrative:
+ *
+ */
+#ifndef lint
+static
+char rcs_hdr[] = "$Id: malloc.c,v 1.2 2006-07-25 10:08:36 rt Exp $";
+#endif
+
+extern int malloc_checking;
+char * malloc_data_start;
+char * malloc_data_end;
+struct mlist * malloc_end;
+int malloc_errfd = 2;
+int malloc_errno;
+int malloc_fatal_level = M_HANDLE_CORE;
+struct mlist malloc_start;
+int malloc_warn_level;
+void malloc_memset();
+
+char *
+malloc(size)
+ unsigned int size;
+{
+ char * func = "malloc";
+ char * getenv();
+ void malloc_fatal();
+ void malloc_init();
+ void malloc_split();
+ void malloc_warning();
+ unsigned int need;
+ struct mlist * oldptr;
+ struct mlist * ptr;
+ char * sbrk();
+
+ /*
+ * If this is the first call to malloc...
+ */
+ if( malloc_data_start == (char *) 0 )
+ {
+ malloc_init();
+ }
+
+ /*
+ * If malloc chain checking is on, go do it.
+ */
+ if( malloc_checking )
+ {
+ (void) malloc_chain_check(1);
+ }
+
+ /*
+ * always make sure there is at least on extra byte in the malloc
+ * area so that we can verify that the user does not overrun the
+ * data area.
+ */
+ size++;
+
+ /*
+ * 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_errno = M_CODE_CHAIN_BROKE;
+ malloc_fatal(func);
+ return(NULL);
+ }
+ oldptr = ptr;
+ }
+ else if( oldptr != malloc_end )
+ {
+ /*
+ * This should never happen. If it does, then
+ * we got a real problem.
+ */
+ malloc_errno = M_CODE_NO_END;
+ malloc_fatal(func);
+ return(NULL);
+ }
+
+
+ /*
+ * 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 > 10*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((int)need);
+ if( ptr == (struct mlist *) -1 )
+ {
+ malloc_errno = M_CODE_NOMORE_MEM;
+ malloc_fatal(func);
+ }
+ malloc_data_end = sbrk((int)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);
+
+ /*
+ * re-adjust the requested size so that it is what the user
+ * actually requested...
+ */
+
+ ptr->r_size--;
+
+ /*
+ * 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,(int)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:
+ * get the needed size of the module
+ * round the size up to appropriat boundry
+ * calculate amount of left over space
+ * if there is enough left over space
+ * create new malloc block out of remainder
+ * if next block is free
+ * join the two blocks together
+ * fill new empty block with free space filler
+ * re-adjust pointers and size of current malloc block
+ *
+ *
+ *
+ * Mod History:
+ * 90/01/27 cpcahil Initial revision.
+ */
+void
+malloc_split(ptr)
+ struct mlist * ptr;
+{
+ extern struct mlist * malloc_end;
+ void malloc_join();
+ int rest;
+ int size;
+ struct mlist * tptr;
+
+ 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, (int)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, (int)(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)
+ */
+
+void free();
+int strcmp();
+int memcmp();
+char * realloc();
+
+void (*malloc_void_funcs[])() =
+{
+ free,
+};
+
+int (*malloc_int_funcs[])() =
+{
+ strcmp,
+ memcmp,
+};
+
+char * (*malloc_char_star_funcs[])() =
+{
+ realloc,
+};
+
+/*
+ * This is malloc's own memset which is used without checking the parameters.
+ */
+
+void
+malloc_memset(ptr,byte,len)
+ char * ptr;
+ char byte;
+ int len;
+{
+
+ while(len-- > 0)
+ {
+ *ptr++ = byte;
+ }
+
+} /* malloc_memset(... */
+
+/*
+ * Function: malloc_fatal()
+ *
+ * Purpose: to display fatal error message and take approrpriate action
+ *
+ * Arguments: funcname - name of function calling this routine
+ *
+ * Returns: nothing of any value
+ *
+ * Narrative:
+ *
+ * Notes: This routine does not make use of any libc functions to build
+ * and/or disply the error message. This is due to the fact that
+ * we are probably at a point where malloc is having a real problem
+ * and we don't want to call any function that may use malloc.
+ */
+void
+malloc_fatal(funcname)
+ char * funcname;
+{
+ char errbuf[128];
+ void exit();
+ void malloc_err_handler();
+ extern char * malloc_err_strings[];
+ extern int malloc_errno;
+ extern int malloc_fatal_level;
+ char * s;
+ char * t;
+
+ s = errbuf;
+ t = "Fatal error: ";
+ while( *s = *t++)
+ {
+ s++;
+ }
+ t = funcname;
+ while( *s = *t++)
+ {
+ s++;
+ }
+
+ t = "(): ";
+ while( *s = *t++)
+ {
+ s++;
+ }
+
+ t = malloc_err_strings[malloc_errno];
+ while( *s = *t++)
+ {
+ s++;
+ }
+
+ *(s++) = '\n';
+
+ if( write(malloc_errfd,errbuf,(unsigned)(s-errbuf)) != (s-errbuf))
+ {
+ (void) write(2,"I/O error to error file\n",(unsigned)24);
+ exit(110);
+ }
+ malloc_err_handler(malloc_fatal_level);
+
+} /* malloc_fatal(... */
+
+/*
+ * Function: malloc_warning()
+ *
+ * Purpose: to display warning error message and take approrpriate action
+ *
+ * Arguments: funcname - name of function calling this routine
+ *
+ * Returns: nothing of any value
+ *
+ * Narrative:
+ *
+ * Notes: This routine does not make use of any libc functions to build
+ * and/or disply the error message. This is due to the fact that
+ * we are probably at a point where malloc is having a real problem
+ * and we don't want to call any function that may use malloc.
+ */
+void
+malloc_warning(funcname)
+ char * funcname;
+{
+ char errbuf[128];
+ void exit();
+ void malloc_err_handler();
+ extern char * malloc_err_strings[];
+ extern int malloc_errno;
+ extern int malloc_warn_level;
+ char * s;
+ char * t;
+
+ s = errbuf;
+ t = "Warning: ";
+ while( *s = *t++)
+ {
+ s++;
+ }
+ t = funcname;
+ while( *s = *t++)
+ {
+ s++;
+ }
+
+ t = "(): ";
+ while( *s = *t++)
+ {
+ s++;
+ }
+
+ t = malloc_err_strings[malloc_errno];
+ while( *s = *t++)
+ {
+ s++;
+ }
+
+ *(s++) = '\n';
+
+ if( write(malloc_errfd,errbuf,(unsigned)(s-errbuf)) != (s-errbuf))
+ {
+ (void) write(2,"I/O error to error file\n",(unsigned)24);
+ exit(110);
+ }
+
+ malloc_err_handler(malloc_warn_level);
+
+} /* malloc_warning(... */
+
+/*
+ * Function: malloc_err_handler()
+ *
+ * Purpose: to take the appropriate action for warning and/or fatal
+ * error conditions.
+ *
+ * Arguments: level - error handling level
+ *
+ * Returns: nothing of any value
+ *
+ * Narrative:
+ *
+ * Notes: This routine does not make use of any libc functions to build
+ * and/or disply the error message. This is due to the fact that
+ * we are probably at a point where malloc is having a real problem
+ * and we don't want to call any function that may use malloc.
+ */
+void
+malloc_err_handler(level)
+{
+ void exit();
+ void malloc_dump();
+ extern int malloc_errfd;
+
+ if( level & M_HANDLE_DUMP )
+ {
+ malloc_dump(malloc_errfd);
+ }
+
+ switch( level & ~M_HANDLE_DUMP )
+ {
+ /*
+ * If we are to drop a core file and exit
+ */
+ case M_HANDLE_ABORT:
+ (void) abort();
+ break;
+
+ /*
+ * If we are to exit..
+ */
+ case M_HANDLE_EXIT:
+ exit(200);
+ break;
+
+#ifndef __MSDOS__
+ /*
+ * If we are to dump a core, but keep going on our merry way
+ */
+ case M_HANDLE_CORE:
+ {
+ int pid;
+
+ /*
+ * fork so child can abort (and dump core)
+ */
+ if( (pid = fork()) == 0 )
+ {
+ (void) write(2,"Child dumping core\n",
+ (unsigned)9);
+ (void) abort();
+ }
+
+ /*
+ * wait for child to finish dumping core
+ */
+ while( 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)tostring(filenam+5,getpid(),
+ 5, B_DEC, '0');
+ filenam[10] = '.';
+ (void)tostring(filenam+11,corecnt++,
+ 3, B_DEC, '0');
+ filenam[14] = '\0';
+ (void) unlink(filenam);
+ if( link("core",filenam) == 0)
+ {
+ (void) unlink("core");
+ }
+ }
+ }
+#endif
+
+
+ /*
+ * If we are to just ignore the error and keep on processing
+ */
+ case M_HANDLE_IGNORE:
+ break;
+
+ } /* switch(... */
+
+} /* malloc_err_handler(... */
+
diff --git a/dmake/dbug/malloc/malloc.h b/dmake/dbug/malloc/malloc.h
new file mode 100644
index 000000000000..ed8c34f2a333
--- /dev/null
+++ b/dmake/dbug/malloc/malloc.h
@@ -0,0 +1,85 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+/*
+ * $Id: malloc.h,v 1.2 2006-07-25 10:08:50 rt Exp $
+ */
+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
+
+/*
+ * Mallopt commands and defaults
+ */
+
+#define MALLOC_WARN 1 /* set malloc warning handling */
+#define MALLOC_FATAL 2 /* set malloc fatal handling */
+#define MALLOC_ERRFILE 3 /* specify malloc error file */
+#define MALLOC_CKCHAIN 4 /* turn on chain checking */
+union malloptarg
+{
+ int i;
+ char * str;
+};
+
+/*
+ * Malloc warning/fatal error codes
+ */
+
+#define M_CODE_CHAIN_BROKE 1 /* malloc chain is broken */
+#define M_CODE_NO_END 2 /* chain end != endptr */
+#define M_CODE_BAD_PTR 3 /* pointer not in malloc area */
+#define M_CODE_BAD_MAGIC 4 /* bad magic number in header */
+#define M_CODE_BAD_CONNECT 5 /* chain poingers corrupt */
+#define M_CODE_OVERRUN 6 /* data overrun in malloc seg */
+#define M_CODE_REUSE 7 /* reuse of freed area */
+#define M_CODE_NOT_INUSE 8 /* pointer is not in use */
+#define M_CODE_NOMORE_MEM 9 /* no more memory available */
+#define M_CODE_OUTOF_BOUNDS 10 /* gone beyound bounds */
+
+void malloc_warning();
+void malloc_fatal();
+void malloc_check_data();
+void malloc_check_str();
+void malloc_verify();
+
diff --git a/dmake/dbug/malloc/mallopt.c b/dmake/dbug/malloc/mallopt.c
new file mode 100644
index 000000000000..d70daf88647a
--- /dev/null
+++ b/dmake/dbug/malloc/mallopt.c
@@ -0,0 +1,98 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+#include <stdio.h>
+#include <fcntl.h>
+#include "malloc.h"
+
+/*
+ * Function: mallopt()
+ *
+ * Purpose: to set options for the malloc debugging library
+ *
+ * Arguments: none
+ *
+ * Returns: nothing of any value
+ *
+ * Narrative:
+ *
+ */
+
+#ifndef lint
+static
+char rcs_hdr[] = "$Id: mallopt.c,v 1.2 2006-07-25 10:09:05 rt Exp $";
+#endif
+
+int
+mallopt(cmd,value)
+ int cmd;
+ union malloptarg value;
+{
+ int i;
+ extern int malloc_checking;
+ extern char * malloc_data_start;
+ extern int malloc_errfd;
+ extern int malloc_fatal_level;
+ void malloc_init();
+ extern int malloc_warn_level;
+ register char * s;
+
+ /*
+ * If not initialized...
+ */
+ if( malloc_data_start == (char *) 0)
+ {
+ malloc_init();
+ }
+
+
+ switch(cmd)
+ {
+ case MALLOC_WARN:
+ malloc_warn_level = value.i;
+ break;
+
+ case MALLOC_FATAL:
+ malloc_fatal_level = value.i;
+ break;
+
+ case MALLOC_CKCHAIN:
+ malloc_checking = value.i;
+ break;
+
+ case MALLOC_ERRFILE:
+
+ i = open(value.str,O_CREAT|O_APPEND|O_WRONLY,0666);
+ if( i == -1 )
+ {
+ (void) write(2,
+ "Unable to open malloc error file: ",
+ (unsigned) 34);
+ for(s=value.str; *s; s++)
+ {
+ /* do nothing */;
+ }
+ (void) write(2,value.str,
+ (unsigned)(s-value.str));
+ (void) write(2,"\n",(unsigned)1);
+ }
+ else
+ {
+ if( malloc_errfd != 2 )
+ {
+ (void) close(malloc_errfd);
+ }
+ malloc_errfd = i;
+ }
+
+ break;
+
+ default:
+ return(1);
+ }
+
+ return(0);
+}
+
diff --git a/dmake/dbug/malloc/memory.c b/dmake/dbug/malloc/memory.c
new file mode 100644
index 000000000000..b2087a76f5af
--- /dev/null
+++ b/dmake/dbug/malloc/memory.c
@@ -0,0 +1,195 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+
+#ifndef lint
+static
+char rcs_hdr[] = "$Id: memory.c,v 1.2 2006-07-25 10:09:19 rt Exp $";
+#endif
+
+void malloc_check_data();
+
+char *
+memccpy(ptr1, ptr2, ch, len)
+ register char * ptr1;
+ register char * ptr2;
+ int len;
+ int ch;
+{
+ int check;
+ 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++)
+ {
+ }
+ if( ptr2[i] == ch )
+ {
+ check = i+1;
+ }
+ else
+ {
+ check = len;
+ }
+
+ malloc_check_data("memccpy", ptr1, check);
+ malloc_check_data("memccpy", ptr2, check);
+
+ /*
+ * if we found the character...
+ */
+
+ if( i < len )
+ {
+ rtn = ptr1+i+1;
+ i++;
+ }
+ 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] != (char) 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 the normal memcpy does not guarrantee that it will
+ * handle overlapping memory correctly, we will try...
+ */
+ if( ptr1 > ptr2 && ptr1 < (ptr2+len))
+ {
+ ptr1 += (len-1);
+ ptr2 += (len-1);
+ while( len-- > 0 )
+ {
+ *(ptr1--) = *(ptr2--);
+ }
+ }
+ else
+ {
+ while( len-- > 0 )
+ {
+ *(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 >= 0 && (*ptr1 == *ptr2) )
+ {
+ ptr1++;
+ ptr2++;
+ }
+
+ /*
+ * If stopped by len, return zero
+ */
+ if( len < 0 )
+ {
+ return(0);
+ }
+
+ 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);
+}
+
+char *
+bcopy(ptr2,ptr1,len)
+ char * ptr2;
+ char * ptr1;
+ int len;
+{
+ return(memcpy(ptr1,ptr2,len));
+}
+
+char *
+bzero(ptr1,len)
+ char * ptr1;
+ int len;
+{
+ return(memset(ptr1,'\0',len));
+}
+
+int
+bcmp(ptr2, ptr1, len)
+ char * ptr1;
+ char * ptr2;
+ int len;
+{
+ return( memcmp(ptr1,ptr2,len) );
+}
+
diff --git a/dmake/dbug/malloc/mlc_chk.c b/dmake/dbug/malloc/mlc_chk.c
new file mode 100644
index 000000000000..08a01172cb66
--- /dev/null
+++ b/dmake/dbug/malloc/mlc_chk.c
@@ -0,0 +1,256 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+
+#include <stdio.h>
+#include "malloc.h"
+#include "debug.h"
+
+#ifndef lint
+static
+char rcs_hdr[] = "$Id: mlc_chk.c,v 1.2 2006-07-25 10:09:34 rt Exp $";
+#endif
+
+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_strn()
+ *
+ * Arguments: func - name of function calling this routine
+ * str - pointer to area to check
+ * len - max length of string
+ *
+ * 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.
+ * 90/08/29 cpcahil added length (for strn* functions)
+ */
+void
+malloc_check_strn(func,str,len)
+ char * func;
+ char * str;
+ int len;
+{
+ register int i;
+ static int layers;
+ register char * s;
+
+ if( (layers++ == 0) && malloc_in_arena(str) )
+ {
+ for( s=str,i=0; (i < len) && *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_end;
+ extern int malloc_errno;
+ extern struct mlist malloc_start;
+ 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)) )
+ {
+ DEBUG4(0,"pointer not within region 0x%x-0x%x, 0x%x-0x%x",
+ ptr, ptr+len, mptr->data, mptr->data+mptr->r_size);
+
+ malloc_errno = M_CODE_OUTOF_BOUNDS;
+ malloc_warning(func);
+ }
+
+ return;
+}
+
diff --git a/dmake/dbug/malloc/mlc_chn.c b/dmake/dbug/malloc/mlc_chn.c
new file mode 100644
index 000000000000..3f24333611f9
--- /dev/null
+++ b/dmake/dbug/malloc/mlc_chn.c
@@ -0,0 +1,188 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+#include <stdio.h>
+#include <fcntl.h>
+#include "malloc.h"
+
+/*
+ * Function: malloc_chain_check()
+ *
+ * Purpose: to verify malloc chain is intact
+ *
+ * Arguments: todo - 0 - just check and return status
+ * 1 - call malloc_warn if error detected
+ *
+ * Returns: 0 - malloc chain intact & no overflows
+ * other - problems detected in malloc chain
+ *
+ * Narrative:
+ *
+ * Notes: If todo is non-zero the malloc_warn function, when called
+ * may not return (i.e. it may exit)
+ *
+ */
+#ifndef lint
+static
+char rcs_hdr[] = "$Id: mlc_chn.c,v 1.1.1.1 2000-09-22 15:33:26 hr Exp $";
+#endif
+
+
+int
+malloc_chain_check(todo)
+ int todo;
+{
+ char * func = "malloc_chain_check";
+ int i;
+ extern char * malloc_data_start;
+ extern char * malloc_data_end;
+ extern struct mlist * malloc_end;
+ extern int malloc_errno;
+ extern struct mlist malloc_start;
+ struct mlist * oldptr;
+ struct mlist * ptr;
+ int rtn = 0;
+
+ oldptr = &malloc_start;
+ for(ptr = malloc_start.next; ; 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_errno = M_CODE_CHAIN_BROKE;
+ if( todo )
+ {
+ malloc_fatal(func);
+ }
+ rtn++;
+ break;
+ }
+ oldptr = ptr;
+ }
+ else
+ {
+ if( oldptr != malloc_end )
+ {
+ /*
+ * This should never happen. If it does, then
+ * we got a real problem.
+ */
+ malloc_errno = M_CODE_NO_END;
+ if( todo )
+ {
+ malloc_fatal(func);
+ }
+ rtn++;
+ }
+ break;
+ }
+
+ /*
+ * verify that ptr is within the malloc region...
+ * since we started within the malloc chain this should never
+ * happen.
+ */
+
+ if( ((char *)ptr < malloc_data_start) ||
+ ((char *)ptr > malloc_data_end) )
+ {
+ malloc_errno = M_CODE_BAD_PTR;
+ if( todo )
+ {
+ malloc_fatal(func);
+ }
+ rtn++;
+ break;
+ }
+
+ /*
+ * verify magic flag is set
+ */
+
+ if( (ptr->flag&M_MAGIC) != M_MAGIC )
+ {
+ malloc_errno = M_CODE_BAD_MAGIC;
+ if( todo )
+ {
+ malloc_warning(func);
+ }
+ rtn++;
+ continue;
+ }
+
+ /*
+ * verify segments are correctly linked together
+ */
+
+ if( (ptr->prev && (ptr->prev->next != ptr) ) ||
+ (ptr->next && (ptr->next->prev != ptr) ) ||
+ ((ptr->next == NULL) && (ptr->prev == NULL)) )
+ {
+ malloc_errno = M_CODE_BAD_CONNECT;
+ if( todo )
+ {
+ malloc_warning(func);
+ }
+ rtn++;
+ continue;
+ }
+
+ /*
+ * If this segment is allocated
+ */
+
+ if( (ptr->flag & M_INUSE) != 0 )
+ {
+ /*
+ * verify no overflow of data area
+ */
+
+ for(i=ptr->r_size; i < ptr->s.size; i++)
+ {
+ if( ptr->data[i] != M_FILL )
+ {
+ malloc_errno = M_CODE_OVERRUN;
+ if( todo )
+ {
+ malloc_warning(func);
+ }
+ rtn++;
+ break;
+ }
+ }
+ }
+ else /* it's not allocated so */
+ {
+ /*
+ * verify no reuse of freed data blocks
+ */
+
+ for(i=0; i < ptr->s.size; i++)
+ {
+ if( ptr->data[i] != M_FREE_FILL )
+ {
+ malloc_errno = M_CODE_REUSE;
+ if( todo )
+ {
+ malloc_warning(func);
+ }
+ rtn++;
+ break;
+ }
+ }
+ }
+
+ } /* for(... */
+
+ return(rtn);
+
+} /* malloc_chain_check(... */
diff --git a/dmake/dbug/malloc/patchlev b/dmake/dbug/malloc/patchlev
new file mode 100644
index 000000000000..00750edc07d6
--- /dev/null
+++ b/dmake/dbug/malloc/patchlev
@@ -0,0 +1 @@
+3
diff --git a/dmake/dbug/malloc/realloc.c b/dmake/dbug/malloc/realloc.c
new file mode 100644
index 000000000000..2801cd86212d
--- /dev/null
+++ b/dmake/dbug/malloc/realloc.c
@@ -0,0 +1,180 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+#include <stdio.h>
+#include "malloc.h"
+
+/*
+ * Function: realloc()
+ *
+ * Purpose: to re-allocate a data area.
+ *
+ * Arguments: cptr - pointer to area to reallocate
+ * size - size to change area to
+ *
+ * Returns: pointer to new area (may be same area)
+ *
+ * Narrative: verify pointer is within malloc region
+ * obtain mlist pointer from cptr
+ * verify magic number is correct
+ * verify inuse flag is set
+ * verify connection to adjoining segments is correct
+ * save requested size
+ * round-up size to appropriate boundry
+ * IF size is bigger than what is in this segment
+ * try to join next segment to this segment
+ * IF size is less than what is is this segment
+ * determine leftover amount of space
+ * ELSE
+ * allocate new segment of size bites
+ * IF allocation failed
+ * return NULL
+ * copy previous data to new segment
+ * free previous segment
+ * return new pointer
+ * split of extra space in this segment (if any)
+ * clear bytes beyound what they had before
+ * return pointer to data
+ */
+#ifndef lint
+static
+char rcs_hdr[] = "$Id: realloc.c,v 1.2 2006-07-25 10:09:48 rt Exp $";
+#endif
+
+char *
+realloc(cptr,size)
+ char * cptr;
+ unsigned int size;
+{
+ void free();
+ char * func = "realloc";
+ int i;
+ char * malloc();
+ extern int malloc_checking;
+ extern struct mlist * malloc_end;
+ extern int malloc_errno;
+ extern char * malloc_data_end;
+ extern char * malloc_data_start;
+ void malloc_join();
+ void malloc_memset();
+ void malloc_split();
+ char * memcpy();
+ char * new_cptr;
+ struct mlist * ptr;
+ int r_size;
+
+ /*
+ * IF malloc chain checking is on, go do it.
+ */
+ if( malloc_checking )
+ {
+ (void) malloc_chain_check(1);
+ }
+
+ /*
+ * verify that cptr is within the malloc region...
+ */
+ if( cptr < malloc_data_start || cptr > malloc_data_end )
+ {
+ malloc_errno = M_CODE_BAD_PTR;
+ malloc_warning(func);
+ return (NULL);
+ }
+
+ /*
+ * 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_MAGIC )
+ {
+ malloc_errno = M_CODE_BAD_MAGIC;
+ malloc_warning(func);
+ return(NULL);
+ }
+
+ if( ! (ptr->flag & M_INUSE) )
+ {
+ malloc_errno = M_CODE_NOT_INUSE ;
+ malloc_warning(func);
+ return(NULL);
+ }
+
+ if( (ptr->prev && (ptr->prev->next != ptr) ) ||
+ (ptr->next && (ptr->next->prev != ptr) ) ||
+ ((ptr->next == NULL) && (ptr->prev == NULL)) )
+ {
+ malloc_errno = M_CODE_BAD_CONNECT;
+ malloc_warning(func);
+ 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 )
+ {
+ /*
+ * 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;
+ }
+ (void)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, (int) (ptr->s.size - i));
+
+ return(ptr->data);
+
+} /* realloc(... */
+
+
diff --git a/dmake/dbug/malloc/string.c b/dmake/dbug/malloc/string.c
new file mode 100644
index 000000000000..7b92bf07ad1b
--- /dev/null
+++ b/dmake/dbug/malloc/string.c
@@ -0,0 +1,533 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "malloc.h"
+
+#ifndef lint
+static
+char rcs_hdr[] = "$Id: string.c,v 1.2 2006-07-25 10:10:03 rt Exp $";
+#endif
+
+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((unsigned)strlen(str1)+1);
+
+ if( rtn != (char *) 0)
+ {
+ 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_check_strn("strncat", str2, len);
+
+ malloc_checking = 1;
+
+ len2 = strlen(str2) + 1;
+ len1 = strlen(str1);
+
+ malloc_checking = 0;
+
+
+ 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++;
+ }
+
+
+ /*
+ * in order to deal with the case of a negative last char of either
+ * string when the other string has a null
+ */
+ if( (*str2 == '\0') && (*str1 == '\0') )
+ {
+ return(0);
+ }
+ else if( *str2 == '\0' )
+ {
+ return(1);
+ }
+ else if( *str1 == '\0' )
+ {
+ return(-1);
+ }
+
+ return( *str1 - *str2 );
+}
+
+int
+strncmp(str1,str2,len)
+ register char * str1;
+ register char * str2;
+ register int len;
+{
+ malloc_check_strn("strncmp", str1, len);
+ malloc_check_strn("strncmp", str2, len);
+
+ while( --len >= 0 && *str1 && (*str1 == *str2) )
+ {
+ str1++;
+ str2++;
+ }
+
+ if( len < 0 )
+ {
+ return(0);
+ }
+ /*
+ * in order to deal with the case of a negative last char of either
+ * string when the other string has a null
+ */
+ if( (*str2 == '\0') && (*str1 == '\0') )
+ {
+ return(0);
+ }
+ else if( *str2 == '\0' )
+ {
+ return(1);
+ }
+ else if( *str1 == '\0' )
+ {
+ return(-1);
+ }
+
+ 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;
+{
+ extern int malloc_checking;
+ char * rtn;
+
+ malloc_check_data("strncpy", str1, len);
+ malloc_check_strn("strncpy", str2, len);
+
+ rtn = str1;
+
+ while((len-- > 0) && (*str1++ = *str2++) != '\0')
+ {
+ }
+ while( (len-- > 0) )
+ {
+ *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 != (char) c)
+ {
+ 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++;
+ }
+
+ if( *str1 == (char) c)
+ {
+ rtn = str1;
+ }
+
+ return(rtn);
+}
+
+char *
+index(str1,c)
+ char * str1;
+ char c;
+{
+ return( strchr(str1,c) );
+}
+
+char *
+rindex(str1,c)
+ char * str1;
+ char 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 */
+}
+
diff --git a/dmake/dbug/malloc/testmem.c b/dmake/dbug/malloc/testmem.c
new file mode 100644
index 000000000000..46fba912f8c0
--- /dev/null
+++ b/dmake/dbug/malloc/testmem.c
@@ -0,0 +1,646 @@
+/*
+ * This stuff is all stolen (with permission, since it was in the public
+ * domain) from Henry Spencer's string and memory library. Thanks Henry.
+ */
+
+/*
+ * Test program for string(3) routines.
+ *
+ * Note that at least one Bell Labs implementation of the string
+ * routines flunks a couple of these tests -- the ones which test
+ * behavior on "negative" characters.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+char * index();
+char * rindex();
+
+#define STREQ(a, b) (strcmp((a), (b)) == 0)
+
+char *it = "<UNSET>"; /* Routine name for message routines. */
+int waserror = 0; /* For exit status. */
+
+char uctest[] = "\004\203"; /* For testing signedness of chars. */
+int charsigned; /* Result. */
+
+/*
+ - check - complain if condition is not true
+ */
+void
+check(thing, number)
+int thing;
+int number; /* Test number for error message. */
+{
+ if (!thing) {
+ printf("%s flunked test %d\n", it, number);
+ waserror = 1;
+ }
+}
+
+/*
+ - equal - complain if first two args don't strcmp as equal
+ */
+void
+equal(a, b, number)
+char *a;
+char *b;
+int number; /* Test number for error message. */
+{
+ check(a != NULL && b != NULL && STREQ(a, b), number);
+}
+
+char one[50];
+char two[50];
+
+#ifdef UNIXERR
+#define ERR 1
+#endif
+#ifdef BERKERR
+#define ERR 1
+#endif
+#ifdef ERR
+int f;
+extern char *sys_errlist[];
+extern int sys_nerr;
+extern int errno;
+#endif
+
+/* ARGSUSED */
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ /*
+ * First, establish whether chars are signed.
+ */
+ if (uctest[0] < uctest[1])
+ charsigned = 0;
+ else
+ charsigned = 1;
+
+ /*
+ * Then, do the rest of the work. Split into two functions because
+ * some compilers get unhappy about a single immense function.
+ */
+ first();
+ second();
+
+ exit((waserror) ? 1 : 0);
+}
+
+first()
+{
+ /*
+ * Test strcmp first because we use it to test other things.
+ */
+ it = "strcmp";
+ check(strcmp("", "") == 0, 1); /* Trivial case. */
+ check(strcmp("a", "a") == 0, 2); /* Identity. */
+ check(strcmp("abc", "abc") == 0, 3); /* Multicharacter. */
+ check(strcmp("abc", "abcd") < 0, 4); /* Length mismatches. */
+ check(strcmp("abcd", "abc") > 0, 5);
+ check(strcmp("abcd", "abce") < 0, 6); /* Honest miscompares. */
+ check(strcmp("abce", "abcd") > 0, 7);
+ check(strcmp("a\203", "a") > 0, 8); /* Tricky if char signed. */
+ if (charsigned) /* Sign-bit comparison. */
+ check(strcmp("a\203", "a\003") < 0, 9);
+ else
+ check(strcmp("a\203", "a\003") > 0, 9);
+ check(strcmp("a", "a\203") < 0, 10); /* Tricky if char signed. */
+
+ /*
+ * Test strcpy next because we need it to set up other tests.
+ */
+ it = "strcpy";
+ check(strcpy(one, "abcd") == one, 1); /* Returned value. */
+ equal(one, "abcd", 2); /* Basic test. */
+
+ (void) strcpy(one, "x");
+ equal(one, "x", 3); /* Writeover. */
+ equal(one+2, "cd", 4); /* Wrote too much? */
+
+ (void) strcpy(two, "hi there");
+ (void) strcpy(one, two);
+ equal(one, "hi there", 5); /* Basic test encore. */
+ equal(two, "hi there", 6); /* Stomped on source? */
+
+ (void) strcpy(one, "");
+ equal(one, "", 7); /* Boundary condition. */
+
+ /*
+ * strcat
+ */
+ it = "strcat";
+ (void) strcpy(one, "ijk");
+ check(strcat(one, "lmn") == one, 1); /* Returned value. */
+ equal(one, "ijklmn", 2); /* Basic test. */
+
+ (void) strcpy(one, "x");
+ (void) strcat(one, "yz");
+ equal(one, "xyz", 3); /* Writeover. */
+ equal(one+4, "mn", 4); /* Wrote too much? */
+
+ (void) strcpy(one, "gh");
+ (void) strcpy(two, "ef");
+ (void) strcat(one, two);
+ equal(one, "ghef", 5); /* Basic test encore. */
+ equal(two, "ef", 6); /* Stomped on source? */
+
+ (void) strcpy(one, "");
+ (void) strcat(one, "");
+ equal(one, "", 7); /* Boundary conditions. */
+ (void) strcpy(one, "ab");
+ (void) strcat(one, "");
+ equal(one, "ab", 8);
+ (void) strcpy(one, "");
+ (void) strcat(one, "cd");
+ equal(one, "cd", 9);
+
+ /*
+ * strncat - first test it as strcat, with big counts, then
+ * test the count mechanism.
+ */
+ it = "strncat";
+ (void) strcpy(one, "ijk");
+ check(strncat(one, "lmn", 99) == one, 1); /* Returned value. */
+ equal(one, "ijklmn", 2); /* Basic test. */
+
+ (void) strcpy(one, "x");
+ (void) strncat(one, "yz", 99);
+ equal(one, "xyz", 3); /* Writeover. */
+ equal(one+4, "mn", 4); /* Wrote too much? */
+
+ (void) strcpy(one, "gh");
+ (void) strcpy(two, "ef");
+ (void) strncat(one, two, 99);
+ equal(one, "ghef", 5); /* Basic test encore. */
+ equal(two, "ef", 6); /* Stomped on source? */
+
+ (void) strcpy(one, "");
+ (void) strncat(one, "", 99);
+ equal(one, "", 7); /* Boundary conditions. */
+ (void) strcpy(one, "ab");
+ (void) strncat(one, "", 99);
+ equal(one, "ab", 8);
+ (void) strcpy(one, "");
+ (void) strncat(one, "cd", 99);
+ equal(one, "cd", 9);
+
+ (void) strcpy(one, "ab");
+ (void) strncat(one, "cdef", 2);
+ equal(one, "abcd", 10); /* Count-limited. */
+
+ (void) strncat(one, "gh", 0);
+ equal(one, "abcd", 11); /* Zero count. */
+
+ (void) strncat(one, "gh", 2);
+ equal(one, "abcdgh", 12); /* Count and length equal. */
+
+ /*
+ * strncmp - first test as strcmp with big counts, then test
+ * count code.
+ */
+ it = "strncmp";
+ check(strncmp("", "", 99) == 0, 1); /* Trivial case. */
+ check(strncmp("a", "a", 99) == 0, 2); /* Identity. */
+ check(strncmp("abc", "abc", 99) == 0, 3); /* Multicharacter. */
+ check(strncmp("abc", "abcd", 99) < 0, 4); /* Length unequal. */
+ check(strncmp("abcd", "abc", 99) > 0, 5);
+ check(strncmp("abcd", "abce", 99) < 0, 6); /* Honestly unequal. */
+ check(strncmp("abce", "abcd", 99) > 0, 7);
+ check(strncmp("a\203", "a", 2) > 0, 8); /* Tricky if '\203' < 0 */
+ if (charsigned) /* Sign-bit comparison. */
+ check(strncmp("a\203", "a\003", 2) < 0, 9);
+ else
+ check(strncmp("a\203", "a\003", 2) > 0, 9);
+ check(strncmp("abce", "abcd", 3) == 0, 10); /* Count limited. */
+ check(strncmp("abce", "abc", 3) == 0, 11); /* Count == length. */
+ check(strncmp("abcd", "abce", 4) < 0, 12); /* Nudging limit. */
+ check(strncmp("abc", "def", 0) == 0, 13); /* Zero count. */
+
+ /*
+ * strncpy - testing is a bit different because of odd semantics
+ */
+ it = "strncpy";
+ check(strncpy(one, "abc", 4) == one, 1); /* Returned value. */
+ equal(one, "abc", 2); /* Did the copy go right? */
+
+ (void) strcpy(one, "abcdefgh");
+ (void) strncpy(one, "xyz", 2);
+ equal(one, "xycdefgh", 3); /* Copy cut by count. */
+
+ (void) strcpy(one, "abcdefgh");
+ (void) strncpy(one, "xyz", 3); /* Copy cut just before NUL. */
+ equal(one, "xyzdefgh", 4);
+
+ (void) strcpy(one, "abcdefgh");
+ (void) strncpy(one, "xyz", 4); /* Copy just includes NUL. */
+ equal(one, "xyz", 5);
+ equal(one+4, "efgh", 6); /* Wrote too much? */
+
+ (void) strcpy(one, "abcdefgh");
+ (void) strncpy(one, "xyz", 5); /* Copy includes padding. */
+ equal(one, "xyz", 7);
+ equal(one+4, "", 8);
+ equal(one+5, "fgh", 9);
+
+ (void) strcpy(one, "abc");
+ (void) strncpy(one, "xyz", 0); /* Zero-length copy. */
+ equal(one, "abc", 10);
+
+ (void) strncpy(one, "", 2); /* Zero-length source. */
+ equal(one, "", 11);
+ equal(one+1, "", 12);
+ equal(one+2, "c", 13);
+
+ (void) strcpy(one, "hi there");
+ (void) strncpy(two, one, 9);
+ equal(two, "hi there", 14); /* Just paranoia. */
+ equal(one, "hi there", 15); /* Stomped on source? */
+
+ /*
+ * strlen
+ */
+ it = "strlen";
+ check(strlen("") == 0, 1); /* Empty. */
+ check(strlen("a") == 1, 2); /* Single char. */
+ check(strlen("abcd") == 4, 3); /* Multiple chars. */
+
+ /*
+ * strchr
+ */
+ it = "strchr";
+ check(strchr("abcd", 'z') == NULL, 1); /* Not found. */
+ (void) strcpy(one, "abcd");
+ check(strchr(one, 'c') == one+2, 2); /* Basic test. */
+ check(strchr(one, 'd') == one+3, 3); /* End of string. */
+ check(strchr(one, 'a') == one, 4); /* Beginning. */
+ check(strchr(one, '\0') == one+4, 5); /* Finding NUL. */
+ (void) strcpy(one, "ababa");
+ check(strchr(one, 'b') == one+1, 6); /* Finding first. */
+ (void) strcpy(one, "");
+ check(strchr(one, 'b') == NULL, 7); /* Empty string. */
+ check(strchr(one, '\0') == one, 8); /* NUL in empty string. */
+
+ /*
+ * index - just like strchr
+ */
+ it = "index";
+ check(index("abcd", 'z') == NULL, 1); /* Not found. */
+ (void) strcpy(one, "abcd");
+ check(index(one, 'c') == one+2, 2); /* Basic test. */
+ check(index(one, 'd') == one+3, 3); /* End of string. */
+ check(index(one, 'a') == one, 4); /* Beginning. */
+ check(index(one, '\0') == one+4, 5); /* Finding NUL. */
+ (void) strcpy(one, "ababa");
+ check(index(one, 'b') == one+1, 6); /* Finding first. */
+ (void) strcpy(one, "");
+ check(index(one, 'b') == NULL, 7); /* Empty string. */
+ check(index(one, '\0') == one, 8); /* NUL in empty string. */
+
+ /*
+ * strrchr
+ */
+ it = "strrchr";
+ check(strrchr("abcd", 'z') == NULL, 1); /* Not found. */
+ (void) strcpy(one, "abcd");
+ check(strrchr(one, 'c') == one+2, 2); /* Basic test. */
+ check(strrchr(one, 'd') == one+3, 3); /* End of string. */
+ check(strrchr(one, 'a') == one, 4); /* Beginning. */
+ check(strrchr(one, '\0') == one+4, 5); /* Finding NUL. */
+ (void) strcpy(one, "ababa");
+ check(strrchr(one, 'b') == one+3, 6); /* Finding last. */
+ (void) strcpy(one, "");
+ check(strrchr(one, 'b') == NULL, 7); /* Empty string. */
+ check(strrchr(one, '\0') == one, 8); /* NUL in empty string. */
+
+ /*
+ * rindex - just like strrchr
+ */
+ it = "rindex";
+ check(rindex("abcd", 'z') == NULL, 1); /* Not found. */
+ (void) strcpy(one, "abcd");
+ check(rindex(one, 'c') == one+2, 2); /* Basic test. */
+ check(rindex(one, 'd') == one+3, 3); /* End of string. */
+ check(rindex(one, 'a') == one, 4); /* Beginning. */
+ check(rindex(one, '\0') == one+4, 5); /* Finding NUL. */
+ (void) strcpy(one, "ababa");
+ check(rindex(one, 'b') == one+3, 6); /* Finding last. */
+ (void) strcpy(one, "");
+ check(rindex(one, 'b') == NULL, 7); /* Empty string. */
+ check(rindex(one, '\0') == one, 8); /* NUL in empty string. */
+}
+
+second()
+{
+ /*
+ * strpbrk - somewhat like strchr
+ */
+ it = "strpbrk";
+ check(strpbrk("abcd", "z") == NULL, 1); /* Not found. */
+ (void) strcpy(one, "abcd");
+ check(strpbrk(one, "c") == one+2, 2); /* Basic test. */
+ check(strpbrk(one, "d") == one+3, 3); /* End of string. */
+ check(strpbrk(one, "a") == one, 4); /* Beginning. */
+ check(strpbrk(one, "") == NULL, 5); /* Empty search list. */
+ check(strpbrk(one, "cb") == one+1, 6); /* Multiple search. */
+ (void) strcpy(one, "abcabdea");
+ check(strpbrk(one, "b") == one+1, 7); /* Finding first. */
+ check(strpbrk(one, "cb") == one+1, 8); /* With multiple search. */
+ check(strpbrk(one, "db") == one+1, 9); /* Another variant. */
+ (void) strcpy(one, "");
+ check(strpbrk(one, "bc") == NULL, 10); /* Empty string. */
+ check(strpbrk(one, "") == NULL, 11); /* Both strings empty. */
+
+#if 0
+ /*
+ * strstr - somewhat like strchr
+ */
+ it = "strstr";
+ check(strstr("abcd", "z") == NULL, 1); /* Not found. */
+ check(strstr("abcd", "abx") == NULL, 2); /* Dead end. */
+ (void) strcpy(one, "abcd");
+ check(strstr(one, "c") == one+2, 3); /* Basic test. */
+ check(strstr(one, "bc") == one+1, 4); /* Multichar. */
+ check(strstr(one, "d") == one+3, 5); /* End of string. */
+ check(strstr(one, "cd") == one+2, 6); /* Tail of string. */
+ check(strstr(one, "abc") == one, 7); /* Beginning. */
+ check(strstr(one, "abcd") == one, 8); /* Exact match. */
+ check(strstr(one, "abcde") == NULL, 9); /* Too long. */
+ check(strstr(one, "de") == NULL, 10); /* Past end. */
+ check(strstr(one, "") == one+4, 11); /* Finding empty. */
+ (void) strcpy(one, "ababa");
+ check(strstr(one, "ba") == one+1, 12); /* Finding first. */
+ (void) strcpy(one, "");
+ check(strstr(one, "b") == NULL, 13); /* Empty string. */
+ check(strstr(one, "") == one, 14); /* Empty in empty string. */
+ (void) strcpy(one, "bcbca");
+ check(strstr(one, "bca") == one+2, 15); /* False start. */
+ (void) strcpy(one, "bbbcabbca");
+ check(strstr(one, "bbca") == one+1, 16); /* With overlap. */
+#endif
+
+ /*
+ * strspn
+ */
+ it = "strspn";
+ check(strspn("abcba", "abc") == 5, 1); /* Whole string. */
+ check(strspn("abcba", "ab") == 2, 2); /* Partial. */
+ check(strspn("abc", "qx") == 0, 3); /* None. */
+ check(strspn("", "ab") == 0, 4); /* Null string. */
+ check(strspn("abc", "") == 0, 5); /* Null search list. */
+
+ /*
+ * strcspn
+ */
+ it = "strcspn";
+ check(strcspn("abcba", "qx") == 5, 1); /* Whole string. */
+ check(strcspn("abcba", "cx") == 2, 2); /* Partial. */
+ check(strcspn("abc", "abc") == 0, 3); /* None. */
+ check(strcspn("", "ab") == 0, 4); /* Null string. */
+ check(strcspn("abc", "") == 3, 5); /* Null search list. */
+
+ /*
+ * strtok - the hard one
+ */
+ it = "strtok";
+ (void) strcpy(one, "first, second, third");
+ equal(strtok(one, ", "), "first", 1); /* Basic test. */
+ equal(one, "first", 2);
+ equal(strtok((char *)NULL, ", "), "second", 3);
+ equal(strtok((char *)NULL, ", "), "third", 4);
+ check(strtok((char *)NULL, ", ") == NULL, 5);
+ (void) strcpy(one, ", first, ");
+ equal(strtok(one, ", "), "first", 6); /* Extra delims, 1 tok. */
+ check(strtok((char *)NULL, ", ") == NULL, 7);
+ (void) strcpy(one, "1a, 1b; 2a, 2b");
+ equal(strtok(one, ", "), "1a", 8); /* Changing delim lists. */
+ equal(strtok((char *)NULL, "; "), "1b", 9);
+ equal(strtok((char *)NULL, ", "), "2a", 10);
+ (void) strcpy(two, "x-y");
+ equal(strtok(two, "-"), "x", 11); /* New string before done. */
+ equal(strtok((char *)NULL, "-"), "y", 12);
+ check(strtok((char *)NULL, "-") == NULL, 13);
+ (void) strcpy(one, "a,b, c,, ,d");
+ equal(strtok(one, ", "), "a", 14); /* Different separators. */
+ equal(strtok((char *)NULL, ", "), "b", 15);
+ equal(strtok((char *)NULL, " ,"), "c", 16); /* Permute list too. */
+ equal(strtok((char *)NULL, " ,"), "d", 17);
+ check(strtok((char *)NULL, ", ") == NULL, 18);
+ check(strtok((char *)NULL, ", ") == NULL, 19); /* Persistence. */
+ (void) strcpy(one, ", ");
+ check(strtok(one, ", ") == NULL, 20); /* No tokens. */
+ (void) strcpy(one, "");
+ check(strtok(one, ", ") == NULL, 21); /* Empty string. */
+ (void) strcpy(one, "abc");
+ equal(strtok(one, ", "), "abc", 22); /* No delimiters. */
+ check(strtok((char *)NULL, ", ") == NULL, 23);
+ (void) strcpy(one, "abc");
+ equal(strtok(one, ""), "abc", 24); /* Empty delimiter list. */
+ check(strtok((char *)NULL, "") == NULL, 25);
+ (void) strcpy(one, "abcdefgh");
+ (void) strcpy(one, "a,b,c");
+ equal(strtok(one, ","), "a", 26); /* Basics again... */
+ equal(strtok((char *)NULL, ","), "b", 27);
+ equal(strtok((char *)NULL, ","), "c", 28);
+ check(strtok((char *)NULL, ",") == NULL, 29);
+ equal(one+6, "gh", 30); /* Stomped past end? */
+ equal(one, "a", 31); /* Stomped old tokens? */
+ equal(one+2, "b", 32);
+ equal(one+4, "c", 33);
+
+ /*
+ * memcmp
+ */
+ it = "memcmp";
+ check(memcmp("a", "a", 1) == 0, 1); /* Identity. */
+ check(memcmp("abc", "abc", 3) == 0, 2); /* Multicharacter. */
+ check(memcmp("abcd", "abce", 4) < 0, 3); /* Honestly unequal. */
+ check(memcmp("abce", "abcd", 4) > 0, 4);
+ check(memcmp("alph", "beta", 4) < 0, 5);
+ if (charsigned) /* Sign-bit comparison. */
+ check(memcmp("a\203", "a\003", 2) < 0, 6);
+ else
+ check(memcmp("a\203", "a\003", 2) > 0, 6);
+ check(memcmp("abce", "abcd", 3) == 0, 7); /* Count limited. */
+ check(memcmp("abc", "def", 0) == 0, 8); /* Zero count. */
+
+ /*
+ * memchr
+ */
+ it = "memchr";
+ check(memchr("abcd", 'z', 4) == NULL, 1); /* Not found. */
+ (void) strcpy(one, "abcd");
+ check(memchr(one, 'c', 4) == one+2, 2); /* Basic test. */
+ check(memchr(one, 'd', 4) == one+3, 3); /* End of string. */
+ check(memchr(one, 'a', 4) == one, 4); /* Beginning. */
+ check(memchr(one, '\0', 5) == one+4, 5); /* Finding NUL. */
+ (void) strcpy(one, "ababa");
+ check(memchr(one, 'b', 5) == one+1, 6); /* Finding first. */
+ check(memchr(one, 'b', 0) == NULL, 7); /* Zero count. */
+ check(memchr(one, 'a', 1) == one, 8); /* Singleton case. */
+ (void) strcpy(one, "a\203b");
+ check(memchr(one, 0203, 3) == one+1, 9); /* Unsignedness. */
+
+ /*
+ * memcpy
+ *
+ * Note that X3J11 says memcpy must work regardless of overlap.
+ * The SVID says it might fail.
+ */
+ it = "memcpy";
+ check(memcpy(one, "abc", 4) == one, 1); /* Returned value. */
+ equal(one, "abc", 2); /* Did the copy go right? */
+
+ (void) strcpy(one, "abcdefgh");
+ (void) memcpy(one+1, "xyz", 2);
+ equal(one, "axydefgh", 3); /* Basic test. */
+
+ (void) strcpy(one, "abc");
+ (void) memcpy(one, "xyz", 0);
+ equal(one, "abc", 4); /* Zero-length copy. */
+
+ (void) strcpy(one, "hi there");
+ (void) strcpy(two, "foo");
+ (void) memcpy(two, one, 9);
+ equal(two, "hi there", 5); /* Just paranoia. */
+ equal(one, "hi there", 6); /* Stomped on source? */
+
+ (void) strcpy(one, "abcdefgh");
+ (void) memcpy(one+1, one, 9);
+ equal(one, "aabcdefgh", 7); /* Overlap, right-to-left. */
+
+ (void) strcpy(one, "abcdefgh");
+ (void) memcpy(one+1, one+2, 7);
+ equal(one, "acdefgh", 8); /* Overlap, left-to-right. */
+
+ (void) strcpy(one, "abcdefgh");
+ (void) memcpy(one, one, 9);
+ equal(one, "abcdefgh", 9); /* 100% overlap. */
+
+ /*
+ * memccpy - first test like memcpy, then the search part
+ *
+ * The SVID, the only place where memccpy is mentioned, says
+ * overlap might fail, so we don't try it. Besides, it's hard
+ * to see the rationale for a non-left-to-right memccpy.
+ */
+ it = "memccpy";
+ check(memccpy(one, "abc", 'q', 4) == NULL, 1); /* Returned value. */
+ equal(one, "abc", 2); /* Did the copy go right? */
+
+ (void) strcpy(one, "abcdefgh");
+ (void) memccpy(one+1, "xyz", 'q', 2);
+ equal(one, "axydefgh", 3); /* Basic test. */
+
+ (void) strcpy(one, "abc");
+ (void) memccpy(one, "xyz", 'q', 0);
+ equal(one, "abc", 4); /* Zero-length copy. */
+
+ (void) strcpy(one, "hi there");
+ (void) strcpy(two, "foo");
+ (void) memccpy(two, one, 'q', 9);
+ equal(two, "hi there", 5); /* Just paranoia. */
+ equal(one, "hi there", 6); /* Stomped on source? */
+
+ (void) strcpy(one, "abcdefgh");
+ (void) strcpy(two, "horsefeathers");
+ check(memccpy(two, one, 'f', 9) == two+6, 7); /* Returned value. */
+ equal(one, "abcdefgh", 8); /* Source intact? */
+ equal(two, "abcdefeathers", 9); /* Copy correct? */
+
+ (void) strcpy(one, "abcd");
+ (void) strcpy(two, "bumblebee");
+ check(memccpy(two, one, 'a', 4) == two+1, 10); /* First char. */
+ equal(two, "aumblebee", 11);
+ check(memccpy(two, one, 'd', 4) == two+4, 12); /* Last char. */
+ equal(two, "abcdlebee", 13);
+ (void) strcpy(one, "xyz");
+ check(memccpy(two, one, 'x', 1) == two+1, 14); /* Singleton. */
+ equal(two, "xbcdlebee", 15);
+
+ /*
+ * memset
+ */
+ it = "memset";
+ (void) strcpy(one, "abcdefgh");
+ check(memset(one+1, 'x', 3) == one+1, 1); /* Return value. */
+ equal(one, "axxxefgh", 2); /* Basic test. */
+
+ (void) memset(one+2, 'y', 0);
+ equal(one, "axxxefgh", 3); /* Zero-length set. */
+
+ (void) memset(one+5, 0, 1);
+ equal(one, "axxxe", 4); /* Zero fill. */
+ equal(one+6, "gh", 5); /* And the leftover. */
+
+ (void) memset(one+2, 010045, 1);
+ equal(one, "ax\045xe", 6); /* Unsigned char convert. */
+
+ /*
+ * bcopy - much like memcpy
+ *
+ * Berklix manual is silent about overlap, so don't test it.
+ */
+ it = "bcopy";
+ (void) bcopy("abc", one, 4);
+ equal(one, "abc", 1); /* Simple copy. */
+
+ (void) strcpy(one, "abcdefgh");
+ (void) bcopy("xyz", one+1, 2);
+ equal(one, "axydefgh", 2); /* Basic test. */
+
+ (void) strcpy(one, "abc");
+ (void) bcopy("xyz", one, 0);
+ equal(one, "abc", 3); /* Zero-length copy. */
+
+ (void) strcpy(one, "hi there");
+ (void) strcpy(two, "foo");
+ (void) bcopy(one, two, 9);
+ equal(two, "hi there", 4); /* Just paranoia. */
+ equal(one, "hi there", 5); /* Stomped on source? */
+
+ /*
+ * bzero
+ */
+ it = "bzero";
+ (void) strcpy(one, "abcdef");
+ bzero(one+2, 2);
+ equal(one, "ab", 1); /* Basic test. */
+ equal(one+3, "", 2);
+ equal(one+4, "ef", 3);
+
+ (void) strcpy(one, "abcdef");
+ bzero(one+2, 0);
+ equal(one, "abcdef", 4); /* Zero-length copy. */
+
+ /*
+ * bcmp - somewhat like memcmp
+ */
+ it = "bcmp";
+ check(bcmp("a", "a", 1) == 0, 1); /* Identity. */
+ check(bcmp("abc", "abc", 3) == 0, 2); /* Multicharacter. */
+ check(bcmp("abcd", "abce", 4) != 0, 3); /* Honestly unequal. */
+ check(bcmp("abce", "abcd", 4) != 0, 4);
+ check(bcmp("alph", "beta", 4) != 0, 5);
+ check(bcmp("abce", "abcd", 3) == 0, 6); /* Count limited. */
+ check(bcmp("abc", "def", 0) == 0, 8); /* Zero count. */
+
+#ifdef ERR
+ /*
+ * strerror - VERY system-dependent
+ */
+ it = "strerror";
+ f = open("/", 1); /* Should always fail. */
+ check(f < 0 && errno > 0 && errno < sys_nerr, 1);
+ equal(strerror(errno), sys_errlist[errno], 2);
+#ifdef UNIXERR
+ equal(strerror(errno), "Is a directory", 3);
+#endif
+#ifdef BERKERR
+ equal(strerror(errno), "Permission denied", 3);
+#endif
+#endif
+}
diff --git a/dmake/dbug/malloc/testmlc.c b/dmake/dbug/malloc/testmlc.c
new file mode 100644
index 000000000000..16e11736cc18
--- /dev/null
+++ b/dmake/dbug/malloc/testmlc.c
@@ -0,0 +1,176 @@
+/* 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 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(2);
+ exit( 0 );
+}
+
diff --git a/dmake/dbug/malloc/tostring.c b/dmake/dbug/malloc/tostring.c
new file mode 100644
index 000000000000..e3bc9990271d
--- /dev/null
+++ b/dmake/dbug/malloc/tostring.c
@@ -0,0 +1,132 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+#include "tostring.h"
+
+/*
+ * Function: tostring()
+ *
+ * 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.
+ */
+
+#ifndef lint
+static
+char rcs_hdr[] = "$Id: tostring.c,v 1.2 2006-07-25 10:10:17 rt Exp $";
+#endif
+
+#define T_LEN 10
+
+int
+tostring(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) );
+
+} /* tostring(... */
+
diff --git a/dmake/dbug/malloc/tostring.h b/dmake/dbug/malloc/tostring.h
new file mode 100644
index 000000000000..ccde36db4173
--- /dev/null
+++ b/dmake/dbug/malloc/tostring.h
@@ -0,0 +1,13 @@
+/*
+ * (c) Copyright 1990 Conor P. Cahill (uunet!virtech!cpcahil).
+ * You may copy, distribute, and use this software as long as this
+ * copyright statement is not removed.
+ */
+/*
+ * $Id: tostring.h,v 1.2 2006-07-25 10:10:32 rt Exp $
+ */
+#define B_BIN 2
+#define B_DEC 10
+#define B_HEX 16
+#define B_OCTAL 8
+