Blame src/LYLeaks.c

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