/* ** Copyright (c) 1994, University of Kansas, All Rights Reserved ** ** This code will be used only if LY_FIND_LEAKS is defined. ** ** Revision History: ** 05-26-94 created Lynx 2-3-1 Garrett Arch Blythe ** 10-30-97 modified to handle StrAllocCopy() and ** StrAllocCat(). - KW & FM */ /* ** Disable the overriding of the memory routines for this file. */ #define NO_MEMORY_TRACKING #include #include #include #include #include #ifdef LY_FIND_LEAKS PRIVATE AllocationList *ALp_RunTimeAllocations = NULL; #define LEAK_SUMMARY #ifdef LEAK_SUMMARY PRIVATE long now_allocated = 0; PRIVATE long peak_alloced = 0; PRIVATE long total_alloced = 0; PRIVATE long total_freed = 0; PRIVATE long count_mallocs = 0; PRIVATE long count_frees = 0; PRIVATE void CountMallocs ARGS1(long, size) { ++count_mallocs; total_alloced += size; now_allocated += size; if (peak_alloced < now_allocated) peak_alloced = now_allocated; } PRIVATE void CountFrees ARGS1(long, size) { ++count_frees; total_freed += size; now_allocated -= size; } #else #define CountMallocs() ++count_mallocs #define CountFrees() /* nothing */ #endif /* ** Purpose: Add a new allocation item to the list. ** Arguments: ALp_new The new item to add. ** Return Value: void ** Remarks/Portability/Dependencies/Restrictions: ** Static function made to make code reusable in projects beyond ** Lynx (some might ask why not use HTList). ** Revision History: ** 05-26-94 created Lynx 2-3-1 Garrett Arch Blythe */ PRIVATE void AddToList ARGS1( AllocationList *, ALp_new) { /* * Just make this the first item in the list. */ ALp_new->ALp_Next = ALp_RunTimeAllocations; ALp_RunTimeAllocations = ALp_new; } /* ** Purpose: Find the place in the list where vp_find is currently ** tracked. ** Arguments: vp_find A pointer to look for in the list. ** Return Value: AllocationList * Either vp_find's place in the ** list or NULL if not found. ** Remarks/Portability/Dependencies/Restrictions: ** Static function made to make code reusable in projects outside ** of Lynx (some might ask why not use HTList). ** Revision History: ** 05-26-94 created Lynx 2-3-1 Garrett Arch Blythe */ PRIVATE AllocationList *FindInList ARGS1( void *, vp_find) { AllocationList *ALp_find = ALp_RunTimeAllocations; /* * Go through the list of allocated pointers until end of list * or vp_find is found. */ while (ALp_find != NULL) { if (ALp_find->vp_Alloced == vp_find) { break; } ALp_find = ALp_find->ALp_Next; } return(ALp_find); } /* ** Purpose: Remove the specified item from the list. ** Arguments: ALp_del The item to remove from the list. ** Return Value: void ** Remarks/Portability/Dependencies/Restrictions: ** Static function made to make code reusable in projects outside ** of Lynx (some might ask why not use HTList). ** Revision History: ** 05-26-94 created Lynx 2-3-1 Garrett Arch Blythe */ PRIVATE void RemoveFromList ARGS1( AllocationList *, ALp_del) { AllocationList *ALp_findbefore = ALp_RunTimeAllocations; /* * There is one special case, where the item to remove is the * first in the list. */ if (ALp_del == ALp_findbefore) { ALp_RunTimeAllocations = ALp_del->ALp_Next; return; } /* * Loop through checking all of the next values, if a match * don't continue. Always assume the item will be found. */ while (ALp_findbefore->ALp_Next != ALp_del) { ALp_findbefore = ALp_findbefore->ALp_Next; } /* * We are one item before the one to get rid of. * Get rid of it. */ ALp_findbefore->ALp_Next = ALp_del->ALp_Next; } /* * Make the malloc-sequence available for debugging/tracing. */ PUBLIC long LYLeakSequence NOARGS { return count_mallocs; } /* ** Purpose: Print a report of all memory left unallocated by ** Lynx code or attempted unallocations on ** pointers that are not valid and then free ** all unfreed memory. ** Arguments: void ** Return Value: void ** Remarks/Portability/Dependencies/Restrictions: ** This function should be registered for execution with the ** atexit (stdlib.h) function as the first statement ** in main. ** All output of this function is sent to the file defined in ** the header LYLeaks.h (LEAKAGE_SINK). */ PUBLIC void LYLeaks NOARGS { AllocationList *ALp_head; size_t st_total = (size_t)0; FILE *Fp_leakagesink; if (LYfind_leaks == FALSE) return; /* * Open the leakage sink to take all the output. * Recreate the file each time. * Do nothing if unable to open the file. */ Fp_leakagesink = LYNewTxtFile(LEAKAGE_SINK); if (Fp_leakagesink == NULL) { return; } while (ALp_RunTimeAllocations != NULL) { /* * Take the head off of the run time allocation list. */ ALp_head = ALp_RunTimeAllocations; ALp_RunTimeAllocations = ALp_head->ALp_Next; /* * Print the type of leak/error. * Free off memory when we no longer need it. */ if (ALp_head->vp_Alloced == NULL) { /* * If there is realloc information on the * bad request, then it was a bad pointer * value in a realloc statement. */ fprintf(Fp_leakagesink, "%s.\n", gettext("Invalid pointer detected.")); fprintf(Fp_leakagesink, "%s\t%ld\n", gettext("Sequence:"), ALp_head->st_Sequence); fprintf(Fp_leakagesink, "%s\t%p\n", gettext("Pointer:"), ALp_head->vp_BadRequest); /* * Don't free the bad request, it is an invalid pointer. * If the free source information is empty, we * should check the realloc information * too since it can get passed bad pointer * values also. */ if (ALp_head->SL_memory.cp_FileName == NULL) { fprintf(Fp_leakagesink, "%s\t%s\n", gettext("FileName:"), ALp_head->SL_realloc.cp_FileName); fprintf(Fp_leakagesink, "%s\t%d\n", gettext("LineCount:"), ALp_head->SL_realloc.ssi_LineNumber); } else { fprintf(Fp_leakagesink, "%s\t%s\n", gettext("FileName:"), ALp_head->SL_memory.cp_FileName); fprintf(Fp_leakagesink, "%s\t%d\n", gettext("LineCount:"), ALp_head->SL_memory.ssi_LineNumber); } } else { size_t i_counter; char *value = (char *)(ALp_head->vp_Alloced); /* * Increment the count of total memory lost and * then print the information. */ st_total += ALp_head->st_Bytes; fprintf(Fp_leakagesink, "%s\n", gettext("Memory leak detected.")); fprintf(Fp_leakagesink, "%s\t%ld\n", gettext("Sequence:"), ALp_head->st_Sequence); fprintf(Fp_leakagesink, "%s\t%p\n", gettext("Pointer:"), ALp_head->vp_Alloced); fprintf(Fp_leakagesink, "%s\t", gettext("Contains:")); for (i_counter = 0; i_counter < ALp_head->st_Bytes && i_counter < MAX_CONTENT_LENGTH; i_counter++) { if (isprint(UCH(value[i_counter]))) { fprintf(Fp_leakagesink, "%c", value[i_counter]); } else { fprintf(Fp_leakagesink, "|"); } } fprintf(Fp_leakagesink, "\n"); fprintf(Fp_leakagesink, "%s\t%d\n", gettext("ByteSize:"), (int)(ALp_head->st_Bytes)); fprintf(Fp_leakagesink, "%s\t%s\n", gettext("FileName:"), ALp_head->SL_memory.cp_FileName); fprintf(Fp_leakagesink, "%s\t%d\n", gettext("LineCount:"), ALp_head->SL_memory.ssi_LineNumber); /* * Give the last time the pointer was realloced * if it happened also. */ if (ALp_head->SL_realloc.cp_FileName != NULL) { fprintf(Fp_leakagesink, "%s\t%s\n", gettext("realloced:"), ALp_head->SL_realloc.cp_FileName); fprintf(Fp_leakagesink, "%s\t%d\n", gettext("LineCount:"), ALp_head->SL_realloc.ssi_LineNumber); } fflush(Fp_leakagesink); FREE(ALp_head->vp_Alloced); } /* * Create a blank line and release the memory held * by the item. */ fprintf(Fp_leakagesink, "\n"); FREE(ALp_head); } /* * Give a grand total of the leakage. * Close the output file. */ fprintf(Fp_leakagesink, "%s\t%u\n", gettext("Total memory leakage this run:"), (unsigned)st_total); #ifdef LEAK_SUMMARY fprintf(Fp_leakagesink, "%s\t%ld\n", gettext("Peak allocation"), peak_alloced); fprintf(Fp_leakagesink, "%s\t%ld\n", gettext("Bytes allocated"), total_alloced); fprintf(Fp_leakagesink, "%s\t%ld\n", gettext("Total mallocs"), count_mallocs); fprintf(Fp_leakagesink, "%s\t%ld\n", gettext("Total frees"), count_frees); #endif fclose(Fp_leakagesink); HTSYS_purge(LEAKAGE_SINK); #if defined(NCURSES) && defined(HAVE__NC_FREEALL) _nc_freeall(); #endif } /* ** Purpose: Capture allocations using malloc (stdlib.h) and track ** the information in a list. ** Arguments: st_bytes The size of the allocation requested ** in bytes. ** cp_File The file from which the request for ** allocation came from. ** ssi_Line The line number in cp_File where the ** allocation request came from. ** Return Value: void * A pointer to the allocated memory or NULL on ** failure as per malloc (stdlib.h) ** Remarks/Portability/Dependencies/Restrictions: ** If no memory is allocated, then no entry is added to the ** allocation list. ** Revision History: ** 05-26-94 created Lynx 2-3-1 Garrett Arch Blythe */ PUBLIC void *LYLeakMalloc ARGS3( size_t, st_bytes, CONST char *, cp_File, CONST short, ssi_Line) { void *vp_malloc; if (LYfind_leaks == FALSE) return (void *)malloc(st_bytes); /* * Do the actual allocation. */ vp_malloc = (void *)malloc(st_bytes); CountMallocs(st_bytes); /* * Only on successful allocation do we track any information. */ if (vp_malloc != NULL) { /* * Further allocate memory to store the information. * Just return on failure to allocate more. */ AllocationList *ALp_new = typecalloc(AllocationList); if (ALp_new == NULL) { return(vp_malloc); } /* * Copy over the relevant information. * There is no need to allocate more memory for the * file name as it is a static string anyhow. */ ALp_new->st_Sequence = count_mallocs; ALp_new->vp_Alloced = vp_malloc; ALp_new->st_Bytes = st_bytes; ALp_new->SL_memory.cp_FileName = cp_File; ALp_new->SL_memory.ssi_LineNumber = ssi_Line; /* * Add the new item to the allocation list. */ AddToList(ALp_new); } return(vp_malloc); } /* ** Purpose: Add information about new allocation to the list, ** after a call to malloc or calloc or an equivalent ** function which may or may not have already created ** a list entry. ** Arguments: vp_malloc The pointer to newly allocated memory. ** Arguments: st_bytes The size of the allocation requested ** in bytes. ** cp_File The file from which the request for ** allocation came from. ** ssi_Line The line number in cp_File where the ** allocation request came from. ** Return Value: void * A pointer to the allocated memory or NULL on ** failure. ** Remarks/Portability/Dependencies/Restrictions: ** If no memory is allocated, then no entry is added to the ** allocation list. ** Revision History: ** 1999-02-08 created, modelled after LYLeakMalloc - kw */ PUBLIC AllocationList *LYLeak_mark_malloced ARGS4( void *, vp_malloced, size_t, st_bytes, CONST char *, cp_File, CONST short, ssi_Line) { AllocationList *ALp_new = NULL; if (LYfind_leaks == FALSE) return NULL; /* * The actual allocation has already been done! * * Only on successful allocation do we track any information. */ if (vp_malloced != NULL) { /* * See if there is already an entry. If so, just * update the source location info. */ ALp_new = FindInList(vp_malloced); if (ALp_new) { ALp_new->SL_memory.cp_FileName = cp_File; ALp_new->SL_memory.ssi_LineNumber = ssi_Line; return(ALp_new); } /* * Further allocate memory to store the information. * Just return on failure to allocate more. */ ALp_new = typecalloc(AllocationList); if (ALp_new == NULL) { return(NULL); } /* * Copy over the relevant information. */ ALp_new->vp_Alloced = vp_malloced; ALp_new->st_Bytes = st_bytes; ALp_new->SL_memory.cp_FileName = cp_File; ALp_new->SL_memory.ssi_LineNumber = ssi_Line; /* * Add the new item to the allocation list. */ AddToList(ALp_new); } return(ALp_new); } /* ** Purpose: Capture allocations by calloc (stdlib.h) and ** save relevant information in a list. ** Arguments: st_number The number of items to allocate. ** st_bytes The size of each item. ** cp_File The file which wants to allocation. ** ssi_Line The line number in cp_File requesting ** the allocation. ** Return Value: void * The allocated memory, or NULL on failure as ** per calloc (stdlib.h) ** Remarks/Portability/Dependencies/Restrictions: ** If no memory can be allocated, then no entry will be added ** to the list. ** Revision History: ** 05-26-94 created Lynx 2-3-1 Garrett Arch Blythe */ PUBLIC void *LYLeakCalloc ARGS4( size_t, st_number, size_t, st_bytes, CONST char *, cp_File, CONST short, ssi_Line) { void *vp_calloc; if (LYfind_leaks == FALSE) return (void *)calloc(st_number, st_bytes); /* * Allocate the requested memory. */ vp_calloc = (void *)calloc(st_number, st_bytes); CountMallocs(st_bytes); /* * Only if the allocation was a success do we track information. */ if (vp_calloc != NULL) { /* * Allocate memory for the item to be in the list. * If unable, just return. */ AllocationList *ALp_new = typecalloc(AllocationList); if (ALp_new == NULL) { return(vp_calloc); } /* * Copy over the relevant information. * There is no need to allocate memory for the file * name as it is a static string anyway. */ ALp_new->st_Sequence = count_mallocs; ALp_new->vp_Alloced = vp_calloc; ALp_new->st_Bytes = (st_number * st_bytes); ALp_new->SL_memory.cp_FileName = cp_File; ALp_new->SL_memory.ssi_LineNumber = ssi_Line; /* * Add the item to the allocation list. */ AddToList(ALp_new); } return(vp_calloc); } /* ** Purpose: Capture any realloc (stdlib.h) calls in order to ** properly keep track of our run time allocation ** table. ** Arguments: vp_Alloced The previously allocated block of ** memory to resize. If NULL, ** realloc works just like ** malloc. ** st_newBytes The new size of the chunk of memory. ** cp_File The file containing the realloc. ** ssi_Line The line containing the realloc in cp_File. ** Return Value: void * The new pointer value (could be the same) or ** NULL if unable to resize (old block ** still exists). ** Remarks/Portability/Dependencies/Restrictions: ** If unable to resize vp_Alloced, then no change in the ** allocation list will be made. ** If vp_Alloced is an invalid pointer value, the program will ** exit after one last entry is added to the allocation list. ** Revision History: ** 05-26-94 created Lynx 2-3-1 Garrett Arch Blythe */ PUBLIC void *LYLeakRealloc ARGS4( void *, vp_Alloced, size_t, st_newBytes, CONST char *, cp_File, CONST short, ssi_Line) { void *vp_realloc; AllocationList *ALp_renew; if (LYfind_leaks == FALSE) return (void *)realloc(vp_Alloced, st_newBytes); /* * If we are asked to resize a NULL pointer, this is just a * malloc call. */ if (vp_Alloced == NULL) { return(LYLeakMalloc(st_newBytes, cp_File, ssi_Line)); } /* * Find the current vp_Alloced block in the list. * If NULL, this is an invalid pointer value. */ ALp_renew = FindInList(vp_Alloced); if (ALp_renew == NULL) { /* * Track the invalid pointer value and then exit. * If unable to allocate, just exit. */ auto AllocationList *ALp_new = typecalloc(AllocationList); if (ALp_new == NULL) { exit(EXIT_FAILURE); } /* * Set the information up; no need to allocate file name * since it is a static string. */ ALp_new->vp_Alloced = NULL; ALp_new->vp_BadRequest = vp_Alloced; ALp_new->SL_realloc.cp_FileName = cp_File; ALp_new->SL_realloc.ssi_LineNumber = ssi_Line; /* * Add the item to the list. * Exit. */ AddToList(ALp_new); exit(EXIT_FAILURE); } /* * Perform the resize. * If not NULL, record the information. */ vp_realloc = (void *)realloc(vp_Alloced, st_newBytes); CountMallocs(st_newBytes); CountFrees(ALp_renew->st_Bytes); if (vp_realloc != NULL) { ALp_renew->st_Sequence = count_mallocs; ALp_renew->vp_Alloced = vp_realloc; ALp_renew->st_Bytes = st_newBytes; /* * Update the realloc information, too. * No need to allocate file name, static string. */ ALp_renew->SL_realloc.cp_FileName = cp_File; ALp_renew->SL_realloc.ssi_LineNumber = ssi_Line; } return(vp_realloc); } /* ** Purpose: Add information about reallocated memory to the list, ** after a call to realloc or an equivalent ** function which has not already created or updated ** a list entry. ** Arguments: ALp_old List entry for previously allocated ** block of memory to resize. If NULL, ** mark_realloced works just like ** mark_malloced. ** vp_realloced The new pointer, after resizing. ** st_newBytes The new size of the chunk of memory. ** cp_File The file to record. ** ssi_Line The line to record. ** Return Value: Pointer to new or updated list entry ** for this memory block. ** NULL on allocation error. ** Revision History: ** 1999-02-11 created kw */ #if defined(LY_FIND_LEAKS) && defined(LY_FIND_LEAKS_EXTENDED) PRIVATE AllocationList *mark_realloced ARGS5( AllocationList *, ALp_old, void *, vp_realloced, size_t, st_newBytes, CONST char *, cp_File, CONST short, ssi_Line) { /* * If there is no list entry for the old allocation, treat this * as if a new allocation had happened. */ if (ALp_old == NULL) { return(LYLeak_mark_malloced( vp_realloced, st_newBytes, cp_File, ssi_Line)); } /* * ALp_old represents the memory block before reallocation. * Assume that if we get here, there isn't yet a list entry * for the new, possibly different, address after realloc, * that is our list hasn't been updated - so we're going to * do that now. */ if (vp_realloced != NULL) { ALp_old->vp_Alloced = vp_realloced; ALp_old->st_Bytes = st_newBytes; ALp_old->SL_realloc.cp_FileName = cp_File; ALp_old->SL_realloc.ssi_LineNumber = ssi_Line; } return(ALp_old); } #endif /* not LY_FIND_LEAKS and LY_FIND_LEAKS_EXTENDED */ /* ** Purpose: Capture all requests to free information and also ** remove items from the allocation list. ** Arguments: vp_Alloced The memory to free. ** cp_File The file calling free. ** ssi_Line The line of cp_File calling free. ** Return Value: void ** Remarks/Portability/Dependencies/Restrictions: ** If the pointer value is invalid, then an item will be added ** to the list and nothing else is done. ** I really like the name of this function and one day hope ** that Lynx is Leak Free. ** Revision History: ** 05-26-94 created Lynx 2-3-1 Garrett Arch Blythe */ PUBLIC void LYLeakFree ARGS3( void *, vp_Alloced, CONST char *, cp_File, CONST short, ssi_Line) { AllocationList *ALp_free; if (LYfind_leaks == FALSE) { free(vp_Alloced); return; } /* * Find the pointer in the allocated list. * If not found, bad pointer. * If found, free list item and vp_Allloced. */ ALp_free = FindInList(vp_Alloced); if (ALp_free == NULL) { /* * Create the final entry before exiting marking this error. * If unable to allocate more memory just exit. */ AllocationList *ALp_new = typecalloc(AllocationList); if (ALp_new == NULL) { exit(EXIT_FAILURE); } /* * Set up the information, no memory need be allocated * for the file name since it is a static string. */ ALp_new->vp_Alloced = NULL; ALp_new->vp_BadRequest = vp_Alloced; ALp_new->SL_memory.cp_FileName = cp_File; ALp_new->SL_memory.ssi_LineNumber = ssi_Line; /* * Add the entry to the list and then return. */ AddToList(ALp_new); return; } else { /* * Free off the memory. * Take entry out of allocation list. */ CountFrees(ALp_free->st_Bytes); RemoveFromList(ALp_free); FREE(ALp_free); FREE(vp_Alloced); } } /* ** Allocates a new copy of a string, and returns it. ** Tracks allocations by using other LYLeakFoo functions. ** Equivalent to HTSACopy in HTUtils.c - KW */ PUBLIC char * LYLeakSACopy ARGS4( char **, dest, CONST char *, src, CONST char *, cp_File, CONST short, ssi_Line) { if (src != NULL && src == *dest) { CTRACE((tfp, "LYLeakSACopy: *dest equals src, contains \"%s\"\n", src)); return *dest; } if (*dest) { LYLeakFree(*dest, cp_File, ssi_Line); *dest = NULL; } if (src) { *dest = (char *)LYLeakMalloc(strlen(src) + 1, cp_File, ssi_Line); if (*dest == NULL) outofmem(__FILE__, "LYLeakSACopy"); strcpy (*dest, src); } return *dest; } /* ** String Allocate and Concatenate. ** Tracks allocations by using other LYLeakFoo functions. ** Equivalent to HTSACat in HTUtils.c - KW */ PUBLIC char * LYLeakSACat ARGS4( char **, dest, CONST char *, src, CONST char *, cp_File, CONST short, ssi_Line) { if (src && *src) { if (src == *dest) { CTRACE((tfp, "LYLeakSACat: *dest equals src, contains \"%s\"\n", src)); return *dest; } if (*dest) { int length = strlen(*dest); *dest = (char *)LYLeakRealloc(*dest, (length + strlen(src) + 1), cp_File, ssi_Line); if (*dest == NULL) outofmem(__FILE__, "LYLeakSACat"); strcpy (*dest + length, src); } else { *dest = (char *)LYLeakMalloc((strlen(src) + 1), cp_File, ssi_Line); if (*dest == NULL) outofmem(__FILE__, "LYLeakSACat"); strcpy (*dest, src); } } return *dest; } #if defined(LY_FIND_LEAKS) && defined(LY_FIND_LEAKS_EXTENDED) PUBLIC CONST char * leak_cp_File_hack = __FILE__; PUBLIC short leak_ssi_Line_hack = __LINE__; /* ** Purpose: A wrapper around StrAllocVsprintf (the workhorse of ** HTSprintf/HTSprintf0, implemented in HTString.c) that ** tries to make sure that our allocation list is always ** properly updated, whether StrAllocVsprintf itself was ** compiled with memory tracking or not (or even a mixture, ** like tracking the freeing but not the new allocation). ** Some source files can be compiled with LY_FIND_LEAKS_EXTENDED ** in effect while others only have LY_FIND_LEAKS in effect, ** and as long as HTString.c is complied with memory tracking ** (of either kind) string objects allocated by HTSprintf/ ** HTSprintf0 (or otherwise) can be passed around among them and ** manipulated both ways. ** Arguments: dest As for StrAllocVsprintf. ** cp_File The source file of the caller (i.e. the ** caller of HTSprintf/HTSprintf0, hopefully). ** ssi_Line The line of cp_File calling. ** inuse,fmt,ap As for StrAllocVsprintf. ** Return Value: The char pointer to resulting string, as set ** by StrAllocVsprintf, or ** NULL if dest==0 (wrong use!). ** Remarks/Portability/Dependencies/Restrictions: ** The price for generality is severe inefficiency: several ** list lookups are done to be on the safe side. ** We don't get he real allocation size, only a minimum based ** on the string length of the result. So the amount of memory ** leakage may get underestimated. ** If *dest is an invalid pointer value on entry (i.e. was not ** tracked), the program will exit after one last entry is added ** to the allocation list. ** If StrAllocVsprintf fails to return a valid string via the ** indirect string pointer (its first parameter), invalid memory ** access will result and the program will probably terminate ** with a signal. This can happen if, on entry, *dest is NULL ** and fmt is empty or NULL, so just Don't Do That. ** Revision History: ** 1999-02-11 created kw ** 1999-10-15 added comments kw */ PRIVATE char * LYLeakSAVsprintf ARGS6( char **, dest, CONST char *, cp_File, CONST short, ssi_Line, size_t, inuse, CONST char *, fmt, va_list *, ap) { AllocationList *ALp_old; void *vp_oldAlloced; CONST char * old_cp_File = __FILE__; short old_ssi_Line = __LINE__; if (!dest) return NULL; if (LYfind_leaks == FALSE) { StrAllocVsprintf(dest, inuse, fmt, ap); return (*dest); } vp_oldAlloced = *dest; if (!vp_oldAlloced) { StrAllocVsprintf(dest, inuse, fmt, ap); LYLeak_mark_malloced(*dest, strlen(*dest) + 1, cp_File, ssi_Line); return(*dest); } else { void * vp_realloced; ALp_old = FindInList(vp_oldAlloced); if (ALp_old == NULL) { /* * Track the invalid pointer value and then exit. * If unable to allocate, just exit. */ auto AllocationList *ALp_new = typecalloc(AllocationList); if (ALp_new == NULL) { exit(EXIT_FAILURE); } /* * Set the information up; no need to allocate file name * since it is a static string. */ ALp_new->vp_Alloced = NULL; ALp_new->vp_BadRequest = vp_oldAlloced; ALp_new->SL_realloc.cp_FileName = cp_File; ALp_new->SL_realloc.ssi_LineNumber = ssi_Line; /* * Add the item to the list. * Exit. */ AddToList(ALp_new); exit(EXIT_FAILURE); } old_cp_File = ALp_old->SL_memory.cp_FileName; old_ssi_Line = ALp_old->SL_memory.ssi_LineNumber; /* * DO THE REAL WORK, by calling StrAllocVsprintf. * If result is not NULL, record the information. */ StrAllocVsprintf(dest, inuse, fmt, ap); vp_realloced = (void *)*dest; if (vp_realloced != NULL) { AllocationList *ALp_new = FindInList(vp_realloced); if (!ALp_new) { /* Look up again, list may have changed! - kw */ ALp_old = FindInList(vp_oldAlloced); if (ALp_old == NULL) { LYLeak_mark_malloced(*dest, strlen(*dest) + 1, cp_File, ssi_Line); return(*dest); } mark_realloced(ALp_old, *dest, strlen(*dest) + 1, cp_File, ssi_Line); return(*dest); } if (vp_realloced == vp_oldAlloced) { ALp_new->SL_memory.cp_FileName = old_cp_File; ALp_new->SL_memory.ssi_LineNumber = old_ssi_Line; ALp_new->SL_realloc.cp_FileName = cp_File; ALp_new->SL_realloc.ssi_LineNumber = ssi_Line; return(*dest); } /* Look up again, list may have changed! - kw */ ALp_old = FindInList(vp_oldAlloced); if (ALp_old == NULL) { ALp_new->SL_memory.cp_FileName = old_cp_File; ALp_new->SL_memory.ssi_LineNumber = old_ssi_Line; ALp_new->SL_realloc.cp_FileName = cp_File; ALp_new->SL_realloc.ssi_LineNumber = ssi_Line; } else { ALp_new->SL_memory.cp_FileName = old_cp_File; ALp_new->SL_memory.ssi_LineNumber = old_ssi_Line; ALp_new->SL_realloc.cp_FileName = cp_File; ALp_new->SL_realloc.ssi_LineNumber = ssi_Line; } } return(*dest); } } /* Note: the following may need updating if HTSprintf in HTString.c * is changed. - kw */ #ifdef ANSI_VARARGS PRIVATE char * LYLeakHTSprintf (char **pstr, CONST char *fmt, ...) #else PRIVATE char * LYLeakHTSprintf (va_alist) va_dcl #endif { char *str; size_t inuse = 0; va_list ap; LYva_start(ap,fmt); { #ifndef ANSI_VARARGS char ** pstr = va_arg(ap, char **); CONST char * fmt = va_arg(ap, CONST char *); #endif if (pstr != 0 && *pstr != 0) inuse = strlen(*pstr); str = LYLeakSAVsprintf(pstr, leak_cp_File_hack, leak_ssi_Line_hack, inuse, fmt, &ap); } va_end(ap); return str; } /* Note: the following may need updating if HTSprintf0 in HTString.c * is changed. - kw */ #ifdef ANSI_VARARGS PRIVATE char * LYLeakHTSprintf0 (char **pstr, CONST char *fmt, ...) #else PRIVATE char * LYLeakHTSprintf0 (va_alist) va_dcl #endif { char *str; va_list ap; LYva_start(ap,fmt); { #ifndef ANSI_VARARGS char ** pstr = va_arg(ap, char **); CONST char * fmt = va_arg(ap, CONST char *); #endif str = LYLeakSAVsprintf(pstr, leak_cp_File_hack, leak_ssi_Line_hack, 0, fmt, &ap); } va_end(ap); return str; } /* * HTSprintf and HTSprintf0 will be defined such that they effectively * call one of the following two functions that store away a copy to * the File & Line info in temporary hack variables, and then call * the real function (which is returned here as a function pointer) * to the regular HTSprintf/HTSprintf0 arguments. * It's probably a bit inefficient, but that shouldn't be noticeable * compared to all the time that memory tracking takes up for list * traversal. - kw */ PUBLIC HTSprintflike *Get_htsprintf_fn ARGS2( CONST char *, cp_File, CONST short, ssi_Line) { leak_cp_File_hack = cp_File; leak_ssi_Line_hack = ssi_Line; return &LYLeakHTSprintf; } PUBLIC HTSprintflike *Get_htsprintf0_fn ARGS2( CONST char *, cp_File, CONST short, ssi_Line) { leak_cp_File_hack = cp_File; leak_ssi_Line_hack = ssi_Line; return &LYLeakHTSprintf0; } #endif /* LY_FIND_LEAKS and LY_FIND_LEAKS_EXTENDED */ #else /* Standard C forbids an empty file */ void no_leak_checking NOPARAMS; void no_leak_checking NOARGS { } #endif /* LY_FIND_LEAKS */