diff -r 836adbf7a2cd -r 3317bb8137f4 jdk/src/demo/share/jvmti/hprof/debug_malloc.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/demo/share/jvmti/hprof/debug_malloc.c Sun Aug 17 15:54:13 2014 +0100 @@ -0,0 +1,769 @@ +/* + * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This source code is provided to illustrate the usage of a given feature + * or technique and has been deliberately simplified. Additional steps + * required for a production-quality application, such as security checks, + * input validation and proper error handling, might not be present in + * this sample code. + */ + + +/* ************************************************************************** + * + * Set of malloc/realloc/calloc/strdup/free replacement macros that + * insert some extra words around each allocation for debugging purposes + * and also attempt to detect invalid uses of the malloc heap through + * various tricks like inserting clobber words at the head and tail of + * the user's area, delayed free() calls, and setting the memory to + * a fixed pattern on allocation and when freed. The allocations also + * can include warrants so that when an area is clobbered, this + * package can report where the allocation took place. + * The macros included are: + * malloc(size) + * realloc(ptr,size) + * calloc(nelem,elsize) + * strdup(s1) + * free(ptr) + * malloc_police() <--- Not a system function + * The above macros match the standard behavior of the system functions. + * + * They should be used through the include file "debug_malloc.h". + * + * IMPORTANT: All source files that call any of these macros + * should include debug_malloc.h. This package will + * not work if the memory isn't allocated and freed + * by the macros in debug_malloc.h. The important issue + * is that any malloc() from debug_malloc.h must be + * freed by the free() in debug_malloc.h. + * + * The macros in debug_malloc.h will override the normal use of + * malloc, realloc, calloc, strdup, and free with the functions below. + * + * These functions include: + * void *debug_malloc(size_t, void*, int); + * void *debug_realloc(void*, size_t, void*, int); + * void *debug_calloc(size_t, size_t, void*, int); + * void debug_free(void *, void*, int); + * + * In addition the function debug_malloc_police() can be called to + * tell you what memory has not been freed. + * void debug_malloc_police(void*, int); + * The function debug_malloc_police() is available through the macro + * malloc_police(). Normally you would want to call this at exit() + * time to find out what memory is still allocated. + * + * The variable malloc_watch determines if the warrants are generated. + * warrants are structures that include the filename and line number + * of the caller who allocated the memory. This structure is stored + * at the tail of the malloc space, which is allocated large enough + * to hold some clobber words at the head and tail, the user's request + * and the warrant record (if malloc_watch is non-zero). + * + * The macro LEFT_OVER_CHAR is what the trailing bytes of an allocation + * are set to (when the allocation is not a multiple of 8) on allocation. + * At free(0 time, these bytes are double checked to make sure they were + * not clobbered. To remove this feature #undef LEFT_OVER_CHAR. + * + * The memory freed will have the FREED_CHAR put into it. To remove this + * feature #undef FREED_CHAR. + * + * The memory allocated (not calloc'd) will have the ALLOC_CHAR put into it + * at the time of allocation. To remove this feature #undef ALLOC_CHAR. + * + * The macro MAX_FREE_DELAY_COUNT controls how many free blocks will + * be kept around before being freed. This creates a delayed affect + * so that free space that gets clobbered just might get detected. + * The free() call will immediately set the user space to the FREED_CHAR, + * leaving the clobber words and warrant in place (making sure they + * haven't been clobbered). Then the free() pointer is added to a + * queue of MAX_FREE_DELAY_COUNT long, and if the queue was full, the + * oldest free()'d memory is actually freed, getting it's entire + * memory length set to the FREED_CHAR. + * + * WARNING: This can significantly slow down an application, depending + * on how many allocations are made. Also the additional memory + * needed for the clobber words and the warrants can be significant + * again, depending on how many allocations are made. + * In addition, the delayed free calls can create situations + * where you might run out of memory prematurely. + * + * ************************************************************************** + */ + +#ifdef DEBUG + +#include +#include +#include +#include +#include +#include "hprof.h" + +/* *************************************************************************** + * Space normally looks like (clobber Word is 64 bits and aligned to 8 bytes): + * + * ----------------- + * malloc/free get->| clobber Word | ---> contains -size requested by user + * ----------------- + * User gets --->| user space | + * | | + * | | left_over | ---> left_over bytes will be <= 7 + * ----------------- + * | clobber Word | ---> contains -size requested by user + * ----------------- + * | Warrant | ---> Optional (malloc_watch!=0) + * | | Contains filename and line number + * | | where allocation happened + * | | + * ----------------- + ***************************************************************************/ + +/* + * Flag that tells debug_malloc/debug_free/debug_realloc to police + * heap space usage. (This is a dynamic flag that can be turned on/off) + */ +static int malloc_watch = 1; + +/* Character to stuff into freed space */ +#define FREED_CHAR 'F' + +/* Character to stuff into allocated space */ +#define ALLOC_CHAR 'A' + +/* Character to stuff into left over trailing bytes */ +#define LEFT_OVER_CHAR 'Z' + +/* Number of 'free' calls that will be delayed until the end */ +#define MAX_FREE_DELAY_COUNT 1 +#undef MAX_FREE_DELAY_COUNT + +/* Maximum name of __FILE_ stored in each malloc'd area */ +#define WARRANT_NAME_MAX (32-1) /* 1 less than multiple of 8 is best */ + +/* Macro to convert a user pointer to the malloc pointer */ +#define user2malloc_(uptr) (((char*)(void*)uptr)-sizeof(Word)) + +/* Macro to convert a macro pointer to the user pointer */ +#define malloc2user_(mptr) (((char*)(void*)(mptr))+sizeof(Word)) + +/* Size of the warrant record (this is dynamic) */ +#define warrant_space ( malloc_watch?sizeof(Warrant_Record):0 ) + +/* Macro to round up a number of bytes to a multiple of sizeof(Word) bytes */ +#define round_up_(n) \ + ((n)==0?0:(sizeof(Word)+(((n)-1)/sizeof(Word))*sizeof(Word))) + +/* Macro to calculate the needed malloc bytes from the user's request. */ +#define rbytes_(nbytes) \ + (size_t)( sizeof(Word) + round_up_(nbytes) + sizeof(Word) + warrant_space ) + +/* Macro to get the -size stored in space through the malloc pointer */ +#define nsize1_(mptr) (((Word*)(void*)(mptr))->nsize1) +#define nsize2_(mptr) (((Word*)(void*)(mptr))->nsize2) + +/* Macro to get the -size stored in the tail of the space through */ +/* the malloc pointer */ +#define tail_nsize1_(mptr) \ + nsize1_(((char*)(void*)(mptr))+round_up_(-nsize1_(mptr))+sizeof(Word)) +#define tail_nsize2_(mptr) \ + nsize2_(((char*)(void*)(mptr))+round_up_(-nsize1_(mptr))+sizeof(Word)) + +/* Macro to get the -size stored in space through the user pointer */ +#define user_nsize1_(uptr) nsize1_(user2malloc_(uptr)) +#define user_nsize2_(uptr) nsize2_(user2malloc_(uptr)) + +/* Macro to get the -size stored in the tail of the space through */ +/* the user pointer */ +#define user_tail_nsize1_(uptr) tail_nsize1_(user2malloc_(uptr)) +#define user_tail_nsize2_(uptr) tail_nsize2_(user2malloc_(uptr)) + +/* Macro to get the int* of the last 32bit word of user space */ +#define last_user_word_(mptr) \ + ((int*)(((char*)(void*)(mptr))+round_up_(-nsize1_(mptr)))) + +/* Macros to get at the warrant contents from the malloc pointer */ +#define warrant_(mptr) \ + (*((Warrant_Record*)(void*)(((char*)(void*)(mptr))+round_up_(-nsize1_(mptr))+sizeof(Word)*2))) + +/* This struct is allocated after the tail clobber word if malloc_watch */ +/* is true. */ +typedef struct { + void *link; /* Next mptr in list */ + char name[WARRANT_NAME_MAX + 1]; /* Name of allocator */ + int line; /* Line number where allocated */ + int id; /* Nth allocation */ +} Warrant_Record; +#define warrant_link_(mptr) warrant_(mptr).link +#define warrant_name_(mptr) warrant_(mptr).name +#define warrant_line_(mptr) warrant_(mptr).line +#define warrant_id_(mptr) warrant_(mptr).id +#define MFILE(mptr) (malloc_watch?warrant_name_(mptr):"?") +#define MLINE(mptr) (malloc_watch?warrant_line_(mptr):0) +#define MID(mptr) (malloc_watch?warrant_id_(mptr):0) + +/* This should be one machine word and is also the clobber word struct */ +typedef struct { + int nsize1; + int nsize2; +} Word; /* Largest basic type , sizeof(double)? */ + +/* The first malloc pointer for the warrants */ +static void *first_warrant_mptr = NULL; + +/* Counter of allocations */ +static int id_counter = 0; +static int largest_size = 0; +static void * largest_addr = NULL; +static void * smallest_addr = NULL; + +/* Used to isolate what the error is */ +static char *debug_check; +static void *clobbered_ptr; + +/* Minimum macro */ +#define minimum(a,b) ((a)<(b)?(a):(b)) + +/* Message routine */ +static void +error_message(const char * format, ...) +{ + FILE *error_fp = stderr; /* All debug_malloc.c messages */ + va_list ap; + va_start(ap, format); + (void)fprintf(error_fp, "debug_malloc: "); + (void)vfprintf(error_fp, format, ap); + (void)fprintf(error_fp, "\n"); + (void)fflush(error_fp); + va_end(ap); +} + +/* This function prints out a memory error for the memory function + * 'name' which was called in file 'file' at line number 'line'. The malloc + * pointer with the error is in 'mptr'. + */ +static void +memory_error(void *mptr, const char *name, int mid, const char *mfile, int mline, const char *file, int line) +{ + char nice_words[512]; + char temp[256]; + int len; + void *mptr_walk; + + if (name == NULL) + name = "UNKNOWN_NAME"; + if (file == NULL) + file = "UNKNOWN_FILE"; + md_system_error(temp, (int)sizeof(temp)); + (void)strcpy(nice_words, temp); + if ( debug_check!=NULL ) { + (void)md_snprintf(nice_words, sizeof(nice_words), + "%s The %s at %p appears to have been hit.", + temp, debug_check, clobbered_ptr); + } + len = -nsize1_(mptr); + error_message("Error: " + "%s The malloc space #%d is at %p [user size=%d(0x%x)]," + " and was allocated from file \"%s\" at line %d." + " [The debug function %s() detected this error " + "in file \"%s\" at line %d.]", + nice_words, mid, mptr, len, len, mfile, mline, + name, file, line); + + /* Print out contents of this allocation */ + { + int i; + void *uptr = malloc2user_(mptr); + char *pmess; + pmess = temp; + for(i=0;i<(int)sizeof(temp);i++) { + int ch = ((unsigned char*)uptr)[i]; + if ( isprint(ch) ) { + *pmess++ = ch; + } else { + *pmess++ = '\\'; + *pmess++ = 'x'; + (void)sprintf(pmess,"%02x",ch); + pmess+=2; + } + } + *pmess = 0; + error_message("Error: %p contains user data: %s", uptr, temp); + } + + /* Try and print out table */ + if (!malloc_watch) { + return; + } + mptr_walk = first_warrant_mptr; + if (mptr_walk != NULL) { + error_message("Active allocations: " + "count=%d, largest_size=%d, address range (%p,%p)", + id_counter, largest_size, smallest_addr, largest_addr); + do { + int size1; + int size2; + char *mfile_walk; + + if ( mptr_walk > largest_addr || mptr_walk < smallest_addr ) { + error_message("Terminating list due to pointer corruption"); + break; + } + size1 = -nsize1_(mptr_walk); + size2 = -nsize2_(mptr_walk); + mfile_walk = MFILE(mptr_walk); + error_message("#%d: addr=%p size1=%d size2=%d file=\"%.*s\" line=%d", + MID(mptr_walk), mptr_walk, size1, size2, + WARRANT_NAME_MAX, mfile_walk, MLINE(mptr_walk)); + if ( size1 != size2 || size1 > largest_size || size1 < 0 ) { + error_message("Terminating list due to size corruption"); + break; + } + mptr_walk = warrant_link_(mptr_walk); + } while (mptr_walk != NULL); + } + abort(); +} + +/* This function sets the clobber word and sets up the warrant for the input + * malloc pointer "mptr". + */ +static void +setup_space_and_issue_warrant(void *mptr, size_t size, const char *file, int line) +{ + register int nbytes; + + /*LINTED*/ + nbytes = (int)size; + if ( nbytes > largest_size || largest_addr == NULL ) largest_size = nbytes; + /*LINTED*/ + if ( mptr > largest_addr ) largest_addr = mptr; + /*LINTED*/ + if ( mptr < smallest_addr || smallest_addr == NULL ) smallest_addr = mptr; + + /* Must be done first: */ + nsize1_(mptr) = -nbytes; + nsize2_(mptr) = -nbytes; + tail_nsize1_(mptr) = -nbytes; + tail_nsize2_(mptr) = -nbytes; + +#ifdef LEFT_OVER_CHAR + /* Fill in those few extra bytes just before the tail Word structure */ + { + register int trailing_extra_bytes; + /* LINTED */ + trailing_extra_bytes = (int) (round_up_(nbytes) - nbytes); + if ( trailing_extra_bytes > 0 ) { + register char *p; + register int i; + p = ((char *) mptr) + sizeof(Word) + nbytes; + for (i = 0; i < trailing_extra_bytes; i++) + p[i] = LEFT_OVER_CHAR; + } + } +#endif + + /* Fill out warrant */ + if (malloc_watch) { + static Warrant_Record zero_warrant; + register void *p1, + *p2; + size_t len; + int start_pos = 0; + warrant_(mptr) = zero_warrant; + p1 = warrant_name_(mptr); + len = strlen(file); + if ( len > WARRANT_NAME_MAX ) { + /*LINTED*/ + start_pos = (int)len - WARRANT_NAME_MAX; + } + p2 = ((char*)file) + start_pos; + /*LINTED*/ + (void) memcpy(p1, p2, minimum(((int)len), WARRANT_NAME_MAX)); + warrant_line_(mptr) = line; + warrant_id_(mptr) = ++id_counter; + warrant_link_(mptr) = first_warrant_mptr; + first_warrant_mptr = mptr; + } +} + +/* This function checks the clobber words at the beginning and end of the + * allocated space. + */ +static void +memory_check(void *uptr, int mid, const char *mfile, int mline, const char *file, int line) +{ + int neg_nbytes; + int nbytes; + + debug_check = "pointer value itself"; + clobbered_ptr = uptr; + if (uptr == NULL) + memory_error((void *) NULL, "memory_check", mid, mfile, mline, file, line); + + /* Check both Word structures */ + + debug_check = "first beginning clobber word"; + clobbered_ptr = (char*)&user_nsize1_(uptr); + neg_nbytes = user_nsize1_(uptr); + if (neg_nbytes >= 0) + memory_error(user2malloc_(uptr), "memory_check", mid, mfile, mline, file, line); + + debug_check = "second beginning clobber word"; + clobbered_ptr = (char*)&user_nsize2_(uptr); + if (neg_nbytes != user_nsize2_(uptr)) + memory_error(user2malloc_(uptr), "memory_check", mid, mfile, mline, file, line); + + debug_check = "first ending clobber word"; + clobbered_ptr = (char*)&user_tail_nsize1_(uptr); + if (neg_nbytes != user_tail_nsize1_(uptr)) + memory_error(user2malloc_(uptr), "memory_check", mid, mfile, mline, file, line); + + debug_check = "second ending clobber word"; + clobbered_ptr = (char*)&user_tail_nsize2_(uptr); + if (neg_nbytes != user_tail_nsize2_(uptr)) + memory_error(user2malloc_(uptr), "memory_check", mid, mfile, mline, file, line); + + /* Get a positive count of bytes */ + nbytes = -neg_nbytes; + +#ifdef LEFT_OVER_CHAR + { + /* Check those few extra bytes just before the tail Word structure */ + register int trailing_extra_bytes; + register int i; + register char *p; + /* LINTED */ + trailing_extra_bytes = (int) (round_up_(nbytes) - nbytes); + p = ((char *) (uptr)) + nbytes; + debug_check = "trailing left over area"; + for (i = 0; i < trailing_extra_bytes; i++) { + clobbered_ptr = p+1; + if (p[i] != LEFT_OVER_CHAR) { + memory_error(user2malloc_(uptr), "memory_check", mid, mfile, mline, file, line); + } + } + } +#endif + + /* Make sure debug_check is cleared */ + debug_check = NULL; +} + +/* This function looks for the given malloc pointer in the police line up + * and removes it from the warrant list. + * mptr The pointer to the malloc space being removed + */ +static int +remove_warrant(void *mptr) +{ + void *mptr1, + *last_mptr1; + + /* Free it up from the list */ + if (malloc_watch && mptr != NULL) { + int found; + + found = 0; + last_mptr1 = NULL; + mptr1 = first_warrant_mptr; + while (mptr1 != NULL) { + if (mptr1 == mptr) { + if (last_mptr1 == NULL) + first_warrant_mptr = warrant_link_(mptr1); + else + warrant_link_(last_mptr1) = warrant_link_(mptr1); + found = 1; + break; + } + last_mptr1 = mptr1; + mptr1 = warrant_link_(mptr1); + } + return found; + } + return 1; +} + +static void +actual_free(void *uptr, const char *file, int line) +{ + void *mptr; + const char *mfile; + int mline; + int mid; + if ( uptr == NULL ) + return; + mptr = user2malloc_(uptr); + memory_check(uptr, (mid=MID(mptr)), (mfile=MFILE(mptr)), (mline=MLINE(mptr)), file, line); + if (malloc_watch && remove_warrant(mptr)==0 ) + memory_check(uptr, mid, mfile, mline, file, line); +#ifdef FREED_CHAR + if ( mptr!=NULL ) { + size_t nbytes = -nsize1_(mptr); + /* LINTED */ + (void)memset(mptr, FREED_CHAR, rbytes_(nbytes)); + } +#endif + free(mptr); +} + +#ifdef MAX_FREE_DELAY_COUNT + +static void *free_delay[MAX_FREE_DELAY_COUNT]; +static int free_delay_pos = 0; + +static void +delayed_free(void *uptr, const char* file, int line) +{ + void *mptr; + void *olduptr = free_delay[free_delay_pos]; + size_t nbytes; + if ( uptr==NULL ) + return; + mptr = user2malloc_(uptr); + memory_check(uptr, MID(mptr), MFILE(mptr), MLINE(mptr), file, line); + if ( olduptr!=NULL ) { + actual_free(olduptr, file, line); + } + free_delay[free_delay_pos] = uptr; + free_delay_pos++; + free_delay_pos = free_delay_pos % MAX_FREE_DELAY_COUNT; + nbytes = -user_nsize1_(uptr); +#ifdef FREED_CHAR + (void)memset(uptr, FREED_CHAR, (size_t)nbytes); +#endif +} + +static void +delayed_free_all(const char *file, int line) +{ + int i; + for ( i=0; i< MAX_FREE_DELAY_COUNT; i++) { + void *olduptr = free_delay[i]; + free_delay[i] = NULL; + if ( olduptr!=NULL ) { + actual_free(olduptr, file, line); + } + } +} + +#endif + +void +debug_free(void *uptr, const char *file, int line) +{ + int mid = 0; + + if (uptr == NULL) + memory_error((void *) NULL, "debug_free", mid, file, line, file, line); +#ifdef MAX_FREE_DELAY_COUNT + delayed_free(uptr, file, line); +#else + actual_free(uptr, file, line); +#endif +} + +/* This function calls malloc(). */ +void * +debug_malloc(size_t nbytes, const char *file, int line) +{ + void *mptr; + void *uptr; + int mid = id_counter; + + /*LINTED*/ + if ((int)nbytes <= 0) + memory_error((void *) NULL, "debug_malloc", mid, file, line, file, line); + /* LINTED */ + mptr = malloc(rbytes_(nbytes)); + if (mptr == NULL) + memory_error((void *) NULL, "debug_malloc", mid, file, line, file, line); + setup_space_and_issue_warrant(mptr, nbytes, file, line); + uptr = malloc2user_(mptr); +#ifdef ALLOC_CHAR + (void)memset(uptr, ALLOC_CHAR, (size_t)nbytes); +#endif + return uptr; +} + +void * +debug_realloc(void *uptr, size_t nbytes, const char *file, int line) +{ + void *mptr; + void *oldmptr; + void *newuptr; + size_t oldnbytes; + int mid = id_counter; + + oldmptr = user2malloc_(uptr); + oldnbytes = 0; + if ((int)nbytes <= 0) + memory_error(oldmptr, "debug_realloc", mid, file, line, file, line); + if (uptr != NULL) { + memory_check(uptr, MID(oldmptr), MFILE(oldmptr), MLINE(oldmptr), file, line); + oldnbytes = -user_nsize1_(uptr); + if ( malloc_watch && remove_warrant(oldmptr)==0 ) + memory_check(uptr, MID(oldmptr), MFILE(oldmptr), MLINE(oldmptr), file, line); + } + if (uptr == NULL) { + /* LINTED */ + mptr = malloc(rbytes_(nbytes)); + } else { + /* LINTED */ + mptr = realloc(oldmptr, rbytes_(nbytes)); + } + if (mptr == NULL) + memory_error(oldmptr, "debug_realloc", mid, file, line, file, line); + setup_space_and_issue_warrant(mptr, nbytes, file, line); + newuptr = malloc2user_(mptr); +#ifdef ALLOC_CHAR + if (uptr == NULL) + (void)memset(newuptr, ALLOC_CHAR, (size_t)nbytes); + else if ( nbytes > oldnbytes ) + (void)memset(((char*)newuptr)+oldnbytes, ALLOC_CHAR, (size_t)nbytes-oldnbytes); +#endif + return newuptr; +} + +/* This function calls calloc(). */ +void * +debug_calloc(size_t nelem, size_t elsize, const char *file, int line) +{ + void *mptr; + size_t nbytes; + int mid = id_counter; + + nbytes = nelem*elsize; + /*LINTED*/ + if ((int)nbytes <= 0) + memory_error((void *) NULL, "debug_calloc", mid, file, line, file, line); + /* LINTED */ + mptr = calloc(rbytes_(nbytes),1); + if (mptr == NULL) + memory_error((void *) NULL, "debug_calloc", mid, file, line, file, line); + setup_space_and_issue_warrant(mptr, nbytes, file, line); + return malloc2user_(mptr); +} + +/* This function replaces strdup(). */ +char * +debug_strdup(const char *s1, const char *file, int line) +{ + void *mptr; + void *uptr; + size_t nbytes; + int mid = id_counter; + + if (s1 == NULL) + memory_error((void *) NULL, "debug_strdup", mid, file, line, file, line); + nbytes = strlen(s1)+1; + /*LINTED*/ + if ((int)nbytes < 0) + memory_error((void *) NULL, "debug_strdup", mid, file, line, file, line); + /* LINTED */ + mptr = malloc(rbytes_(nbytes)); + if (mptr == NULL) + memory_error((void *) NULL, "debug_strdup", mid, file, line, file, line); + setup_space_and_issue_warrant(mptr, nbytes, file, line); + uptr = malloc2user_(mptr); + (void)strcpy((char*)uptr, s1); + return (char*)uptr; +} + +void +debug_malloc_verify(const char *file, int line) +{ + void *mptr; + +#ifdef MAX_FREE_DELAY_COUNT + delayed_free_all(file,line); +#endif + + if (!malloc_watch) { + return; + } + mptr = first_warrant_mptr; + if (mptr != NULL) { + /* Check all this memory first */ + do { + memory_check(malloc2user_(mptr), MID(mptr), MFILE(mptr), MLINE(mptr), file, line); + mptr = warrant_link_(mptr); + } while (mptr != NULL); + } +} + +/* Report outstanding space warrants to console. */ +void +debug_malloc_police(const char *file, int line) +{ + void *mptr; + +#ifdef MAX_FREE_DELAY_COUNT + delayed_free_all(file,line); +#endif + + if (!malloc_watch) { + return; + } + + mptr = first_warrant_mptr; + if (mptr != NULL) { + debug_malloc_verify(file, line); + /* Now issue warrants */ + mptr = first_warrant_mptr; + do { + error_message("Outstanding space warrant: %p (%d bytes) allocated by %s at line %d, allocation #%d", + mptr, -nsize1_(mptr), warrant_name_(mptr), + warrant_line_(mptr), warrant_id_(mptr)); + + mptr = warrant_link_(mptr); + } while (mptr != NULL); + } +} + +#else + +void +debug_malloc_verify(const char *file, int line) +{ + file = file; + line = line; +} + +void +debug_malloc_police(const char *file, int line) +{ + file = file; + line = line; +} + +#endif