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
error_message(const char * format,...)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
memory_error(void * mptr,const char * name,int mid,const char * mfile,int mline,const char * file,int line)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
setup_space_and_issue_warrant(void * mptr,size_t size,const char * file,int line)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
memory_check(void * uptr,int mid,const char * mfile,int mline,const char * file,int line)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
remove_warrant(void * mptr)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
actual_free(void * uptr,const char * file,int line)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
delayed_free(void * uptr,const char * file,int line)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
delayed_free_all(const char * file,int line)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
debug_free(void * uptr,const char * file,int line)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           *
debug_malloc(size_t nbytes,const char * file,int line)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           *
debug_realloc(void * uptr,size_t nbytes,const char * file,int line)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           *
debug_calloc(size_t nelem,size_t elsize,const char * file,int line)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           *
debug_strdup(const char * s1,const char * file,int line)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
debug_malloc_verify(const char * file,int line)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
debug_malloc_police(const char * file,int line)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
debug_malloc_verify(const char * file,int line)756 debug_malloc_verify(const char *file, int line)
757 {
758     file = file;
759     line = line;
760 }
761 
762 void
debug_malloc_police(const char * file,int line)763 debug_malloc_police(const char *file, int line)
764 {
765     file = file;
766     line = line;
767 }
768 
769 #endif
770