home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Dream 52
/
Amiga_Dream_52.iso
/
Linux
/
Divers
/
lynx2.8.1dev.10.tar.gz
/
lynx2.8.1dev.10.tar
/
lynx2-8
/
src
/
LYLeaks.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-03-25
|
16KB
|
608 lines
/*
** Copyright (c) 1994, University of Kansas, All Rights Reserved
**
** This code will be used only if LY_FIND_LEAKS is defined.
*/
/*
** Disable the overriding of the memory routines for this file.
*/
#define NO_MEMORY_TRACKING
#include <HTUtils.h>
#include <tcp.h>
#include <LYexit.h>
#include <LYLeaks.h>
#include <LYUtils.h>
#include <ctype.h>
/*#include <stdio.h> included by HTUtils.h -- FM */
#define FREE(x) if (x) {free(x); x = NULL;}
PRIVATE AllocationList *ALp_RunTimeAllocations = NULL;
PRIVATE void AddToList PARAMS((
AllocationList * ALp_new));
PRIVATE AllocationList *FindInList PARAMS((
void * vp_find));
PRIVATE void RemoveFromList PARAMS((
AllocationList * ALp_del));
/*
** 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).
** Revision History:
** 05-26-94 created Lynx 2-3-1 Garrett Arch Blythe
** 10-30-97 modified to handle StrAllocCopy() and
** StrAllocCat(). - KW & FM
*/
PUBLIC void LYLeaks NOARGS
{
AllocationList *ALp_head;
size_t st_total = (size_t)0;
FILE *Fp_leakagesink;
/*
* 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,
"Invalid pointer detected.\n");
fprintf(Fp_leakagesink,
"Pointer:\t%p\n", 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, "FileName:\t%s\n",
ALp_head->SL_realloc.cp_FileName);
fprintf(Fp_leakagesink, "LineCount:\t%d\n",
ALp_head->SL_realloc.ssi_LineNumber);
} else {
fprintf(Fp_leakagesink, "FileName:\t%s\n",
ALp_head->SL_memory.cp_FileName);
fprintf(Fp_leakagesink, "LineCount:\t%d\n",
ALp_head->SL_memory.ssi_LineNumber);
}
} else {
size_t i_counter;
/*
* Increment the count of total memory lost and
* then print the information.
*/
st_total += ALp_head->st_Bytes;
fprintf(Fp_leakagesink, "Memory leak detected.\n");
fprintf(Fp_leakagesink, "Pointer:\t%p\n", ALp_head->vp_Alloced);
fprintf(Fp_leakagesink, "Contains:\t");
for (i_counter = 0;
i_counter < ALp_head->st_Bytes &&
i_counter < MAX_CONTENT_LENGTH;
i_counter++) {
if (isprint(((char *)(ALp_head->vp_Alloced))[i_counter])) {
fprintf(Fp_leakagesink, "%c",
((char *)(ALp_head->vp_Alloced))[i_counter]);
} else {
fprintf(Fp_leakagesink, "|");
}
}
fprintf(Fp_leakagesink, "\n");
FREE(ALp_head->vp_Alloced);
fprintf(Fp_leakagesink, "ByteSize:\t%d\n",
(int)(ALp_head->st_Bytes));
fprintf(Fp_leakagesink, "FileName:\t%s\n",
ALp_head->SL_memory.cp_FileName);
fprintf(Fp_leakagesink, "LineCount:\t%d\n",
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, "realloced:\t%s\n",
ALp_head->SL_realloc.cp_FileName);
fprintf(Fp_leakagesink, "LineCount:\t%d\n",
ALp_head->SL_realloc.ssi_LineNumber);
}
}
/*
* 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, "\nTotal memory leakage this run:\t%u\n",
(unsigned)st_total);
fclose(Fp_leakagesink);
#ifdef VMS
{
char VMSfilename[256];
/*
* Purge lower versions of the file.
*/
sprintf(VMSfilename, "%s;-1", LEAKAGE_SINK);
while (remove(VMSfilename) == 0)
;
/*
* Reset version number.
*/
sprintf(VMSfilename, "%s;1", LEAKAGE_SINK);
rename(LEAKAGE_SINK, VMSfilename);
}
#endif /* VMS */
}
/*
** 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)
{
/*
* Do the actual allocation.
*/
void *vp_malloc = (void *)malloc(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 =
(AllocationList *)calloc(1, sizeof(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->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: 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)
{
/*
* Allocate the requested memory.
*/
void *vp_calloc = (void *)calloc(st_number, 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 =
(AllocationList *)calloc(1, sizeof(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->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 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 =
(AllocationList *)calloc(1,
sizeof(AllocationList));
if (ALp_new == NULL) {
exit(-1);
}
/*
* 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(-1);
}
/*
* Perform the resize.
* If not NULL, record the information.
*/
vp_realloc = (void *)realloc(vp_Alloced, st_newBytes);
if (vp_realloc != NULL) {
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: 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;
/*
* 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 =
(AllocationList *)calloc(1,
sizeof(AllocationList));
if (ALp_new == NULL) {
exit(-1);
}
/*
* 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.
*/
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 (*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 (*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;
}
/*
** 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;
}