"Fossies" - the Fresh Open Source Software Archive

Member "lynx2.9.0dev.1/src/LYLeaks.c" (27 Dec 2018, 32570 Bytes) of package /linux/www/lynx2.9.0dev.1.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "LYLeaks.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.8.9_vs_2.9.0dev.1.

    1 /*
    2  * $LynxId: LYLeaks.c,v 1.43 2018/12/27 23:48:37 Kamil.Dudka Exp $
    3  *
    4  *  Copyright (c) 1994, University of Kansas, All Rights Reserved
    5  *  (this file was rewritten twice - 1998/1999 and 2003/2004)
    6  *
    7  *  This code will be used only if LY_FIND_LEAKS is defined.
    8  *
    9  *  Revision History:
   10  *  05-26-94    created Lynx 2-3-1 Garrett Arch Blythe
   11  *  10-30-97    modified to handle StrAllocCopy() and
   12  *            StrAllocCat(). - KW & FM
   13  *  07-23-07    free leaks of THIS module too -TD
   14  *  02-09-12    add bstring functions -TD
   15  */
   16 
   17 /*
   18  *  Disable the overriding of the memory routines for this file.
   19  */
   20 #define NO_MEMORY_TRACKING
   21 
   22 #include <HTUtils.h>
   23 #include <LYexit.h>
   24 #include <LYLeaks.h>
   25 #include <LYUtils.h>
   26 #include <LYGlobalDefs.h>
   27 
   28 #ifdef LY_FIND_LEAKS
   29 
   30 static AllocationList *ALp_RunTimeAllocations = NULL;
   31 
   32 #define LEAK_SUMMARY
   33 
   34 #ifdef LEAK_SUMMARY
   35 
   36 static size_t now_allocated = 0;
   37 static size_t peak_alloced = 0;
   38 
   39 static size_t total_alloced = 0;
   40 static size_t total_freed = 0;
   41 
   42 static long count_mallocs = 0;
   43 static long count_frees = 0;
   44 
   45 static void CountMallocs(size_t size)
   46 {
   47     ++count_mallocs;
   48     total_alloced += size;
   49     now_allocated += size;
   50     if (peak_alloced < now_allocated)
   51     peak_alloced = now_allocated;
   52 }
   53 
   54 static void CountFrees(size_t size)
   55 {
   56     ++count_frees;
   57     total_freed += size;
   58     now_allocated -= size;
   59 }
   60 
   61 #else
   62 #define CountMallocs(size) ++count_mallocs
   63 #define CountFrees(size)    /* nothing */
   64 #endif
   65 
   66 /*
   67  *  Purpose:    Add a new allocation item to the list.
   68  *  Arguments:      ALp_new The new item to add.
   69  *  Return Value:   void
   70  *  Remarks/Portability/Dependencies/Restrictions:
   71  *      Static function made to make code reusable in projects beyond
   72  *      Lynx (some might ask why not use HTList).
   73  *  Revision History:
   74  *  05-26-94    created Lynx 2-3-1 Garrett Arch Blythe
   75  */
   76 static void AddToList(AllocationList * ALp_new)
   77 {
   78     /*
   79      * Just make this the first item in the list.
   80      */
   81     ALp_new->ALp_Next = ALp_RunTimeAllocations;
   82     ALp_RunTimeAllocations = ALp_new;
   83 }
   84 
   85 /*
   86  *  Purpose:    Find the place in the list where vp_find is currently
   87  *      tracked.
   88  *  Arguments:      vp_find A pointer to look for in the list.
   89  *  Return Value:   AllocationList *    Either vp_find's place in the
   90  *                      list or NULL if not found.
   91  *  Remarks/Portability/Dependencies/Restrictions:
   92  *      Static function made to make code reusable in projects outside
   93  *      of Lynx (some might ask why not use HTList).
   94  *  Revision History:
   95  *  05-26-94    created Lynx 2-3-1 Garrett Arch Blythe
   96  */
   97 static AllocationList *FindInList(void *vp_find)
   98 {
   99     AllocationList *ALp_find = ALp_RunTimeAllocations;
  100 
  101     /*
  102      * Go through the list of allocated pointers until end of list or vp_find
  103      * is found.
  104      */
  105     while (ALp_find != NULL) {
  106     if (ALp_find->vp_Alloced == vp_find) {
  107         break;
  108     }
  109     ALp_find = ALp_find->ALp_Next;
  110     }
  111 
  112     return (ALp_find);
  113 }
  114 
  115 /*
  116  *  Purpose:    Remove the specified item from the list.
  117  *  Arguments:      ALp_del The item to remove from the list.
  118  *  Return Value:   void
  119  *  Remarks/Portability/Dependencies/Restrictions:
  120  *      Static function made to make code reusable in projects outside
  121  *      of Lynx (some might ask why not use HTList).
  122  *  Revision History:
  123  *  05-26-94    created Lynx 2-3-1 Garrett Arch Blythe
  124  */
  125 static void RemoveFromList(AllocationList * ALp_del)
  126 {
  127     AllocationList *ALp_findbefore = ALp_RunTimeAllocations;
  128 
  129     /*
  130      * There is one special case, where the item to remove is the first in the
  131      * list.
  132      */
  133     if (ALp_del == ALp_findbefore) {
  134     ALp_RunTimeAllocations = ALp_del->ALp_Next;
  135     } else {
  136 
  137     /*
  138      * Loop through checking all of the next values, if a match don't
  139      * continue.  Always assume the item will be found.
  140      */
  141     while (ALp_findbefore->ALp_Next != ALp_del) {
  142         ALp_findbefore = ALp_findbefore->ALp_Next;
  143     }
  144 
  145     /*
  146      * We are one item before the one to get rid of.  Get rid of it.
  147      */
  148     ALp_findbefore->ALp_Next = ALp_del->ALp_Next;
  149     }
  150 }
  151 
  152 /*
  153  * Make the malloc-sequence available for debugging/tracing.
  154  */
  155 #ifndef LYLeakSequence
  156 long LYLeakSequence(void)
  157 {
  158     return count_mallocs;
  159 }
  160 #endif
  161 
  162 /*
  163  *  Purpose:    Print a report of all memory left unallocated by
  164  *      Lynx code or attempted unallocations on
  165  *      pointers that are not valid and then free
  166  *      all unfreed memory.
  167  *  Arguments:      void
  168  *  Return Value:   void
  169  *  Remarks/Portability/Dependencies/Restrictions:
  170  *      This function should be registered for execution with the
  171  *      atexit (stdlib.h) function as the first statement
  172  *      in main.
  173  *      All output of this function is sent to the file defined in
  174  *      the header LYLeaks.h (LEAKAGE_SINK).
  175  */
  176 void LYLeaks(void)
  177 {
  178     AllocationList *ALp_head;
  179     size_t st_total = (size_t) 0;
  180     FILE *Fp_leakagesink;
  181 
  182     CTRACE((tfp, "entering LYLeaks, flag=%d\n", LYfind_leaks));
  183 
  184     if (LYfind_leaks == FALSE) {
  185     /*
  186      * Free MY leaks too, in case someone else is watching.
  187      */
  188     while (ALp_RunTimeAllocations != NULL) {
  189         ALp_head = ALp_RunTimeAllocations;
  190         ALp_RunTimeAllocations = ALp_head->ALp_Next;
  191         free(ALp_head);
  192     }
  193     return;
  194     }
  195 
  196     /*
  197      * Open the leakage sink to take all the output.  Recreate the file each
  198      * time.  Do nothing if unable to open the file.
  199      */
  200     Fp_leakagesink = LYNewTxtFile(LYLeaksPath);
  201     if (Fp_leakagesink == NULL) {
  202     return;
  203     }
  204 
  205     while (ALp_RunTimeAllocations != NULL) {
  206     /*
  207      * Take the head off of the run time allocation list.
  208      */
  209     ALp_head = ALp_RunTimeAllocations;
  210     ALp_RunTimeAllocations = ALp_head->ALp_Next;
  211 
  212     /*
  213      * Print the type of leak/error.  Release memory when we no longer
  214      * need it.
  215      */
  216     if (ALp_head->vp_Alloced == NULL) {
  217         /*
  218          * If there is realloc information on the bad request, then it was
  219          * a bad pointer value in a realloc statement.
  220          */
  221         fprintf(Fp_leakagesink, "%s.\n",
  222             gettext("Invalid pointer detected."));
  223         fprintf(Fp_leakagesink, "%s\t%ld\n",
  224             gettext("Sequence:"),
  225             ALp_head->st_Sequence);
  226         fprintf(Fp_leakagesink, "%s\t%p\n",
  227             gettext("Pointer:"), ALp_head->vp_BadRequest);
  228 
  229         /*
  230          * Don't free the bad request, it is an invalid pointer.  If the
  231          * free source information is empty, we should check the realloc
  232          * information too since it can get passed bad pointer values also.
  233          */
  234         if (ALp_head->SL_memory.cp_FileName == NULL) {
  235         fprintf(Fp_leakagesink, "%s\t%s\n",
  236             gettext("FileName:"),
  237             ALp_head->SL_realloc.cp_FileName);
  238         fprintf(Fp_leakagesink, "%s\t%d\n",
  239             gettext("LineCount:"),
  240             ALp_head->SL_realloc.ssi_LineNumber);
  241         } else {
  242         fprintf(Fp_leakagesink, "%s\t%s\n",
  243             gettext("FileName:"),
  244             ALp_head->SL_memory.cp_FileName);
  245         fprintf(Fp_leakagesink, "%s\t%d\n",
  246             gettext("LineCount:"),
  247             ALp_head->SL_memory.ssi_LineNumber);
  248         }
  249     } else {
  250         size_t i_counter;
  251         char *value = (char *) (ALp_head->vp_Alloced);
  252 
  253         /*
  254          * Increment the count of total memory lost and then print the
  255          * information.
  256          */
  257         st_total += ALp_head->st_Bytes;
  258 
  259         fprintf(Fp_leakagesink, "%s\n",
  260             gettext("Memory leak detected."));
  261         fprintf(Fp_leakagesink, "%s\t%ld\n",
  262             gettext("Sequence:"),
  263             ALp_head->st_Sequence);
  264         fprintf(Fp_leakagesink, "%s\t%p\n",
  265             gettext("Pointer:"),
  266             ALp_head->vp_Alloced);
  267         fprintf(Fp_leakagesink, "%s\t",
  268             gettext("Contains:"));
  269         for (i_counter = 0;
  270          i_counter < ALp_head->st_Bytes &&
  271          i_counter < MAX_CONTENT_LENGTH;
  272          i_counter++) {
  273         if (isprint(UCH(value[i_counter]))) {
  274             fprintf(Fp_leakagesink, "%c", value[i_counter]);
  275         } else {
  276             fprintf(Fp_leakagesink, "|");
  277         }
  278         }
  279         fprintf(Fp_leakagesink, "\n");
  280         fprintf(Fp_leakagesink, "%s\t%d\n",
  281             gettext("ByteSize:"),
  282             (int) (ALp_head->st_Bytes));
  283         fprintf(Fp_leakagesink, "%s\t%s\n",
  284             gettext("FileName:"),
  285             ALp_head->SL_memory.cp_FileName);
  286         fprintf(Fp_leakagesink, "%s\t%d\n",
  287             gettext("LineCount:"),
  288             ALp_head->SL_memory.ssi_LineNumber);
  289         /*
  290          * Give the last time the pointer was realloced if it happened
  291          * also.
  292          */
  293         if (ALp_head->SL_realloc.cp_FileName != NULL) {
  294         fprintf(Fp_leakagesink, "%s\t%s\n",
  295             gettext("realloced:"),
  296             ALp_head->SL_realloc.cp_FileName);
  297         fprintf(Fp_leakagesink, "%s\t%d\n",
  298             gettext("LineCount:"),
  299             ALp_head->SL_realloc.ssi_LineNumber);
  300         }
  301         fflush(Fp_leakagesink);
  302         FREE(ALp_head->vp_Alloced);
  303     }
  304 
  305     /*
  306      * Create a blank line and release the memory held by the item.
  307      */
  308     fprintf(Fp_leakagesink, "\n");
  309     FREE(ALp_head);
  310     }
  311 
  312     /*
  313      * Give a grand total of the leakage.  Close the output file.
  314      */
  315     fprintf(Fp_leakagesink, "%s\t%u\n",
  316         gettext("Total memory leakage this run:"),
  317         (unsigned) st_total);
  318 #ifdef LEAK_SUMMARY
  319     fprintf(Fp_leakagesink,
  320         "%s\t%lu\n", gettext("Peak allocation"), (unsigned long) peak_alloced);
  321     fprintf(Fp_leakagesink,
  322         "%s\t%lu\n", gettext("Bytes allocated"), (unsigned long) total_alloced);
  323     fprintf(Fp_leakagesink,
  324         "%s\t%ld\n", gettext("Total mallocs"), count_mallocs);
  325     fprintf(Fp_leakagesink,
  326         "%s\t%ld\n", gettext("Total frees"), count_frees);
  327 #endif
  328     fclose(Fp_leakagesink);
  329 
  330     HTSYS_purge(LEAKAGE_SINK);
  331 }
  332 
  333 /*
  334  *  Purpose:    Capture allocations using malloc (stdlib.h) and track
  335  *      the information in a list.
  336  *  Arguments:  st_bytes    The size of the allocation requested
  337  *              in bytes.
  338  *      cp_File     The file from which the request for
  339  *              allocation came from.
  340  *      ssi_Line    The line number in cp_File where the
  341  *              allocation request came from.
  342  *  Return Value:   void *  A pointer to the allocated memory or NULL on
  343  *              failure as per malloc (stdlib.h)
  344  *  Remarks/Portability/Dependencies/Restrictions:
  345  *      If no memory is allocated, then no entry is added to the
  346  *      allocation list.
  347  *  Revision History:
  348  *  05-26-94    created Lynx 2-3-1 Garrett Arch Blythe
  349  */
  350 void *LYLeakMalloc(size_t st_bytes, const char *cp_File,
  351            const short ssi_Line)
  352 {
  353     void *vp_malloc;
  354 
  355     if (LYfind_leaks == FALSE) {
  356     vp_malloc = (void *) malloc(st_bytes);
  357     } else {
  358 
  359     /*
  360      * Do the actual allocation.
  361      */
  362     vp_malloc = (void *) malloc(st_bytes);
  363     CountMallocs(st_bytes);
  364 
  365     /*
  366      * Only on successful allocation do we track any information.
  367      */
  368     if (vp_malloc != NULL) {
  369         /*
  370          * Further allocate memory to store the information.  Just return
  371          * on failure to allocate more.
  372          */
  373         AllocationList *ALp_new = typecalloc(AllocationList);
  374 
  375         if (ALp_new != NULL) {
  376         /*
  377          * Copy over the relevant information.  There is no need to
  378          * allocate more memory for the file name as it is a static
  379          * string anyway.
  380          */
  381         ALp_new->st_Sequence = count_mallocs;
  382         ALp_new->vp_Alloced = vp_malloc;
  383         ALp_new->st_Bytes = st_bytes;
  384         ALp_new->SL_memory.cp_FileName = cp_File;
  385         ALp_new->SL_memory.ssi_LineNumber = ssi_Line;
  386 
  387         /*
  388          * Add the new item to the allocation list.
  389          */
  390         AddToList(ALp_new);
  391         }
  392     }
  393     }
  394     return (vp_malloc);
  395 }
  396 
  397 /*
  398  *  Purpose:    Add information about new allocation to the list,
  399  *      after a call to malloc or calloc or an equivalent
  400  *      function which may or may not have already created
  401  *      a list entry.
  402  *  Arguments:  vp_malloc   The pointer to newly allocated memory.
  403  *  Arguments:  st_bytes    The size of the allocation requested
  404  *              in bytes.
  405  *      cp_File     The file from which the request for
  406  *              allocation came from.
  407  *      ssi_Line    The line number in cp_File where the
  408  *              allocation request came from.
  409  *  Return Value:   void *  A pointer to the allocated memory or NULL on
  410  *              failure.
  411  *  Remarks/Portability/Dependencies/Restrictions:
  412  *      If no memory is allocated, then no entry is added to the
  413  *      allocation list.
  414  *  Revision History:
  415  *  1999-02-08  created, modelled after LYLeakMalloc - kw
  416  */
  417 AllocationList *LYLeak_mark_malloced(void *vp_malloced,
  418                      size_t st_bytes,
  419                      const char *cp_File,
  420                      const short ssi_Line)
  421 {
  422     AllocationList *ALp_new = NULL;
  423 
  424     if (LYfind_leaks != FALSE) {
  425     /*
  426      * The actual allocation has already been done!
  427      *
  428      * Only on successful allocation do we track any information.
  429      */
  430     if (vp_malloced != NULL) {
  431         /*
  432          * See if there is already an entry.  If so, just update the source
  433          * location info.
  434          */
  435         ALp_new = FindInList(vp_malloced);
  436         if (ALp_new) {
  437         ALp_new->SL_memory.cp_FileName = cp_File;
  438         ALp_new->SL_memory.ssi_LineNumber = ssi_Line;
  439         } else {
  440         /*
  441          * Further allocate memory to store the information.  Just
  442          * return on failure to allocate more.
  443          */
  444         ALp_new = typecalloc(AllocationList);
  445         if (ALp_new != NULL) {
  446             /*
  447              * Copy over the relevant information.
  448              */
  449             ALp_new->vp_Alloced = vp_malloced;
  450             ALp_new->st_Bytes = st_bytes;
  451             ALp_new->SL_memory.cp_FileName = cp_File;
  452             ALp_new->SL_memory.ssi_LineNumber = ssi_Line;
  453 
  454             /*
  455              * Add the new item to the allocation list.
  456              */
  457             AddToList(ALp_new);
  458             CountMallocs(st_bytes);
  459         }
  460         }
  461     }
  462     }
  463     return (ALp_new);
  464 }
  465 
  466 /*
  467  *  Purpose:    Capture allocations by calloc (stdlib.h) and
  468  *      save relevant information in a list.
  469  *  Arguments:  st_number   The number of items to allocate.
  470  *      st_bytes    The size of each item.
  471  *      cp_File     The file which wants to allocation.
  472  *      ssi_Line    The line number in cp_File requesting
  473  *              the allocation.
  474  *  Return Value:   void *  The allocated memory, or NULL on failure as
  475  *              per calloc (stdlib.h)
  476  *  Remarks/Portability/Dependencies/Restrictions:
  477  *      If no memory can be allocated, then no entry will be added
  478  *      to the list.
  479  *  Revision History:
  480  *      05-26-94    created Lynx 2-3-1 Garrett Arch Blythe
  481  */
  482 void *LYLeakCalloc(size_t st_number, size_t st_bytes, const char *cp_File,
  483            const short ssi_Line)
  484 {
  485     void *vp_calloc;
  486 
  487     if (LYfind_leaks == FALSE) {
  488     vp_calloc = (void *) calloc(st_number, st_bytes);
  489     } else {
  490 
  491     /*
  492      * Allocate the requested memory.
  493      */
  494     vp_calloc = (void *) calloc(st_number, st_bytes);
  495     CountMallocs(st_bytes * st_number);
  496 
  497     /*
  498      * Only if the allocation was a success do we track information.
  499      */
  500     if (vp_calloc != NULL) {
  501         /*
  502          * Allocate memory for the item to be in the list.  If unable, just
  503          * return.
  504          */
  505         AllocationList *ALp_new = typecalloc(AllocationList);
  506 
  507         if (ALp_new != NULL) {
  508 
  509         /*
  510          * Copy over the relevant information.  There is no need to
  511          * allocate memory for the file name as it is a static string
  512          * anyway.
  513          */
  514         ALp_new->st_Sequence = count_mallocs;
  515         ALp_new->vp_Alloced = vp_calloc;
  516         ALp_new->st_Bytes = (st_number * st_bytes);
  517         ALp_new->SL_memory.cp_FileName = cp_File;
  518         ALp_new->SL_memory.ssi_LineNumber = ssi_Line;
  519 
  520         /*
  521          * Add the item to the allocation list.
  522          */
  523         AddToList(ALp_new);
  524         }
  525     }
  526     }
  527     return (vp_calloc);
  528 }
  529 
  530 /*
  531  *  Purpose:    Capture any realloc (stdlib.h) calls in order to
  532  *      properly keep track of our run time allocation
  533  *      table.
  534  *  Arguments:  vp_Alloced  The previously allocated block of
  535  *              memory to resize.  If NULL,
  536  *              realloc works just like
  537  *              malloc.
  538  *      st_newBytes The new size of the chunk of memory.
  539  *      cp_File     The file containing the realloc.
  540  *      ssi_Line    The line containing the realloc in cp_File.
  541  *  Return Value:   void *  The new pointer value (could be the same) or
  542  *              NULL if unable to resize (old block
  543  *              still exists).
  544  *  Remarks/Portability/Dependencies/Restrictions:
  545  *      If unable to resize vp_Alloced, then no change in the
  546  *      allocation list will be made.
  547  *      If vp_Alloced is an invalid pointer value, the program will
  548  *      exit after one last entry is added to the allocation list.
  549  *  Revision History:
  550  *  05-26-94    created Lynx 2-3-1 Garrett Arch Blythe
  551  */
  552 void *LYLeakRealloc(void *vp_Alloced,
  553             size_t st_newBytes,
  554             const char *cp_File,
  555             const short ssi_Line)
  556 {
  557     void *vp_realloc;
  558     AllocationList *ALp_renew;
  559 
  560     if (LYfind_leaks == FALSE) {
  561     vp_realloc = (void *) realloc(vp_Alloced, st_newBytes);
  562 
  563     } else if (vp_Alloced == NULL) {
  564     /*
  565      * If we are asked to resize a NULL pointer, this is just a malloc
  566      * call.
  567      */
  568     vp_realloc = LYLeakMalloc(st_newBytes, cp_File, ssi_Line);
  569 
  570     } else {
  571 
  572     /*
  573      * Find the current vp_Alloced block in the list.  If NULL, this is an
  574      * invalid pointer value.
  575      */
  576     ALp_renew = FindInList(vp_Alloced);
  577     if (ALp_renew == NULL) {
  578         /*
  579          * Track the invalid pointer value and then exit.  If unable to
  580          * allocate, just exit.
  581          */
  582         AllocationList *ALp_new = typecalloc(AllocationList);
  583 
  584         if (ALp_new == NULL) {
  585         exit_immediately(EXIT_FAILURE);
  586         }
  587 
  588         /*
  589          * Set the information up; no need to allocate file name since it is a
  590          * static string.
  591          */
  592         ALp_new->vp_Alloced = NULL;
  593         ALp_new->vp_BadRequest = vp_Alloced;
  594         ALp_new->SL_realloc.cp_FileName = cp_File;
  595         ALp_new->SL_realloc.ssi_LineNumber = ssi_Line;
  596 
  597         /*
  598          * Add the item to the list.  Exit.
  599          */
  600         AddToList(ALp_new);
  601         exit_immediately(EXIT_FAILURE);
  602     }
  603 
  604     /*
  605      * Perform the resize.  If not NULL, record the information.
  606      */
  607     vp_realloc = (void *) realloc(vp_Alloced, st_newBytes);
  608     CountFrees(ALp_renew->st_Bytes);
  609     CountMallocs(st_newBytes);
  610 
  611     if (vp_realloc != NULL) {
  612         ALp_renew->st_Sequence = count_mallocs;
  613         ALp_renew->vp_Alloced = vp_realloc;
  614         ALp_renew->st_Bytes = st_newBytes;
  615 
  616         /*
  617          * Update the realloc information, too.  No need to allocate file name,
  618          * static string.
  619          */
  620         ALp_renew->SL_realloc.cp_FileName = cp_File;
  621         ALp_renew->SL_realloc.ssi_LineNumber = ssi_Line;
  622     }
  623     }
  624     return (vp_realloc);
  625 }
  626 
  627 /*
  628  *  Purpose:    Add information about reallocated memory to the list,
  629  *      after a call to realloc or an equivalent
  630  *      function which has not already created or updated
  631  *      a list entry.
  632  *  Arguments:  ALp_old     List entry for previously allocated
  633  *              block of memory to resize.  If NULL,
  634  *              mark_realloced works just like
  635  *              mark_malloced.
  636  *      vp_realloced    The new pointer, after resizing.
  637  *      st_newBytes The new size of the chunk of memory.
  638  *      cp_File     The file to record.
  639  *      ssi_Line    The line to record.
  640  *  Return Value:       Pointer to new or updated list entry
  641  *              for this memory block.
  642  *              NULL on allocation error.
  643  *  Revision History:
  644  *  1999-02-11  created kw
  645  */
  646 #if defined(LY_FIND_LEAKS) && defined(LY_FIND_LEAKS_EXTENDED)
  647 static AllocationList *mark_realloced(AllocationList * ALp_old, void *vp_realloced,
  648                       size_t st_newBytes,
  649                       const char *cp_File,
  650                       const short ssi_Line)
  651 {
  652     /*
  653      * If there is no list entry for the old allocation, treat this as if a new
  654      * allocation had happened.
  655      */
  656     if (ALp_old == NULL) {
  657     return (LYLeak_mark_malloced(vp_realloced, st_newBytes, cp_File, ssi_Line));
  658     }
  659 
  660     /*
  661      * ALp_old represents the memory block before reallocation.  Assume that if
  662      * we get here, there isn't yet a list entry for the new, possibly
  663      * different, address after realloc, that is our list hasn't been updated -
  664      * so we're going to do that now.
  665      */
  666 
  667     if (vp_realloced != NULL) {
  668     ALp_old->vp_Alloced = vp_realloced;
  669     ALp_old->st_Bytes = st_newBytes;
  670     ALp_old->SL_realloc.cp_FileName = cp_File;
  671     ALp_old->SL_realloc.ssi_LineNumber = ssi_Line;
  672     }
  673 
  674     return (ALp_old);
  675 }
  676 #endif /* not LY_FIND_LEAKS and LY_FIND_LEAKS_EXTENDED */
  677 
  678 /*
  679  *  Purpose:    Capture all requests to free information and also
  680  *      remove items from the allocation list.
  681  *  Arguments:  vp_Alloced  The memory to free.
  682  *      cp_File     The file calling free.
  683  *      ssi_Line    The line of cp_File calling free.
  684  *  Return Value:   void
  685  *  Remarks/Portability/Dependencies/Restrictions:
  686  *      If the pointer value is invalid, then an item will be added
  687  *      to the list and nothing else is done.
  688  *      I really like the name of this function and one day hope
  689  *      that Lynx is Leak Free.
  690  *  Revision History:
  691  *  05-26-94    created Lynx 2-3-1 Garrett Arch Blythe
  692  */
  693 void LYLeakFree(void *vp_Alloced,
  694         const char *cp_File,
  695         const short ssi_Line)
  696 {
  697     AllocationList *ALp_free;
  698 
  699     if (LYfind_leaks == FALSE) {
  700     free(vp_Alloced);
  701     } else {
  702 
  703     /*
  704      * Find the pointer in the allocated list.  If not found, bad pointer. 
  705      * If found, free list item and vp_Alloced.
  706      */
  707     ALp_free = FindInList(vp_Alloced);
  708     if (ALp_free == NULL) {
  709         /*
  710          * Create the final entry before exiting marking this error.  If
  711          * unable to allocate more memory just exit.
  712          */
  713         AllocationList *ALp_new = typecalloc(AllocationList);
  714 
  715         if (ALp_new == NULL) {
  716         exit_immediately(EXIT_FAILURE);
  717         }
  718 
  719         /*
  720          * Set up the information, no memory need be allocated for the file
  721          * name since it is a static string.
  722          */
  723         ALp_new->vp_Alloced = NULL;
  724         ALp_new->vp_BadRequest = vp_Alloced;
  725         ALp_new->SL_memory.cp_FileName = cp_File;
  726         ALp_new->SL_memory.ssi_LineNumber = ssi_Line;
  727 
  728         /*
  729          * Add the entry to the list and then return.
  730          */
  731         AddToList(ALp_new);
  732     } else {
  733         /*
  734          * Free off the memory.  Take entry out of allocation list.
  735          */
  736         CountFrees(ALp_free->st_Bytes);
  737         RemoveFromList(ALp_free);
  738         FREE(ALp_free);
  739         free(vp_Alloced);
  740     }
  741     }
  742 }
  743 
  744 /*
  745  * Check for leaked strdup() results -TD
  746  */
  747 char *LYLeakStrdup(const char *source,
  748            const char *cp_File,
  749            const short ssi_Line)
  750 {
  751     size_t length = strlen(source) + 1;
  752     char *target = (char *) LYLeakMalloc(length, cp_File, ssi_Line);
  753 
  754     if (target != 0) {
  755     memcpy(target, source, length);
  756     }
  757     return target;
  758 }
  759 
  760 /*
  761  *  Allocates a new copy of a string, and returns it.
  762  *  Tracks allocations by using other LYLeakFoo functions.
  763  *  Equivalent to HTSACopy in HTString.c - KW
  764  */
  765 char *LYLeakSACopy(char **dest,
  766            const char *src,
  767            const char *cp_File,
  768            const short ssi_Line)
  769 {
  770     if (src != NULL && src == *dest) {
  771     CTRACE((tfp,
  772         "LYLeakSACopy: *dest equals src, contains \"%s\"\n",
  773         src));
  774     } else {
  775     if (*dest) {
  776         LYLeakFree(*dest, cp_File, ssi_Line);
  777         *dest = NULL;
  778     }
  779     if (src) {
  780         *dest = (char *) LYLeakMalloc(strlen(src) + 1, cp_File, ssi_Line);
  781         if (*dest == NULL)
  782         outofmem(__FILE__, "LYLeakSACopy");
  783         strcpy(*dest, src);
  784     }
  785     }
  786     return *dest;
  787 }
  788 
  789 /*
  790  *  String Allocate and Concatenate.
  791  *  Tracks allocations by using other LYLeakFoo functions.
  792  *  Equivalent to HTSACat in HTUtils.c - KW
  793  */
  794 char *LYLeakSACat(char **dest,
  795           const char *src,
  796           const char *cp_File,
  797           const short ssi_Line)
  798 {
  799     if (src && *src) {
  800     if (src == *dest) {
  801         CTRACE((tfp,
  802             "LYLeakSACat:  *dest equals src, contains \"%s\"\n",
  803             src));
  804     } else if (*dest) {
  805         size_t length = strlen(*dest);
  806 
  807         *dest = (char *) LYLeakRealloc(*dest,
  808                        (length + strlen(src) + 1),
  809                        cp_File,
  810                        ssi_Line);
  811         if (*dest == NULL)
  812         outofmem(__FILE__, "LYLeakSACat");
  813         strcpy(*dest + length, src);
  814     } else {
  815         *dest = (char *) LYLeakMalloc((strlen(src) + 1),
  816                       cp_File,
  817                       ssi_Line);
  818         if (*dest == NULL)
  819         outofmem(__FILE__, "LYLeakSACat");
  820         strcpy(*dest, src);
  821     }
  822     }
  823     return *dest;
  824 }
  825 
  826 /******************************************************************************/
  827 
  828 /*
  829  * Equivalents for bstring functions in HTString.c -TD
  830  */
  831 /* same as HTSABAlloc */
  832 void LYLeakSABAlloc(bstring **dest,
  833             int len,
  834             const char *cp_File,
  835             const short ssi_Line)
  836 {
  837     if (*dest == 0) {
  838     *dest = LYLeakCalloc(1, sizeof(bstring), cp_File, ssi_Line);
  839     }
  840 
  841     if ((*dest)->len != len) {
  842     (*dest)->str = (char *) LYLeakRealloc((*dest)->str,
  843                           (size_t) len,
  844                           cp_File,
  845                           ssi_Line);
  846     if ((*dest)->str == NULL)
  847         outofmem(__FILE__, "LYLeakSABalloc");
  848 
  849     (*dest)->len = len;
  850     }
  851 }
  852 
  853 /* same as HTSABCopy */
  854 void LYLeakSABCopy(bstring **dest,
  855            const char *src,
  856            int len,
  857            const char *cp_File,
  858            const short ssi_Line)
  859 {
  860     bstring *t;
  861     unsigned need = (unsigned) (len + 1);
  862 
  863     CTRACE2(TRACE_BSTRING,
  864         (tfp, "HTSABCopy(%p, %p, %d)\n",
  865          (void *) dest, (const void *) src, len));
  866     LYLeakSABFree(dest, cp_File, ssi_Line);
  867     if (src) {
  868     if (TRACE_BSTRING) {
  869         CTRACE((tfp, "===    %4d:", len));
  870         trace_bstring2(src, len);
  871         CTRACE((tfp, "\n"));
  872     }
  873     if ((t = (bstring *) LYLeakMalloc(sizeof(bstring), cp_File, ssi_Line))
  874         == NULL)
  875           outofmem(__FILE__, "HTSABCopy");
  876 
  877     if ((t->str = (char *) LYLeakMalloc(need, cp_File, ssi_Line)) == NULL)
  878         outofmem(__FILE__, "HTSABCopy");
  879 
  880     MemCpy(t->str, src, len);
  881     t->len = len;
  882     t->str[t->len] = '\0';
  883     *dest = t;
  884     }
  885     if (TRACE_BSTRING) {
  886     CTRACE((tfp, "=>     %4d:", BStrLen(*dest)));
  887     trace_bstring(*dest);
  888     CTRACE((tfp, "\n"));
  889     }
  890 }
  891 
  892 /* same as HTSABCopy0 */
  893 void LYLeakSABCopy0(bstring **dest,
  894             const char *src,
  895             const char *cp_File,
  896             const short ssi_Line)
  897 {
  898     LYLeakSABCopy(dest, src, (int) strlen(src), cp_File, ssi_Line);
  899 }
  900 
  901 /* same as HTSABCat */
  902 void LYLeakSABCat(bstring **dest,
  903           const char *src,
  904           int len,
  905           const char *cp_File,
  906           const short ssi_Line)
  907 {
  908     bstring *t = *dest;
  909 
  910     CTRACE2(TRACE_BSTRING,
  911         (tfp, "HTSABCat(%p, %p, %d)\n",
  912          (void *) dest, (const void *) src, len));
  913     if (src) {
  914     unsigned need = (unsigned) (len + 1);
  915 
  916     if (TRACE_BSTRING) {
  917         CTRACE((tfp, "===    %4d:", len));
  918         trace_bstring2(src, len);
  919         CTRACE((tfp, "\n"));
  920     }
  921     if (t) {
  922         unsigned length = (unsigned) t->len + need;
  923 
  924         t->str = (char *) LYLeakRealloc(t->str, length, cp_File, ssi_Line);
  925     } else {
  926         if ((t = (bstring *) LYLeakCalloc(1, sizeof(bstring), cp_File,
  927                           ssi_Line)) == NULL)
  928           outofmem(__FILE__, "HTSACat");
  929 
  930         t->str = (char *) LYLeakMalloc(need, cp_File, ssi_Line);
  931     }
  932     if (t->str == NULL)
  933         outofmem(__FILE__, "HTSACat");
  934 
  935     MemCpy(t->str + t->len, src, len);
  936     t->len += len;
  937     t->str[t->len] = '\0';
  938     *dest = t;
  939     }
  940     if (TRACE_BSTRING) {
  941     CTRACE((tfp, "=>     %4d:", BStrLen(*dest)));
  942     trace_bstring(*dest);
  943     CTRACE((tfp, "\n"));
  944     }
  945 }
  946 
  947 /* same as HTSABCat0 */
  948 void LYLeakSABCat0(bstring **dest,
  949            const char *src,
  950            const char *cp_File,
  951            const short ssi_Line)
  952 {
  953     LYLeakSABCat(dest, src, (int) strlen(src), cp_File, ssi_Line);
  954 }
  955 
  956 /* same as HTSABFree */
  957 void LYLeakSABFree(bstring **ptr,
  958            const char *cp_File,
  959            const short ssi_Line)
  960 {
  961     if (*ptr != NULL) {
  962     if ((*ptr)->str)
  963         LYLeakFree((*ptr)->str, cp_File, ssi_Line);
  964     LYLeakFree(*ptr, cp_File, ssi_Line);
  965     *ptr = NULL;
  966     }
  967 }
  968 
  969 /******************************************************************************/
  970 
  971 #if defined(LY_FIND_LEAKS) && defined(LY_FIND_LEAKS_EXTENDED)
  972 
  973 const char *leak_cp_File_hack = __FILE__;
  974 short leak_ssi_Line_hack = __LINE__;
  975 
  976 /*
  977  * Purpose: A wrapper around StrAllocVsprintf (the workhorse of
  978  *      HTSprintf/HTSprintf0, implemented in HTString.c) that
  979  *      tries to make sure that our allocation list is always
  980  *      properly updated, whether StrAllocVsprintf itself was
  981  *      compiled with memory tracking or not (or even a mixture,
  982  *      like tracking the freeing but not the new allocation).
  983  *      Some source files can be compiled with LY_FIND_LEAKS_EXTENDED
  984  *      in effect while others only have LY_FIND_LEAKS in effect,
  985  *      and as long as HTString.c is complied with memory tracking
  986  *      (of either kind) string objects allocated by HTSprintf/
  987  *      HTSprintf0 (or otherwise) can be passed around among them and
  988  *      manipulated both ways.
  989  *  Arguments:  dest        As for StrAllocVsprintf.
  990  *      cp_File     The source file of the caller (i.e. the
  991  *              caller of HTSprintf/HTSprintf0, hopefully).
  992  *      ssi_Line    The line of cp_File calling.
  993  *      inuse,fmt,ap    As for StrAllocVsprintf.
  994  *  Return Value:   The char pointer to resulting string, as set
  995  *          by StrAllocVsprintf, or
  996  *          NULL if dest==0 (wrong use!).
  997  *  Remarks/Portability/Dependencies/Restrictions:
  998  *      The price for generality is severe inefficiency: several
  999  *      list lookups are done to be on the safe side.
 1000  *      We don't get the real allocation size, only a minimum based
 1001  *      on the string length of the result.  So the amount of memory
 1002  *      leakage may get underestimated.
 1003  *      If *dest is an invalid pointer value on entry (i.e. was not
 1004  *      tracked), the program will exit after one last entry is added
 1005  *      to the allocation list.
 1006  *      If StrAllocVsprintf fails to return a valid string via the
 1007  *      indirect string pointer (its first parameter), invalid memory
 1008  *      access will result and the program will probably terminate
 1009  *      with a signal.  This can happen if, on entry, *dest is NULL
 1010  *      and fmt is empty or NULL, so just Don't Do That.
 1011  *  Revision History:
 1012  *  1999-02-11  created kw
 1013  *  1999-10-15  added comments kw
 1014  */
 1015 static char *LYLeakSAVsprintf(char **dest,
 1016                   const char *cp_File,
 1017                   const short ssi_Line,
 1018                   size_t inuse,
 1019                   const char *fmt,
 1020                   va_list * ap)
 1021 {
 1022     AllocationList *ALp_old;
 1023     void *vp_oldAlloced;
 1024 
 1025     const char *old_cp_File = __FILE__;
 1026     short old_ssi_Line = __LINE__;
 1027 
 1028     if (!dest)
 1029     return NULL;
 1030 
 1031     if (LYfind_leaks == FALSE) {
 1032     StrAllocVsprintf(dest, inuse, fmt, ap);
 1033     return (*dest);
 1034     }
 1035 
 1036     vp_oldAlloced = *dest;
 1037     if (!vp_oldAlloced) {
 1038     StrAllocVsprintf(dest, inuse, fmt, ap);
 1039     LYLeak_mark_malloced(*dest, strlen(*dest) + 1, cp_File, ssi_Line);
 1040     return (*dest);
 1041     } else {
 1042     void *vp_realloced;
 1043 
 1044     ALp_old = FindInList(vp_oldAlloced);
 1045     if (ALp_old == NULL) {
 1046         /*
 1047          * Track the invalid pointer value and then exit.  If unable to
 1048          * allocate, just exit.
 1049          */
 1050         AllocationList *ALp_new = typecalloc(AllocationList);
 1051 
 1052         if (ALp_new == NULL) {
 1053         exit_immediately(EXIT_FAILURE);
 1054         }
 1055 
 1056         /*
 1057          * Set the information up; no need to allocate file name since it
 1058          * is a static string.
 1059          */
 1060         ALp_new->vp_Alloced = NULL;
 1061         ALp_new->vp_BadRequest = vp_oldAlloced;
 1062         ALp_new->SL_realloc.cp_FileName = cp_File;
 1063         ALp_new->SL_realloc.ssi_LineNumber = ssi_Line;
 1064 
 1065         /*
 1066          * Add the item to the list.  Exit.
 1067          */
 1068         AddToList(ALp_new);
 1069         exit_immediately(EXIT_FAILURE);
 1070     }
 1071 
 1072     old_cp_File = ALp_old->SL_memory.cp_FileName;
 1073     old_ssi_Line = ALp_old->SL_memory.ssi_LineNumber;
 1074     /*
 1075      * DO THE REAL WORK, by calling StrAllocVsprintf.  If result is not
 1076      * NULL, record the information.
 1077      */
 1078     StrAllocVsprintf(dest, inuse, fmt, ap);
 1079     vp_realloced = (void *) *dest;
 1080     if (vp_realloced != NULL) {
 1081         AllocationList *ALp_new = FindInList(vp_realloced);
 1082 
 1083         if (!ALp_new) {
 1084         /* Look up again, list may have changed! - kw */
 1085         ALp_old = FindInList(vp_oldAlloced);
 1086         if (ALp_old == NULL) {
 1087             LYLeak_mark_malloced(*dest, strlen(*dest) + 1, cp_File, ssi_Line);
 1088             return (*dest);
 1089         }
 1090         mark_realloced(ALp_old, *dest, strlen(*dest) + 1, cp_File, ssi_Line);
 1091         return (*dest);
 1092         }
 1093         ALp_new->SL_memory.cp_FileName = old_cp_File;
 1094         ALp_new->SL_memory.ssi_LineNumber = old_ssi_Line;
 1095         ALp_new->SL_realloc.cp_FileName = cp_File;
 1096         ALp_new->SL_realloc.ssi_LineNumber = ssi_Line;
 1097     }
 1098     return (*dest);
 1099     }
 1100 }
 1101 
 1102 /* Note: the following may need updating if HTSprintf in HTString.c
 1103  * is changed. - kw */
 1104 static char *LYLeakHTSprintf(char **pstr, const char *fmt, ...)
 1105 {
 1106     char *str;
 1107     size_t inuse = 0;
 1108     va_list ap;
 1109 
 1110     LYva_start(ap, fmt);
 1111 
 1112     if (pstr != 0 && *pstr != 0)
 1113     inuse = strlen(*pstr);
 1114     str = LYLeakSAVsprintf(pstr, leak_cp_File_hack, leak_ssi_Line_hack,
 1115                inuse, fmt, &ap);
 1116 
 1117     va_end(ap);
 1118     return str;
 1119 }
 1120 
 1121 /* Note: the following may need updating if HTSprintf0 in HTString.c
 1122  * is changed. - kw */
 1123 static char *LYLeakHTSprintf0(char **pstr, const char *fmt, ...)
 1124 {
 1125     char *str;
 1126     va_list ap;
 1127 
 1128     LYva_start(ap, fmt);
 1129 
 1130     str = LYLeakSAVsprintf(pstr, leak_cp_File_hack, leak_ssi_Line_hack,
 1131                0, fmt, &ap);
 1132 
 1133     va_end(ap);
 1134     return str;
 1135 }
 1136 
 1137 /*
 1138  * HTSprintf and HTSprintf0 will be defined such that they effectively call one
 1139  * of the following two functions that store away a copy to the File & Line
 1140  * info in temporary hack variables, and then call the real function (which is
 1141  * returned here as a function pointer) to the regular HTSprintf/HTSprintf0
 1142  * arguments.  It's probably a bit inefficient, but that shouldn't be
 1143  * noticeable compared to all the time that memory tracking takes up for list
 1144  * traversal.  - kw
 1145  */
 1146 HTSprintflike *Get_htsprintf_fn(const char *cp_File,
 1147                 const short ssi_Line)
 1148 {
 1149     leak_cp_File_hack = cp_File;
 1150     leak_ssi_Line_hack = ssi_Line;
 1151     return &LYLeakHTSprintf;
 1152 }
 1153 
 1154 HTSprintflike *Get_htsprintf0_fn(const char *cp_File,
 1155                  const short ssi_Line)
 1156 {
 1157     leak_cp_File_hack = cp_File;
 1158     leak_ssi_Line_hack = ssi_Line;
 1159     return &LYLeakHTSprintf0;
 1160 }
 1161 
 1162 #endif /* LY_FIND_LEAKS and LY_FIND_LEAKS_EXTENDED */
 1163 #else
 1164 /* Standard C forbids an empty file */
 1165 void no_leak_checking(void);
 1166 void no_leak_checking(void)
 1167 {
 1168 }
 1169 #endif /* LY_FIND_LEAKS */