jdk/src/jdk.hprof.agent/share/native/libhprof/debug_malloc.c
changeset 26201 40a873d21081
parent 25859 3317bb8137f4
equal deleted inserted replaced
26200:743de4ce28cc 26201:40a873d21081
       
     1 /*
       
     2  * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
       
     3  *
       
     4  * Redistribution and use in source and binary forms, with or without
       
     5  * modification, are permitted provided that the following conditions
       
     6  * are met:
       
     7  *
       
     8  *   - Redistributions of source code must retain the above copyright
       
     9  *     notice, this list of conditions and the following disclaimer.
       
    10  *
       
    11  *   - Redistributions in binary form must reproduce the above copyright
       
    12  *     notice, this list of conditions and the following disclaimer in the
       
    13  *     documentation and/or other materials provided with the distribution.
       
    14  *
       
    15  *   - Neither the name of Oracle nor the names of its
       
    16  *     contributors may be used to endorse or promote products derived
       
    17  *     from this software without specific prior written permission.
       
    18  *
       
    19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
       
    20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
       
    21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
       
    22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
       
    23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
       
    24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
       
    25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
       
    26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
       
    27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
       
    28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
       
    29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    30  */
       
    31 
       
    32 /*
       
    33  * This source code is provided to illustrate the usage of a given feature
       
    34  * or technique and has been deliberately simplified. Additional steps
       
    35  * required for a production-quality application, such as security checks,
       
    36  * input validation and proper error handling, might not be present in
       
    37  * this sample code.
       
    38  */
       
    39 
       
    40 
       
    41 /* **************************************************************************
       
    42  *
       
    43  * Set of malloc/realloc/calloc/strdup/free replacement macros that
       
    44  *    insert some extra words around each allocation for debugging purposes
       
    45  *    and also attempt to detect invalid uses of the malloc heap through
       
    46  *    various tricks like inserting clobber words at the head and tail of
       
    47  *    the user's area, delayed free() calls, and setting the memory to
       
    48  *    a fixed pattern on allocation and when freed.  The allocations also
       
    49  *    can include warrants so that when an area is clobbered, this
       
    50  *    package can report where the allocation took place.
       
    51  *    The macros included are:
       
    52  *              malloc(size)
       
    53  *              realloc(ptr,size)
       
    54  *              calloc(nelem,elsize)
       
    55  *              strdup(s1)
       
    56  *              free(ptr)
       
    57  *              malloc_police()   <--- Not a system function
       
    58  *    The above macros match the standard behavior of the system functions.
       
    59  *
       
    60  *    They should be used through the include file "debug_malloc.h".
       
    61  *
       
    62  *       IMPORTANT: All source files that call any of these macros
       
    63  *                  should include debug_malloc.h. This package will
       
    64  *                  not work if the memory isn't allocated and freed
       
    65  *                  by the macros in debug_malloc.h. The important issue
       
    66  *                  is that any malloc() from debug_malloc.h must be
       
    67  *                  freed by the free() in debug_malloc.h.
       
    68  *
       
    69  *    The macros in debug_malloc.h will override the normal use of
       
    70  *       malloc, realloc, calloc, strdup, and free with the functions below.
       
    71  *
       
    72  *    These functions include:
       
    73  *         void *debug_malloc(size_t, void*, int);
       
    74  *         void *debug_realloc(void*, size_t, void*, int);
       
    75  *         void *debug_calloc(size_t, size_t, void*, int);
       
    76  *         void  debug_free(void *, void*, int);
       
    77  *
       
    78  *   In addition the function debug_malloc_police() can be called to
       
    79  *      tell you what memory has not been freed.
       
    80  *         void debug_malloc_police(void*, int);
       
    81  *      The function debug_malloc_police() is available through the macro
       
    82  *      malloc_police(). Normally you would want to call this at exit()
       
    83  *      time to find out what memory is still allocated.
       
    84  *
       
    85  *   The variable malloc_watch determines if the warrants are generated.
       
    86  *      warrants are structures that include the filename and line number
       
    87  *      of the caller who allocated the memory. This structure is stored
       
    88  *      at the tail of the malloc space, which is allocated large enough
       
    89  *      to hold some clobber words at the head and tail, the user's request
       
    90  *      and the warrant record (if malloc_watch is non-zero).
       
    91  *
       
    92  *   The macro LEFT_OVER_CHAR is what the trailing bytes of an allocation
       
    93  *     are set to (when the allocation is not a multiple of 8) on allocation.
       
    94  *     At free(0 time, these bytes are double checked to make sure they were
       
    95  *     not clobbered. To remove this feature #undef LEFT_OVER_CHAR.
       
    96  *
       
    97  *   The memory freed will have the FREED_CHAR put into it. To remove this
       
    98  *     feature #undef FREED_CHAR.
       
    99  *
       
   100  *   The memory allocated (not calloc'd) will have the ALLOC_CHAR put into it
       
   101  *     at the time of allocation. To remove this feature #undef ALLOC_CHAR.
       
   102  *
       
   103  *   The macro MAX_FREE_DELAY_COUNT controls how many free blocks will
       
   104  *     be kept around before being freed. This creates a delayed affect
       
   105  *     so that free space that gets clobbered just might get detected.
       
   106  *     The free() call will immediately set the user space to the FREED_CHAR,
       
   107  *     leaving the clobber words and warrant in place (making sure they
       
   108  *     haven't been clobbered). Then the free() pointer is added to a
       
   109  *     queue of MAX_FREE_DELAY_COUNT long, and if the queue was full, the
       
   110  *     oldest free()'d memory is actually freed, getting it's entire
       
   111  *     memory length set to the FREED_CHAR.
       
   112  *
       
   113  *  WARNING: This can significantly slow down an application, depending
       
   114  *           on how many allocations are made. Also the additional memory
       
   115  *           needed for the clobber words and the warrants can be significant
       
   116  *           again, depending on how many allocations are made.
       
   117  *           In addition, the delayed free calls can create situations
       
   118  *           where you might run out of memory prematurely.
       
   119  *
       
   120  * **************************************************************************
       
   121  */
       
   122 
       
   123 #ifdef DEBUG
       
   124 
       
   125 #include <stdio.h>
       
   126 #include <stdlib.h>
       
   127 #include <string.h>
       
   128 #include <ctype.h>
       
   129 #include <stdarg.h>
       
   130 #include "hprof.h"
       
   131 
       
   132 /* ***************************************************************************
       
   133  * Space normally looks like (clobber Word is 64 bits and aligned to 8 bytes):
       
   134  *
       
   135  *                  -----------------
       
   136  * malloc/free get->| clobber Word  |   ---> contains -size requested by user
       
   137  *                  -----------------
       
   138  *    User gets --->| user space    |
       
   139  *                  |               |
       
   140  *                  |  | left_over  |  ---> left_over bytes will be <= 7
       
   141  *                  -----------------
       
   142  *                  | clobber Word  |   ---> contains -size requested by user
       
   143  *                  -----------------
       
   144  *                  |   Warrant     |   ---> Optional (malloc_watch!=0)
       
   145  *                  |               |        Contains filename and line number
       
   146  *                  |               |          where allocation happened
       
   147  *                  |               |
       
   148  *                  -----------------
       
   149  ***************************************************************************/
       
   150 
       
   151 /*
       
   152  *  Flag that tells debug_malloc/debug_free/debug_realloc to police
       
   153  *   heap space usage. (This is a dynamic flag that can be turned on/off)
       
   154  */
       
   155 static int      malloc_watch = 1;
       
   156 
       
   157 /* Character to stuff into freed space */
       
   158 #define FREED_CHAR  'F'
       
   159 
       
   160 /* Character to stuff into allocated space */
       
   161 #define ALLOC_CHAR  'A'
       
   162 
       
   163 /* Character to stuff into left over trailing bytes */
       
   164 #define LEFT_OVER_CHAR  'Z'
       
   165 
       
   166 /* Number of 'free' calls that will be delayed until the end */
       
   167 #define MAX_FREE_DELAY_COUNT    1
       
   168 #undef MAX_FREE_DELAY_COUNT
       
   169 
       
   170 /* Maximum name of __FILE_ stored in each malloc'd area */
       
   171 #define WARRANT_NAME_MAX (32-1) /* 1 less than multiple of 8 is best */
       
   172 
       
   173 /* Macro to convert a user pointer to the malloc pointer */
       
   174 #define user2malloc_(uptr)   (((char*)(void*)uptr)-sizeof(Word))
       
   175 
       
   176 /* Macro to convert a macro pointer to the user pointer */
       
   177 #define malloc2user_(mptr)   (((char*)(void*)(mptr))+sizeof(Word))
       
   178 
       
   179 /* Size of the warrant record (this is dynamic) */
       
   180 #define warrant_space  ( malloc_watch?sizeof(Warrant_Record):0 )
       
   181 
       
   182 /* Macro to round up a number of bytes to a multiple of sizeof(Word) bytes */
       
   183 #define round_up_(n) \
       
   184         ((n)==0?0:(sizeof(Word)+(((n)-1)/sizeof(Word))*sizeof(Word)))
       
   185 
       
   186 /* Macro to calculate the needed malloc bytes from the user's request. */
       
   187 #define rbytes_(nbytes) \
       
   188     (size_t)( sizeof(Word) + round_up_(nbytes) + sizeof(Word) + warrant_space )
       
   189 
       
   190 /* Macro to get the -size stored in space through the malloc pointer */
       
   191 #define nsize1_(mptr)           (((Word*)(void*)(mptr))->nsize1)
       
   192 #define nsize2_(mptr)           (((Word*)(void*)(mptr))->nsize2)
       
   193 
       
   194 /* Macro to get the -size stored in the tail of the space through */
       
   195 /*     the malloc pointer */
       
   196 #define tail_nsize1_(mptr)     \
       
   197         nsize1_(((char*)(void*)(mptr))+round_up_(-nsize1_(mptr))+sizeof(Word))
       
   198 #define tail_nsize2_(mptr)     \
       
   199         nsize2_(((char*)(void*)(mptr))+round_up_(-nsize1_(mptr))+sizeof(Word))
       
   200 
       
   201 /* Macro to get the -size stored in space through the user pointer */
       
   202 #define user_nsize1_(uptr)      nsize1_(user2malloc_(uptr))
       
   203 #define user_nsize2_(uptr)      nsize2_(user2malloc_(uptr))
       
   204 
       
   205 /* Macro to get the -size stored in the tail of the space through */
       
   206 /*     the user pointer */
       
   207 #define user_tail_nsize1_(uptr) tail_nsize1_(user2malloc_(uptr))
       
   208 #define user_tail_nsize2_(uptr) tail_nsize2_(user2malloc_(uptr))
       
   209 
       
   210 /* Macro to get the int* of the last 32bit word of user space */
       
   211 #define last_user_word_(mptr)   \
       
   212         ((int*)(((char*)(void*)(mptr))+round_up_(-nsize1_(mptr))))
       
   213 
       
   214 /* Macros to get at the warrant contents from the malloc pointer */
       
   215 #define warrant_(mptr) \
       
   216   (*((Warrant_Record*)(void*)(((char*)(void*)(mptr))+round_up_(-nsize1_(mptr))+sizeof(Word)*2)))
       
   217 
       
   218 /* This struct is allocated after the tail clobber word if malloc_watch */
       
   219 /*    is true. */
       
   220 typedef struct {
       
   221     void           *link;       /* Next mptr in list */
       
   222     char            name[WARRANT_NAME_MAX + 1]; /* Name of allocator */
       
   223     int             line;       /* Line number where allocated */
       
   224     int             id;         /* Nth allocation */
       
   225 }               Warrant_Record;
       
   226 #define warrant_link_(mptr) warrant_(mptr).link
       
   227 #define warrant_name_(mptr) warrant_(mptr).name
       
   228 #define warrant_line_(mptr) warrant_(mptr).line
       
   229 #define warrant_id_(mptr)   warrant_(mptr).id
       
   230 #define MFILE(mptr) (malloc_watch?warrant_name_(mptr):"?")
       
   231 #define MLINE(mptr) (malloc_watch?warrant_line_(mptr):0)
       
   232 #define MID(mptr)   (malloc_watch?warrant_id_(mptr):0)
       
   233 
       
   234 /* This should be one machine word and is also the clobber word struct */
       
   235 typedef struct {
       
   236     int             nsize1;
       
   237     int             nsize2;
       
   238 }               Word;           /* Largest basic type , sizeof(double)? */
       
   239 
       
   240 /* The first malloc pointer for the warrants */
       
   241 static void    *first_warrant_mptr = NULL;
       
   242 
       
   243 /* Counter of allocations */
       
   244 static int id_counter = 0;
       
   245 static int largest_size = 0;
       
   246 static void * largest_addr = NULL;
       
   247 static void * smallest_addr = NULL;
       
   248 
       
   249 /* Used to isolate what the error is */
       
   250 static char *debug_check;
       
   251 static void *clobbered_ptr;
       
   252 
       
   253 /* Minimum macro */
       
   254 #define minimum(a,b) ((a)<(b)?(a):(b))
       
   255 
       
   256 /* Message routine */
       
   257 static void
       
   258 error_message(const char * format, ...)
       
   259 {
       
   260     FILE *error_fp = stderr; /* All debug_malloc.c messages */
       
   261     va_list ap;
       
   262     va_start(ap, format);
       
   263     (void)fprintf(error_fp, "debug_malloc: ");
       
   264     (void)vfprintf(error_fp, format, ap);
       
   265     (void)fprintf(error_fp, "\n");
       
   266     (void)fflush(error_fp);
       
   267     va_end(ap);
       
   268 }
       
   269 
       
   270 /* This function prints out a memory error for the memory function
       
   271  *   'name' which was called in file 'file' at line number 'line'.  The malloc
       
   272  *   pointer with the error is in 'mptr'.
       
   273  */
       
   274 static void
       
   275 memory_error(void *mptr, const char *name, int mid, const char *mfile, int mline, const char *file, int line)
       
   276 {
       
   277     char  nice_words[512];
       
   278     char  temp[256];
       
   279     int   len;
       
   280     void *mptr_walk;
       
   281 
       
   282     if (name == NULL)
       
   283         name = "UNKNOWN_NAME";
       
   284     if (file == NULL)
       
   285         file = "UNKNOWN_FILE";
       
   286     md_system_error(temp, (int)sizeof(temp));
       
   287     (void)strcpy(nice_words, temp);
       
   288     if ( debug_check!=NULL ) {
       
   289        (void)md_snprintf(nice_words, sizeof(nice_words),
       
   290                     "%s The %s at %p appears to have been hit.",
       
   291                     temp, debug_check, clobbered_ptr);
       
   292     }
       
   293     len = -nsize1_(mptr);
       
   294     error_message("Error: "
       
   295                    "%s The malloc space #%d is at %p [user size=%d(0x%x)],"
       
   296                    " and was allocated from file \"%s\" at line %d."
       
   297                    " [The debug function %s() detected this error "
       
   298                    "in file \"%s\" at line %d.]",
       
   299                    nice_words, mid, mptr, len, len, mfile, mline,
       
   300                    name, file, line);
       
   301 
       
   302     /* Print out contents of this allocation */
       
   303     {
       
   304         int i;
       
   305         void *uptr = malloc2user_(mptr);
       
   306         char *pmess;
       
   307         pmess = temp;
       
   308         for(i=0;i<(int)sizeof(temp);i++) {
       
   309             int ch = ((unsigned char*)uptr)[i];
       
   310             if ( isprint(ch) ) {
       
   311                 *pmess++ = ch;
       
   312             } else {
       
   313                 *pmess++ = '\\';
       
   314                 *pmess++ = 'x';
       
   315                 (void)sprintf(pmess,"%02x",ch);
       
   316                 pmess+=2;
       
   317             }
       
   318         }
       
   319         *pmess = 0;
       
   320         error_message("Error: %p contains user data: %s", uptr, temp);
       
   321     }
       
   322 
       
   323     /* Try and print out table */
       
   324     if (!malloc_watch) {
       
   325         return;
       
   326     }
       
   327     mptr_walk = first_warrant_mptr;
       
   328     if (mptr_walk != NULL) {
       
   329         error_message("Active allocations: "
       
   330            "count=%d, largest_size=%d, address range (%p,%p)",
       
   331                         id_counter, largest_size, smallest_addr, largest_addr);
       
   332         do {
       
   333             int size1;
       
   334             int size2;
       
   335             char *mfile_walk;
       
   336 
       
   337             if ( mptr_walk > largest_addr || mptr_walk < smallest_addr ) {
       
   338                 error_message("Terminating list due to pointer corruption");
       
   339                 break;
       
   340             }
       
   341             size1 = -nsize1_(mptr_walk);
       
   342             size2 = -nsize2_(mptr_walk);
       
   343             mfile_walk = MFILE(mptr_walk);
       
   344             error_message("#%d: addr=%p size1=%d size2=%d file=\"%.*s\" line=%d",
       
   345                 MID(mptr_walk), mptr_walk, size1, size2,
       
   346                 WARRANT_NAME_MAX, mfile_walk, MLINE(mptr_walk));
       
   347             if ( size1 != size2 || size1 > largest_size || size1 < 0 ) {
       
   348                 error_message("Terminating list due to size corruption");
       
   349                 break;
       
   350             }
       
   351             mptr_walk = warrant_link_(mptr_walk);
       
   352         } while (mptr_walk != NULL);
       
   353     }
       
   354     abort();
       
   355 }
       
   356 
       
   357 /* This function sets the clobber word and sets up the warrant for the input
       
   358  *   malloc pointer "mptr".
       
   359  */
       
   360 static void
       
   361 setup_space_and_issue_warrant(void *mptr, size_t size, const char *file, int line)
       
   362 {
       
   363     register int    nbytes;
       
   364 
       
   365     /*LINTED*/
       
   366     nbytes = (int)size;
       
   367     if ( nbytes > largest_size || largest_addr == NULL ) largest_size = nbytes;
       
   368     /*LINTED*/
       
   369     if ( mptr > largest_addr ) largest_addr = mptr;
       
   370     /*LINTED*/
       
   371     if ( mptr < smallest_addr || smallest_addr == NULL ) smallest_addr = mptr;
       
   372 
       
   373     /* Must be done first: */
       
   374     nsize1_(mptr) = -nbytes;
       
   375     nsize2_(mptr) = -nbytes;
       
   376     tail_nsize1_(mptr) = -nbytes;
       
   377     tail_nsize2_(mptr) = -nbytes;
       
   378 
       
   379 #ifdef LEFT_OVER_CHAR
       
   380     /* Fill in those few extra bytes just before the tail Word structure */
       
   381     {
       
   382         register int    trailing_extra_bytes;
       
   383         /* LINTED */
       
   384         trailing_extra_bytes = (int) (round_up_(nbytes) - nbytes);
       
   385         if (  trailing_extra_bytes > 0 ) {
       
   386             register char  *p;
       
   387             register int    i;
       
   388             p = ((char *) mptr) + sizeof(Word) + nbytes;
       
   389             for (i = 0; i < trailing_extra_bytes; i++)
       
   390                 p[i] = LEFT_OVER_CHAR;
       
   391         }
       
   392     }
       
   393 #endif
       
   394 
       
   395     /* Fill out warrant */
       
   396     if (malloc_watch) {
       
   397         static Warrant_Record zero_warrant;
       
   398         register void  *p1,
       
   399                        *p2;
       
   400         size_t len;
       
   401         int start_pos = 0;
       
   402         warrant_(mptr) = zero_warrant;
       
   403         p1 = warrant_name_(mptr);
       
   404         len = strlen(file);
       
   405         if ( len >  WARRANT_NAME_MAX )  {
       
   406             /*LINTED*/
       
   407             start_pos = (int)len - WARRANT_NAME_MAX;
       
   408         }
       
   409         p2 = ((char*)file) + start_pos;
       
   410         /*LINTED*/
       
   411         (void) memcpy(p1, p2, minimum(((int)len), WARRANT_NAME_MAX));
       
   412         warrant_line_(mptr) = line;
       
   413         warrant_id_(mptr)   = ++id_counter;
       
   414         warrant_link_(mptr) = first_warrant_mptr;
       
   415         first_warrant_mptr = mptr;
       
   416     }
       
   417 }
       
   418 
       
   419 /* This function checks the clobber words at the beginning and end of the
       
   420  *   allocated space.
       
   421  */
       
   422 static void
       
   423 memory_check(void *uptr, int mid, const char *mfile, int mline, const char *file, int line)
       
   424 {
       
   425     int             neg_nbytes;
       
   426     int             nbytes;
       
   427 
       
   428     debug_check = "pointer value itself";
       
   429     clobbered_ptr = uptr;
       
   430     if (uptr == NULL)
       
   431         memory_error((void *) NULL, "memory_check", mid, mfile, mline, file, line);
       
   432 
       
   433     /* Check both Word structures */
       
   434 
       
   435     debug_check = "first beginning clobber word";
       
   436     clobbered_ptr = (char*)&user_nsize1_(uptr);
       
   437     neg_nbytes = user_nsize1_(uptr);
       
   438     if (neg_nbytes >= 0)
       
   439         memory_error(user2malloc_(uptr), "memory_check", mid, mfile, mline, file, line);
       
   440 
       
   441     debug_check = "second beginning clobber word";
       
   442     clobbered_ptr = (char*)&user_nsize2_(uptr);
       
   443     if (neg_nbytes != user_nsize2_(uptr))
       
   444         memory_error(user2malloc_(uptr), "memory_check", mid, mfile, mline, file, line);
       
   445 
       
   446     debug_check = "first ending clobber word";
       
   447     clobbered_ptr = (char*)&user_tail_nsize1_(uptr);
       
   448     if (neg_nbytes != user_tail_nsize1_(uptr))
       
   449         memory_error(user2malloc_(uptr), "memory_check", mid, mfile, mline, file, line);
       
   450 
       
   451     debug_check = "second ending clobber word";
       
   452     clobbered_ptr = (char*)&user_tail_nsize2_(uptr);
       
   453     if (neg_nbytes != user_tail_nsize2_(uptr))
       
   454         memory_error(user2malloc_(uptr), "memory_check", mid, mfile, mline, file, line);
       
   455 
       
   456     /* Get a positive count of bytes */
       
   457     nbytes = -neg_nbytes;
       
   458 
       
   459 #ifdef LEFT_OVER_CHAR
       
   460     {
       
   461         /* Check those few extra bytes just before the tail Word structure */
       
   462         register int    trailing_extra_bytes;
       
   463         register int    i;
       
   464         register char  *p;
       
   465         /* LINTED */
       
   466         trailing_extra_bytes = (int) (round_up_(nbytes) - nbytes);
       
   467         p = ((char *) (uptr)) + nbytes;
       
   468         debug_check = "trailing left over area";
       
   469         for (i = 0; i < trailing_extra_bytes; i++) {
       
   470             clobbered_ptr = p+1;
       
   471             if (p[i] != LEFT_OVER_CHAR) {
       
   472                 memory_error(user2malloc_(uptr), "memory_check", mid, mfile, mline, file, line);
       
   473             }
       
   474         }
       
   475     }
       
   476 #endif
       
   477 
       
   478     /* Make sure debug_check is cleared */
       
   479     debug_check = NULL;
       
   480 }
       
   481 
       
   482 /* This function looks for the given malloc pointer in the police line up
       
   483  *   and removes it from the warrant list.
       
   484  *      mptr            The pointer to the malloc space being removed
       
   485  */
       
   486 static int
       
   487 remove_warrant(void *mptr)
       
   488 {
       
   489     void           *mptr1,
       
   490                    *last_mptr1;
       
   491 
       
   492     /* Free it up from the list */
       
   493     if (malloc_watch && mptr != NULL) {
       
   494         int found;
       
   495 
       
   496         found = 0;
       
   497         last_mptr1 = NULL;
       
   498         mptr1 = first_warrant_mptr;
       
   499         while (mptr1 != NULL) {
       
   500             if (mptr1 == mptr) {
       
   501                 if (last_mptr1 == NULL)
       
   502                     first_warrant_mptr = warrant_link_(mptr1);
       
   503                 else
       
   504                     warrant_link_(last_mptr1) = warrant_link_(mptr1);
       
   505                 found = 1;
       
   506                 break;
       
   507             }
       
   508             last_mptr1 = mptr1;
       
   509             mptr1 = warrant_link_(mptr1);
       
   510         }
       
   511         return found;
       
   512     }
       
   513     return 1;
       
   514 }
       
   515 
       
   516 static void
       
   517 actual_free(void *uptr, const char *file, int line)
       
   518 {
       
   519     void *mptr;
       
   520     const char *mfile;
       
   521     int mline;
       
   522     int mid;
       
   523     if ( uptr == NULL )
       
   524         return;
       
   525     mptr = user2malloc_(uptr);
       
   526     memory_check(uptr, (mid=MID(mptr)), (mfile=MFILE(mptr)), (mline=MLINE(mptr)), file, line);
       
   527     if (malloc_watch && remove_warrant(mptr)==0 )
       
   528         memory_check(uptr, mid, mfile, mline, file, line);
       
   529 #ifdef FREED_CHAR
       
   530     if ( mptr!=NULL ) {
       
   531         size_t nbytes = -nsize1_(mptr);
       
   532         /* LINTED */
       
   533         (void)memset(mptr, FREED_CHAR, rbytes_(nbytes));
       
   534     }
       
   535 #endif
       
   536     free(mptr);
       
   537 }
       
   538 
       
   539 #ifdef MAX_FREE_DELAY_COUNT
       
   540 
       
   541 static void *free_delay[MAX_FREE_DELAY_COUNT];
       
   542 static int free_delay_pos = 0;
       
   543 
       
   544 static void
       
   545 delayed_free(void *uptr, const char* file, int line)
       
   546 {
       
   547     void *mptr;
       
   548     void *olduptr = free_delay[free_delay_pos];
       
   549     size_t nbytes;
       
   550     if ( uptr==NULL )
       
   551         return;
       
   552     mptr = user2malloc_(uptr);
       
   553     memory_check(uptr, MID(mptr), MFILE(mptr), MLINE(mptr), file, line);
       
   554     if ( olduptr!=NULL ) {
       
   555         actual_free(olduptr, file, line);
       
   556     }
       
   557     free_delay[free_delay_pos] = uptr;
       
   558     free_delay_pos++;
       
   559     free_delay_pos = free_delay_pos % MAX_FREE_DELAY_COUNT;
       
   560     nbytes = -user_nsize1_(uptr);
       
   561 #ifdef FREED_CHAR
       
   562     (void)memset(uptr, FREED_CHAR, (size_t)nbytes);
       
   563 #endif
       
   564 }
       
   565 
       
   566 static void
       
   567 delayed_free_all(const char *file, int line)
       
   568 {
       
   569     int i;
       
   570     for ( i=0; i< MAX_FREE_DELAY_COUNT; i++) {
       
   571         void *olduptr = free_delay[i];
       
   572         free_delay[i] = NULL;
       
   573         if ( olduptr!=NULL ) {
       
   574             actual_free(olduptr, file, line);
       
   575         }
       
   576     }
       
   577 }
       
   578 
       
   579 #endif
       
   580 
       
   581 void
       
   582 debug_free(void *uptr, const char *file, int line)
       
   583 {
       
   584     int mid = 0;
       
   585 
       
   586     if (uptr == NULL)
       
   587         memory_error((void *) NULL, "debug_free", mid, file, line, file, line);
       
   588 #ifdef MAX_FREE_DELAY_COUNT
       
   589     delayed_free(uptr, file, line);
       
   590 #else
       
   591     actual_free(uptr, file, line);
       
   592 #endif
       
   593 }
       
   594 
       
   595 /* This function calls malloc(). */
       
   596 void           *
       
   597 debug_malloc(size_t nbytes, const char *file, int line)
       
   598 {
       
   599     void           *mptr;
       
   600     void           *uptr;
       
   601     int mid = id_counter;
       
   602 
       
   603     /*LINTED*/
       
   604     if ((int)nbytes <= 0)
       
   605         memory_error((void *) NULL, "debug_malloc", mid, file, line, file, line);
       
   606     /* LINTED */
       
   607     mptr = malloc(rbytes_(nbytes));
       
   608     if (mptr == NULL)
       
   609         memory_error((void *) NULL, "debug_malloc", mid, file, line, file, line);
       
   610     setup_space_and_issue_warrant(mptr, nbytes, file, line);
       
   611     uptr = malloc2user_(mptr);
       
   612 #ifdef ALLOC_CHAR
       
   613     (void)memset(uptr, ALLOC_CHAR, (size_t)nbytes);
       
   614 #endif
       
   615     return uptr;
       
   616 }
       
   617 
       
   618 void           *
       
   619 debug_realloc(void *uptr, size_t nbytes, const char *file, int line)
       
   620 {
       
   621     void           *mptr;
       
   622     void           *oldmptr;
       
   623     void           *newuptr;
       
   624     size_t         oldnbytes;
       
   625     int mid = id_counter;
       
   626 
       
   627     oldmptr = user2malloc_(uptr);
       
   628     oldnbytes = 0;
       
   629     if ((int)nbytes <= 0)
       
   630         memory_error(oldmptr, "debug_realloc", mid, file, line, file, line);
       
   631     if (uptr != NULL) {
       
   632         memory_check(uptr, MID(oldmptr), MFILE(oldmptr), MLINE(oldmptr), file, line);
       
   633         oldnbytes = -user_nsize1_(uptr);
       
   634         if ( malloc_watch && remove_warrant(oldmptr)==0 )
       
   635             memory_check(uptr, MID(oldmptr), MFILE(oldmptr), MLINE(oldmptr), file, line);
       
   636     }
       
   637     if (uptr == NULL) {
       
   638         /* LINTED */
       
   639         mptr = malloc(rbytes_(nbytes));
       
   640     } else {
       
   641         /* LINTED */
       
   642         mptr = realloc(oldmptr, rbytes_(nbytes));
       
   643     }
       
   644     if (mptr == NULL)
       
   645         memory_error(oldmptr, "debug_realloc", mid, file, line, file, line);
       
   646     setup_space_and_issue_warrant(mptr, nbytes, file, line);
       
   647     newuptr = malloc2user_(mptr);
       
   648 #ifdef ALLOC_CHAR
       
   649     if (uptr == NULL)
       
   650         (void)memset(newuptr, ALLOC_CHAR, (size_t)nbytes);
       
   651     else if ( nbytes > oldnbytes )
       
   652         (void)memset(((char*)newuptr)+oldnbytes, ALLOC_CHAR, (size_t)nbytes-oldnbytes);
       
   653 #endif
       
   654     return newuptr;
       
   655 }
       
   656 
       
   657 /* This function calls calloc(). */
       
   658 void           *
       
   659 debug_calloc(size_t nelem, size_t elsize, const char *file, int line)
       
   660 {
       
   661     void           *mptr;
       
   662     size_t          nbytes;
       
   663     int mid = id_counter;
       
   664 
       
   665     nbytes = nelem*elsize;
       
   666     /*LINTED*/
       
   667     if ((int)nbytes <= 0)
       
   668         memory_error((void *) NULL, "debug_calloc", mid, file, line, file, line);
       
   669     /* LINTED */
       
   670     mptr = calloc(rbytes_(nbytes),1);
       
   671     if (mptr == NULL)
       
   672         memory_error((void *) NULL, "debug_calloc", mid, file, line, file, line);
       
   673     setup_space_and_issue_warrant(mptr, nbytes, file, line);
       
   674     return malloc2user_(mptr);
       
   675 }
       
   676 
       
   677 /* This function replaces strdup(). */
       
   678 char           *
       
   679 debug_strdup(const char *s1, const char *file, int line)
       
   680 {
       
   681     void           *mptr;
       
   682     void           *uptr;
       
   683     size_t          nbytes;
       
   684     int mid = id_counter;
       
   685 
       
   686     if (s1 == NULL)
       
   687         memory_error((void *) NULL, "debug_strdup", mid, file, line, file, line);
       
   688     nbytes = strlen(s1)+1;
       
   689     /*LINTED*/
       
   690     if ((int)nbytes < 0)
       
   691         memory_error((void *) NULL, "debug_strdup", mid, file, line, file, line);
       
   692     /* LINTED */
       
   693     mptr = malloc(rbytes_(nbytes));
       
   694     if (mptr == NULL)
       
   695         memory_error((void *) NULL, "debug_strdup", mid, file, line, file, line);
       
   696     setup_space_and_issue_warrant(mptr, nbytes, file, line);
       
   697     uptr = malloc2user_(mptr);
       
   698     (void)strcpy((char*)uptr, s1);
       
   699     return (char*)uptr;
       
   700 }
       
   701 
       
   702 void
       
   703 debug_malloc_verify(const char *file, int line)
       
   704 {
       
   705     void           *mptr;
       
   706 
       
   707 #ifdef MAX_FREE_DELAY_COUNT
       
   708     delayed_free_all(file,line);
       
   709 #endif
       
   710 
       
   711     if (!malloc_watch) {
       
   712         return;
       
   713     }
       
   714     mptr = first_warrant_mptr;
       
   715     if (mptr != NULL) {
       
   716         /* Check all this memory first */
       
   717         do {
       
   718             memory_check(malloc2user_(mptr), MID(mptr), MFILE(mptr), MLINE(mptr), file, line);
       
   719             mptr = warrant_link_(mptr);
       
   720         } while (mptr != NULL);
       
   721     }
       
   722 }
       
   723 
       
   724 /* Report outstanding space warrants to console. */
       
   725 void
       
   726 debug_malloc_police(const char *file, int line)
       
   727 {
       
   728     void           *mptr;
       
   729 
       
   730 #ifdef MAX_FREE_DELAY_COUNT
       
   731     delayed_free_all(file,line);
       
   732 #endif
       
   733 
       
   734     if (!malloc_watch) {
       
   735         return;
       
   736     }
       
   737 
       
   738     mptr = first_warrant_mptr;
       
   739     if (mptr != NULL) {
       
   740         debug_malloc_verify(file, line);
       
   741         /* Now issue warrants */
       
   742         mptr = first_warrant_mptr;
       
   743         do {
       
   744             error_message("Outstanding space warrant: %p (%d bytes) allocated by %s at line %d, allocation #%d",
       
   745                mptr, -nsize1_(mptr), warrant_name_(mptr),
       
   746                warrant_line_(mptr), warrant_id_(mptr));
       
   747 
       
   748             mptr = warrant_link_(mptr);
       
   749         } while (mptr != NULL);
       
   750     }
       
   751 }
       
   752 
       
   753 #else
       
   754 
       
   755 void
       
   756 debug_malloc_verify(const char *file, int line)
       
   757 {
       
   758     file = file;
       
   759     line = line;
       
   760 }
       
   761 
       
   762 void
       
   763 debug_malloc_police(const char *file, int line)
       
   764 {
       
   765     file = file;
       
   766     line = line;
       
   767 }
       
   768 
       
   769 #endif