home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1990 / 08 / schimand.lst < prev    next >
File List  |  1990-06-20  |  18KB  |  892 lines

  1. _ENCAPSULATING C MEMORY ALLOCATION_
  2. by Jim Schimandle
  3.  
  4. [LISTING ONE]
  5.  
  6. /* junk.c  -- Junk list build/destroy test
  7.  *  $Log:   E:/vcs/junk/junk.c_v  $
  8.  *       Rev 1.1   20 Nov 1989 09:42:00   set
  9.  *    Added name field for junk node tagging
  10.  *       Rev 1.0   09 Nov 1989 18:12:30   jvs
  11.  *    Initial revision.
  12.  */
  13.  
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17.  
  18. /* Junk item structure  */
  19. typedef struct jnod {
  20.     struct jnod    *junk_next ;
  21.     char        *junk_name ;
  22.     int        junk_data[3000] ;
  23.     } JUNK ;
  24.  
  25. /* Function prototypes  */
  26. JUNK    *junk_list_build(void) ;
  27. void    junk_list_destroy(JUNK *) ;
  28. JUNK    *junk_open(char *) ;
  29. void    junk_close(JUNK *) ;
  30.  
  31. /* main() -- Entry point for test  */
  32. void main()
  33. {
  34. JUNK *jlist ;
  35.  
  36. while ((jlist = junk_list_build()) != NULL)
  37.     {
  38.     junk_list_destroy(jlist) ;
  39.     }
  40. printf("*** Should never get here! ***\n") ;
  41. }
  42.  
  43. /* junk_list_build()  -- Build a list of junk items  */
  44. JUNK *junk_list_build()
  45. {
  46. JUNK *jlist ;
  47. JUNK *jnew ;
  48.  
  49. jlist = NULL ;
  50. while ((jnew = junk_open("name to identify junkitem")) != NULL)
  51.     {
  52.     jnew->junk_next = jlist ;
  53.     jlist = jnew ;
  54.     }
  55.  
  56. return jlist ;
  57. }
  58.  
  59. /* junk_list_destroy()  -- Destroy a list of junk items  */
  60. void junk_list_destroy(JUNK *jlist)
  61. {
  62. JUNK *jtmp ;
  63.  
  64. while (jlist != NULL)
  65.     {
  66.     jtmp = jlist ;
  67.     jlist = jlist->junk_next ;
  68.     junk_close(jtmp) ;
  69.     }
  70. }
  71.  
  72. /* junk_open() -- Create a junk item  */
  73. JUNK *junk_open(char *name)
  74. {
  75. JUNK *jnew ;
  76.  
  77. jnew = (JUNK *) malloc(sizeof(JUNK)) ;
  78. if (jnew != NULL)
  79.     {
  80.     jnew->junk_name = strdup(name) ;
  81.     if (jnew->junk_name == NULL)
  82.         {
  83.         return NULL ;
  84.         }
  85.     }
  86.  
  87. return jnew ;
  88. }
  89.  
  90. /*  junk_close() -- Close a junk item  */
  91. void junk_close(JUNK *jold)
  92. {
  93. free(jold) ;
  94. }
  95.  
  96. [LISTING TWO]
  97.  
  98. /* junk.c -- Junk list build/destroy test
  99.  *  $Log:   E:/vcs/junk/junk.c_v  $
  100.  *       Rev 1.2   28 Nov 1989 10:13:07   jvs
  101.  *    Addition of memory shell
  102.  *       Rev 1.1   20 Nov 1989 09:42:00   set
  103.  *    Added name field for junk node tagging
  104.  *       Rev 1.0   09 Nov 1989 18:12:30   jvs
  105.  *    Initial revision.
  106.  */
  107.  
  108. #include <stdio.h>
  109. #include <stdlib.h>
  110. #include "mshell.h"
  111.  
  112. /* Junk item structure  */
  113. typedef struct jnod {
  114.     struct jnod    *junk_next ;
  115.     char        *junk_name ;
  116.     int        junk_data[3000] ;
  117.     } JUNK ;
  118.  
  119. /* Function prototypes */
  120. JUNK    *junk_list_build(void) ;
  121. void    junk_list_destroy(JUNK *) ;
  122. JUNK    *junk_open(char *) ;
  123. void    junk_close(JUNK *) ;
  124.  
  125. /* main() -- Entry point for test  */
  126. void main()
  127. {
  128. JUNK *jlist ;
  129.  
  130. while ((jlist = junk_list_build()) != NULL)
  131.     {
  132.     junk_list_destroy(jlist) ;
  133.     if (Mem_Used() != 0)
  134.         {
  135.         printf("*** Memory list not empty ***\n") ;
  136.         Mem_Display(stdout) ;
  137.         exit(1) ;
  138.         }
  139.     }
  140. printf("*** Should never get here! ***\n") ;
  141. }
  142.  
  143. /* junk_list_build() -- Build a list of junk items  */
  144. JUNK *junk_list_build()
  145. {
  146. JUNK *jlist ;
  147. JUNK *jnew ;
  148.  
  149. jlist = NULL ;
  150. while ((jnew = junk_open("name to identify junkitem")) != NULL)
  151.     {
  152.     jnew->junk_next = jlist ;
  153.     jlist = jnew ;
  154.     }
  155.  
  156. return jlist ;
  157. }
  158.  
  159. /* junk_list_destroy() -- Destroy a list of junk items  */
  160. void junk_list_destroy(JUNK *jlist)
  161. {
  162. JUNK *jtmp ;
  163.  
  164. while (jlist != NULL)
  165.     {
  166.     jtmp = jlist ;
  167.     jlist = jlist->junk_next ;
  168.     junk_close(jtmp) ;
  169.     }
  170. }
  171.  
  172. /* junk_open() -- Create a junk item  */
  173. JUNK *junk_open(char *name)
  174. {
  175. JUNK *jnew ;
  176.  
  177. jnew = (JUNK *) malloc(sizeof(JUNK)) ;
  178. if (jnew != NULL)
  179.     {
  180.     jnew->junk_name = strdup(name) ;
  181.     if (jnew->junk_name == NULL)
  182.         {
  183.         return NULL ;
  184.         }
  185.     }
  186.  
  187. return jnew ;
  188. }
  189.  
  190. /* junk_close() -- Close a junk item  */
  191. void junk_close(JUNK *jold)
  192. {
  193. free(jold) ;
  194. }
  195.  
  196.  
  197. [LISTING THREE]
  198.  
  199. /*----------------------------------------------------------------------
  200.  *++
  201.  *  mshell.h -- Dynamic memory handler interface
  202.  *  Description: mshell.h provides the interface definitions for the dynamic
  203.  *  memory handler.
  204.  *  See mshell.c for complete documentation.
  205.  *+-
  206.  *  $Log$
  207.  *--
  208.  */
  209.  
  210. /* Compilation options */
  211. #define MEM_LIST        /* Build internal list */
  212. #define MEM_WHERE        /* Keep track of memory block source */
  213.  
  214. /* Interface functions */
  215. unsigned long    Mem_Used(void) ;
  216. void        Mem_Display(FILE *) ;
  217.  
  218. /* Interface functions to access only through macros */
  219. #if defined(MEM_WHERE)
  220. void        *mem_alloc(size_t, char *, int) ;
  221. void        *mem_realloc(void *, size_t, char *, int) ;
  222. void        mem_free(void *, char *, int) ;
  223. char        *mem_strdup(char *, char *, int) ;
  224. #else
  225. void        *mem_alloc(size_t) ;
  226. void        *mem_realloc(void *, size_t) ;
  227. void        mem_free(void *) ;
  228. char        *mem_strdup(char *) ;
  229. #endif
  230.  
  231. /* Interface macros */
  232. #if !defined(__MSHELL__)
  233. #if defined(MEM_WHERE)
  234. #define malloc(a)        mem_alloc((a),__FILE__,__LINE__)
  235. #define realloc(a,b)        mem_realloc((a),(b),__FILE__,__LINE__)
  236. #define free(a)            mem_free((a),__FILE__,__LINE__)
  237. #define strdup(a)        mem_strdup((a),__FILE__,__LINE__)
  238. #else
  239. #define malloc(a)        mem_alloc(a)
  240. #define realloc(a, b)        mem_realloc((a),(b))
  241. #define free(a)            mem_free(a)
  242. #define strdup(a)        mem_strdup(a)
  243. #endif
  244. #endif
  245.  
  246. /*----------------------------------------------------------------------*/
  247.  
  248.  
  249. [LISTING FOUR]
  250.  
  251. /*----------------------------------------------------------------------
  252.  *++
  253.  *  mshell.c
  254.  *  Memory management utilities
  255.  *
  256.  *  Description
  257.  *
  258.  *    mshell.c contains routines to protect the programmer
  259.  *    from errors in calling memory allocation/free routines.
  260.  *    The programmer must use the memory calls defined
  261.  *    in mshell.h. When these calls are used, the
  262.  *    allocation routines in this module add a data structure
  263.  *    to the top of allocated memory blocks which tags them as
  264.  *    legal memory blocks.
  265.  *
  266.  *    When the free routine is called, the memory block to
  267.  *    be freed is checked for legality tag.  If the block
  268.  *    is not legal, the memory list is dumped to stderr and
  269.  *    the program is terminated.
  270.  *
  271.  *  Compilation Options
  272.  *
  273.  *    MEM_LIST    Link all allocated memory blocks onto
  274.  *            an internal list. The list can be
  275.  *            displayed using Mem_Display().
  276.  *
  277.  *    MEM_WHERE    Save the file/line number of allocated
  278.  *            blocks in the header.
  279.  *            Requires that the compilier supports
  280.  *            __FILE__ and __LINE__ preprocessor
  281.  *            directives.
  282.  *            Also requires that the __FILE__ string
  283.  *            have a static or global scope.
  284.  *
  285.  *+-
  286.  *
  287.  *  $Log$
  288.  *    
  289.  *--
  290.  */
  291.  
  292. #define __MSHELL__
  293.  
  294. #include <stdio.h>
  295. #include <stdlib.h>
  296. #include <string.h>
  297. #include "mshell.h"
  298.  
  299. /* Constants */
  300. /* --------- */
  301. #define MEMTAG    0xa55a            /* Value for mh_tag */
  302.  
  303. /* Structures */
  304. /* ---------- */
  305. typedef struct memnod            /* Memory block header info    */
  306.     {                /* ---------------------------- */
  307.     unsigned int    mh_tag ;    /* Special ident tag        */
  308.     size_t        mh_size ;    /* Size of allocation block    */
  309. #if defined(MEM_LIST)
  310.     struct memnod    *mh_next ;    /* Next memory block        */
  311.     struct memnod    *mh_prev ;    /* Previous memory block    */
  312. #endif
  313. #if defined(MEM_WHERE)
  314.     char        *mh_file ;    /* File allocation was from    */
  315.     unsigned int    mh_line ;    /* Line allocation was from    */
  316. #endif
  317.     } MEMHDR ;
  318.  
  319. /* Alignment macros */
  320. /* ---------------- */
  321. #define ALIGN_SIZE sizeof(double)
  322. #define HDR_SIZE sizeof(MEMHDR)
  323. #define RESERVE_SIZE (((HDR_SIZE+(ALIGN_SIZE-1))/ALIGN_SIZE) \
  324.             *ALIGN_SIZE)
  325.  
  326. /* Conversion macros */
  327. /* ----------------- */
  328. #define CLIENT_2_HDR(a) ((MEMHDR *) (((char *) (a)) - RESERVE_SIZE))
  329. #define HDR_2_CLIENT(a) ((void *) (((char *) (a)) + RESERVE_SIZE))
  330.  
  331. /* Local variables */
  332. /* --------------- */
  333. static unsigned long    mem_size = 0 ;    /* Amount of memory used */
  334. #if defined(MEM_LIST)
  335. static MEMHDR    *memlist = NULL ;    /* List of memory blocks */
  336. #endif
  337.  
  338. /* Local functions */
  339. /* --------------- */
  340. void    mem_tag_err(void *, char *, int) ;    /* Tag error */
  341. #if defined(MEM_LIST)
  342. void    mem_list_add(MEMHDR *) ;        /* Add block to list */
  343. void    mem_list_delete(MEMHDR *) ;        /* Delete block from list */
  344. #define Mem_Tag_Err(a) mem_tag_err(a,fil,lin)
  345. #else
  346. #define Mem_Tag_Err(a) mem_tag_err(a,__FILE__,__LINE__)
  347. #endif
  348.  
  349. /************************************************************************/
  350. /**** Functions accessed only through macros ****************************/
  351. /************************************************************************/
  352.  
  353. /*----------------------------------------------------------------------
  354.  *+
  355.  *  mem_alloc
  356.  *  Allocate a memory block
  357.  *
  358.  *  Usage
  359.  *
  360.  *    void *
  361.  *    mem_alloc(
  362.  *    size_t        size
  363.  *    )
  364.  *
  365.  *  Parameters
  366.  *
  367.  *    size        Size of block in bytes to allocate
  368.  *
  369.  *  Return Value
  370.  *
  371.  *    Pointer to allocated memory block
  372.  *    NULL if not enough memory
  373.  *
  374.  *  Description
  375.  *
  376.  *    mem_alloc() makes a protected call to malloc()
  377.  *
  378.  *  Notes
  379.  *
  380.  *    Access this routine using the malloc() macro in mshell.h
  381.  *
  382.  *-
  383.  */
  384.  
  385. void *
  386. mem_alloc(
  387. #if defined(MEM_WHERE)
  388. size_t        size,
  389. char        *fil,
  390. int        lin
  391. #else
  392. size_t        size
  393. #endif
  394. )
  395.  
  396. {
  397. MEMHDR        *p ;
  398.  
  399. /* Allocate memory block */
  400. /* --------------------- */
  401. p = malloc(RESERVE_SIZE + size) ;
  402. if (p == NULL)
  403.     {
  404.     return NULL ;
  405.     }
  406.  
  407. /* Init header */
  408. /* ----------- */
  409. p->mh_tag = MEMTAG ;
  410. p->mh_size = size ;
  411. mem_size += size ;
  412. #if defined(MEM_WHERE)
  413. p->mh_file = fil ;
  414. p->mh_line = lin ;
  415. #endif
  416.  
  417. #if defined(MEM_LIST)
  418. mem_list_add(p) ;
  419. #endif
  420.  
  421. /* Return pointer to client data */
  422. /* ----------------------------- */
  423. return HDR_2_CLIENT(p) ;
  424. }
  425.  
  426. /*----------------------------------------------------------------------
  427.  *+
  428.  *  mem_realloc
  429.  *  Reallocate a memory block
  430.  *
  431.  *  Usage
  432.  *
  433.  *    void *
  434.  *    mem_realloc(
  435.  *    void        *ptr,
  436.  *    size_t         size
  437.  *    )
  438.  *
  439.  *  Parameters
  440.  *
  441.  *    ptr        Pointer to current block
  442.  *    size        Size to adjust block to
  443.  *
  444.  *  Return Value
  445.  *
  446.  *    Pointer to new memory block
  447.  *    NULL if memory cannot be reallocated
  448.  *
  449.  *  Description
  450.  *
  451.  *    mem_realloc() makes a protected call to realloc().
  452.  *
  453.  *  Notes
  454.  *
  455.  *    Access this routine using the realloc() macro in mshell.h
  456.  *
  457.  *-
  458.  */
  459.  
  460. void *
  461. mem_realloc(
  462. #if defined(MEM_WHERE)
  463. void        *ptr,
  464. size_t        size,
  465. char        *fil,
  466. int        lin
  467. #else
  468. void        *ptr,
  469. size_t        size
  470. #endif
  471. )
  472.  
  473. {
  474. MEMHDR        *p ;
  475.  
  476. /* Convert client pointer to header pointer */
  477. /* ---------------------------------------- */
  478. p = CLIENT_2_HDR(ptr) ;
  479.  
  480. /* Check for valid block */
  481. /* --------------------- */
  482. if (p->mh_tag != MEMTAG)
  483.     {
  484.     Mem_Tag_Err(p) ;
  485.     return NULL ;
  486.     }
  487.  
  488. /* Invalidate header */
  489. /* ----------------- */
  490. p->mh_tag = ~MEMTAG ;
  491. mem_size -= p->mh_size ;
  492.  
  493. #if defined(MEM_WHERE)
  494. mem_list_delete(p) ;    /* Remove block from list */
  495. #endif
  496.  
  497. /* Reallocate memory block */
  498. /* ----------------------- */
  499. p = (MEMHDR *) realloc(p, RESERVE_SIZE + size) ;
  500. if (p == NULL)
  501.     {
  502.     return NULL ;
  503.     }
  504.  
  505. /* Update header */
  506. /* ------------- */
  507. p->mh_tag = MEMTAG ;
  508. p->mh_size = size ;
  509. mem_size += size ;
  510. #if defined(MEM_LIST)
  511. p->mh_file = fil ;
  512. p->mh_line = lin ;
  513. #endif
  514.  
  515. #if defined(MEM_WHERE)
  516. mem_list_add(p) ;    /* Add block to list */
  517. #endif
  518.  
  519. /* Return pointer to client data */
  520. /* ----------------------------- */
  521. return HDR_2_CLIENT(p) ;
  522. }
  523.  
  524. /*----------------------------------------------------------------------
  525.  *+
  526.  *  mem_strdup
  527.  *  Save a string in dynamic memory
  528.  *
  529.  *  Usage
  530.  *
  531.  *    char *
  532.  *    mem_strdup(
  533.  *    char        *str
  534.  *    )
  535.  *
  536.  *  Parameters
  537.  *
  538.  *    str        String to save
  539.  *
  540.  *  Return Value
  541.  *
  542.  *    Pointer to allocated string
  543.  *    NULL if not enough memory
  544.  *
  545.  *  Description
  546.  *
  547.  *    mem_strdup() saves the specified string in dynamic memory.
  548.  *
  549.  *  Notes
  550.  *
  551.  *    Access this routine using the strdup() macro in mshell.h
  552.  *
  553.  *-
  554.  */
  555.  
  556. char *
  557. mem_strdup(
  558. #if defined(MEM_WHERE)
  559. char        *str,
  560. char        *fil,
  561. int        lin
  562. #else
  563. char        *str
  564. #endif
  565. )
  566.  
  567. {
  568. char * s ;
  569.  
  570. #if defined(MEM_WHERE)
  571. s = mem_alloc(strlen(str)+1, fil, lin) ;
  572. #else
  573. s = mem_alloc(strlen(str)+1) ;
  574. #endif
  575.  
  576. if (s != NULL)
  577.     {
  578.     strcpy(s, str) ;
  579.     }
  580.  
  581. return s ;
  582. }
  583.  
  584. /*----------------------------------------------------------------------
  585.  *+
  586.  *  mem_free
  587.  *  Free a memory block
  588.  *
  589.  *  Usage
  590.  *
  591.  *    void
  592.  *    mem_free(
  593.  *    void        *ptr
  594.  *    )
  595.  *
  596.  *  Parameters
  597.  *
  598.  *    ptr        Pointer to memory to free
  599.  *
  600.  *  Return Value
  601.  *
  602.  *    None
  603.  *
  604.  *  Description
  605.  *
  606.  *    mem_free() frees the specified memory block. The
  607.  *    block must be allocated using mem_alloc(), mem_realloc()
  608.  *    or mem_strdup().
  609.  *
  610.  *  Notes
  611.  *
  612.  *    Access this routine using the free() macro in mshell.h
  613.  *
  614.  *-
  615.  */
  616.  
  617. void
  618. mem_free(
  619. #if defined(MEM_WHERE)
  620. void        *ptr,
  621. char        *fil,
  622. int        lin
  623. #else
  624. void        *ptr
  625. #endif
  626. )
  627.  
  628. {
  629. MEMHDR         *p ;
  630.  
  631. /* Convert client pointer to header pointer */
  632. /* ---------------------------------------- */
  633. p = CLIENT_2_HDR(ptr) ;
  634.  
  635. /* Check for valid block */
  636. /* --------------------- */
  637. if (p->mh_tag != MEMTAG)
  638.     {
  639.     Mem_Tag_Err(p) ;
  640.     return ;
  641.     }
  642.  
  643. /* Invalidate header */
  644. /* ----------------- */
  645. p->mh_tag = ~MEMTAG ;
  646. mem_size -= p->mh_size ;
  647.  
  648. #if defined(MEM_LIST)
  649. mem_list_delete(p) ;    /* Remove block from list */
  650. #endif
  651.  
  652. /* Free memory block */
  653. /* ----------------- */
  654. free(p) ;
  655. }
  656.  
  657. /************************************************************************/
  658. /**** Functions accessed directly ***************************************/
  659. /************************************************************************/
  660.  
  661. /*----------------------------------------------------------------------
  662.  *+
  663.  *  Mem_Used
  664.  *  Return amount of memory currently allocated
  665.  *
  666.  *  Usage
  667.  *
  668.  *    unsigned long
  669.  *    Mem_Used(
  670.  *    )
  671.  *
  672.  *  Parameters
  673.  *
  674.  *    None.
  675.  *
  676.  *  Description
  677.  *
  678.  *    Mem_Used() returns the number of bytes currently allocated
  679.  *    using the memory management system. The value returned is
  680.  *    simply the sum of the size requests to allocation routines.
  681.  *    It does not reflect any overhead required by the memory
  682.  *    management system.
  683.  *
  684.  *  Notes
  685.  *
  686.  *    None
  687.  *
  688.  *-
  689.  */
  690.  
  691. unsigned long
  692. Mem_Used(
  693. void)
  694.  
  695. {
  696. return mem_size ;
  697. }
  698.  
  699. /*----------------------------------------------------------------------
  700.  *+
  701.  *  Mem_Display
  702.  *  Display memory allocation list
  703.  *
  704.  *  Usage
  705.  *
  706.  *    void
  707.  *    Mem_Display(
  708.  *    FILE        *fp
  709.  *    )
  710.  *
  711.  *  Parameters
  712.  *
  713.  *    fp        File to output data to
  714.  *
  715.  *  Description
  716.  *
  717.  *    Mem_Display() displays the contents of the memory
  718.  *    allocation list.
  719.  *
  720.  *    This function is a no-op if MEM_LIST is not defined.
  721.  *
  722.  *  Notes
  723.  *
  724.  *    None
  725.  *
  726.  *-
  727.  */
  728.  
  729. void
  730. Mem_Display(
  731. FILE        *fp
  732. )
  733.  
  734. {
  735. #if defined(MEM_LIST)
  736. MEMHDR        *p ;
  737. int        idx ;
  738.  
  739. #if defined(MEM_WHERE)
  740. fprintf(fp, "Index   Size  File(Line) - total size %lu\n", mem_size) ;
  741. #else
  742. fprintf(fp, "Index   Size - total size %lu\n", mem_size) ;
  743. #endif
  744.  
  745. idx = 0 ;
  746. p = memlist ;
  747. while (p != NULL)
  748.     {
  749.     fprintf(fp, "%-5d %6u", idx++, p->mh_size) ;
  750. #if defined(MEM_WHERE)
  751.     fprintf(fp, "  %s(%d)", p->mh_file, p->mh_line) ;
  752. #endif
  753.     if (p->mh_tag != MEMTAG)
  754.         {
  755.         fprintf(fp, " INVALID") ;
  756.         }
  757.     fprintf(fp, "\n") ;
  758.     p = p->mh_next ;
  759.     }
  760. #else
  761. fprintf(fp, "Memory list not compiled (MEM_LIST not defined)\n") ;
  762. #endif
  763. }
  764.  
  765. /************************************************************************/
  766. /**** Memory list manipulation functions ********************************/
  767. /************************************************************************/
  768.  
  769. /*
  770.  * mem_list_add()
  771.  * Add block to list
  772.  */
  773.  
  774. #if defined(MEM_LIST)
  775. static void
  776. mem_list_add(
  777. MEMHDR    *p
  778. )
  779.  
  780. {
  781. p->mh_next = memlist ;
  782. p->mh_prev = NULL ;
  783. if (memlist != NULL)
  784.     {
  785.     memlist->mh_prev = p ;
  786.     }
  787. memlist = p ;
  788.  
  789. #if defined(DEBUG_LIST)
  790. printf("mem_list_add()\n") ;
  791. Mem_Display(stdout) ;
  792. #endif
  793. }
  794. #endif
  795.  
  796. /*----------------------------------------------------------------------*/
  797.  
  798. /*
  799.  * mem_list_delete()
  800.  * Delete block from list
  801.  */
  802.  
  803. #if defined(MEM_LIST)
  804. static void
  805. mem_list_delete(
  806. MEMHDR    *p
  807. )
  808.  
  809. {
  810. if (p->mh_next != NULL)
  811.     {
  812.     p->mh_next->mh_prev = p->mh_prev ;
  813.     }
  814. if (p->mh_prev != NULL)
  815.     {
  816.     p->mh_prev->mh_next = p->mh_next ;
  817.     }
  818.     else
  819.     {
  820.     memlist = p->mh_next ;
  821.     }
  822.  
  823. #if defined(DEBUG_LIST)
  824. printf("mem_list_delete()\n") ;
  825. Mem_Display(stdout) ;
  826. #endif
  827. }
  828. #endif
  829.  
  830. /************************************************************************/
  831. /**** Error display *****************************************************/
  832. /************************************************************************/
  833.  
  834. /*
  835.  *  mem_tag_err()
  836.  *  Display memory tag error
  837.  */
  838.  
  839. static void
  840. mem_tag_err(
  841. void        *p,
  842. char        *fil,
  843. int        lin
  844. )
  845.  
  846. {
  847. fprintf(stderr, "Memory tag error - %p - %s(%d)\n", p, fil, lin) ;
  848. #if defined(MEM_LIST)
  849. Mem_Display(stderr) ;
  850. #endif
  851. exit(1) ;
  852. }
  853.  
  854. /*----------------------------------------------------------------------*/
  855.  
  856.  
  857.  
  858.  
  859.  
  860. [Example 1: Output from junk1 shows that there are really
  861. two sources for the memory leaks. The first comes from the 
  862. malloc() of the JUNK structure at line 80. The second comes from 
  863. the strdup() of the name at line 83.]
  864.  
  865. *** Memory list not empty ***
  866. Index   Size  File(Line) - total size 6238
  867. 0       6004  junk1.c(80)
  868. 1         26  junk1.c(83)
  869. 2         26  junk1.c(83)
  870. 3         26  junk1.c(83)
  871. 4         26  junk1.c(83)
  872. 5         26  junk1.c(83)
  873. 6         26  junk1.c(83)
  874. 7         26  junk1.c(83)
  875. 8         26  junk1.c(83)
  876. 9         26  junk1.c(83)
  877.  
  878.  
  879. [Example 2: Obtuse coding for the allocation of memory in 
  880. junk_open() can hide the possibility of a memory leak when the 
  881. first allocation succeeds and the second allocation fails.]
  882.  
  883.  
  884. if (((jnew = (JUNK *) malloc(sizeof(JUNK))) == NULL) ||
  885.     ((jnew->junk_name = strdup(name)) == NULL))
  886.     {
  887.     return NULL ;
  888.     }
  889.  
  890.  
  891.  
  892.