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

  1. _DEBUGGING MEMORY ALLOCATION ERRORS_ 
  2. by Lawerence D. Spencer
  3.  
  4.  
  5. [LISTING ONE]
  6.  
  7. /* bad.c -- Mistakes in memory allocation */
  8.  
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <malloc.h>
  12.  
  13. main()
  14. {
  15.    char *allocated_but_never_freed;
  16.    char *this_one_is_ok;
  17.    char *freed_but_never_allocated;
  18.  
  19.    allocated_but_never_freed = malloc(10);
  20.    this_one_is_ok            = malloc(20);
  21.  
  22.    free(this_one_is_ok);
  23.    free(freed_but_never_allocated);
  24.  
  25.    return(0);
  26. }
  27.  
  28.  
  29. [LISTING TWO]
  30.  
  31. /* bad.c -- Mistakes in memory allocation */
  32.  
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. #include <malloc.h>
  36.  
  37. #include <mem.h>
  38.  
  39. main()
  40. {
  41.    char *allocated_but_never_freed;
  42.    char *this_one_is_ok;
  43.    char *freed_but_never_allocated;
  44.  
  45.    allocated_but_never_freed = memMalloc(10,"tag 1");
  46.    this_one_is_ok            = memMalloc(20,"tag 2");
  47.  
  48.    memFree(this_one_is_ok,           "tag 3");
  49.    memFree(freed_but_never_allocated,"tag 4");
  50.  
  51.    return(0);
  52. }
  53.  
  54.  
  55.  
  56. [LISTING THREE]
  57.  
  58. /* memMalloc() -- Same as malloc(), but registers activity using memTrack().
  59. * Copyright (c) 1990, Cornerstone Systems Group, Inc. 
  60. */
  61.  
  62. #include <stdlib.h>
  63. #include <stdio.h>
  64. #include <malloc.h>
  65.  
  66. #include <mem.h>
  67.  
  68. void *memMalloc(size_t bytes, char *tag)
  69. {
  70.    void *allocated;
  71.    allocated = malloc(bytes);
  72.    memTrack_alloc(allocated, tag);
  73.    return(allocated);
  74. }
  75.  
  76. /* memFree() -- Same as free(), but registers activity using memTrack().
  77. *  Copyright (c) 1990, Cornerstone Systems Group, Inc. 
  78. */
  79.  
  80. #include <stdlib.h>
  81. #include <stdio.h>
  82. #include <malloc.h>
  83.  
  84. #include <mem.h>
  85.  
  86. void memFree(void *to_free, char *tag)
  87. {
  88.    if (memTrack_free(to_free, tag))
  89.       {
  90.       free(to_free);
  91.       }
  92. }
  93. /* MEMTRACK.C -- Module to track memory allocations and frees that occur 
  94. * in the other mem...() routines. Global routines:
  95. *     memTrack_alloc() -- Records allocations.
  96. *     memTrack_free()  -- Records attempts to free. 
  97. *  Copyright (c) 1990, Cornerstone Systems Group, Inc.
  98. */
  99.  
  100. #include <stdlib.h>
  101. #include <stdio.h>
  102. #include <malloc.h>
  103.  
  104. #include <mem.h>
  105.  
  106. static FILE  *memTrack_fp(void);
  107. static void   memTrack_msg(char *msg);
  108.  
  109. #define  ALLOC   'A'
  110. #define  FREE    'F'
  111.  
  112. /* Track an allocation. Write it in the debugging file in the format 
  113. *   A 0000:0000 tag */
  114. void memTrack_alloc(void *allocated, char *tag)
  115. {
  116.    FILE  *fp;
  117.  
  118.    if (fp = memTrack_fp())
  119.       {
  120.       fseek(fp,0L,SEEK_END);
  121.       fprintf(fp,"%c %p %s\n",ALLOC, allocated, tag);
  122.       fclose(fp);
  123.       }
  124. }
  125.  
  126. /*  Track freeing of pointer. Return FALSE if was not allocated, but tracking 
  127.  *  file exists. Return TRUE otherwise. */
  128. int memTrack_free(void *to_free, char *tag)
  129. {
  130.    int   rc = 1;
  131.    FILE  *fp;
  132.    void  *addr_in_file = 0;
  133. #define  MAX_LTH  200
  134.    char  line[MAX_LTH];
  135.    char  found = 0;
  136.    char  dummy;
  137.    int   ii;
  138.    long  loc;
  139.    if (fp = memTrack_fp())
  140.       {
  141.       rewind(fp);
  142.       for ( loc=0L; fgets(line,MAX_LTH,fp); loc = ftell(fp) )
  143.          {
  144.          if (line[0] != ALLOC)         /* Is the line an 'Allocated' line?  */
  145.             continue;                  /*   If not, back to top of loop.    */
  146.          ii = sscanf(line,"%c %p",&dummy, &addr_in_file);
  147.          if (ii==0 || ii==EOF)
  148.             continue;
  149.                                        /* Is addr in file the one we want?  */
  150.          if ( (char *)addr_in_file - (char *)to_free == 0 )
  151.             {
  152.             found = 1;                 
  153.             fseek(fp,loc,SEEK_SET);    /* Back to start of line    */
  154.             fputc(FREE,fp);            /* Over-write the ALLOC tag */
  155.             break;
  156.             }
  157.          }
  158.       fclose(fp);
  159.       if (!found)
  160.          {
  161.          char  msg[80];
  162.          sprintf(msg,"Tried to free %p (%s).  Not allocated.",to_free,tag);
  163.          memTrack_msg(msg);
  164.          }
  165.       }
  166.    return(rc);
  167. }
  168.  
  169. /* Return FILE pointer for tracking file.  */
  170. static FILE  *memTrack_fp()
  171. {
  172.    static char  *ep = NULL;    /* Points to environment var that names file */
  173.    FILE  *fp = NULL;           /* File pointer to return                    */
  174.  
  175.    if (ep == NULL              /* First time through, just create blank file */
  176.    &&   (ep = getenv("MEMTRACK"))
  177.    &&   (fp = fopen(ep,"w")) )
  178.       {
  179.       fclose(fp);
  180.       fp = 0;
  181.       }
  182.    if (ep)                     /* If we have a file name, proceed.          */
  183.       {                        /*   Otherwise, do nothing.                  */
  184.       fp = fopen(ep,"r+");     /* Open debugging file for append access.    */
  185.       if (!fp)
  186.          {
  187.          fprintf(stderr,"\a\nCannot open %s\n\a",ep);
  188.          }
  189.       }
  190.    return(fp);
  191. }
  192.  
  193. /* Write a message to the debugging file. */
  194. static void memTrack_msg(char *msg)
  195. {
  196.    FILE  *fp;
  197.  
  198.    if (fp = memTrack_fp())
  199.       {
  200.       fseek(fp,0L,SEEK_END);
  201.       fprintf(fp,"\n%s\n",msg);
  202.       fclose(fp);
  203.       }
  204.    else
  205.       {
  206.       fprintf(stderr,"%s\n",msg);
  207.       }
  208. }
  209.  
  210. /* memCalloc() -- Same as calloc(), but registers activity using memTrack().
  211. *  Copyright (c) 1990, Cornerstone Systems Group, Inc.
  212. */
  213. #include <stdlib.h>
  214. #include <stdio.h>
  215. #include <malloc.h>
  216. #include <mem.h>
  217.  
  218. void *memCalloc(size_t num_elems, size_t bytes_per_elem, char *tag)
  219. {
  220.    void *allocated;
  221.    allocated = calloc(num_elems, bytes_per_elem);
  222.    memTrack_alloc(allocated, tag);
  223.    return(allocated);
  224. }
  225.  
  226. /* memRealloc() - Same as realloc(), but registers activity with memTrack().
  227. *  Copyright (c) 1990, Cornerstone Systems Group, Inc.
  228. */
  229. #include <stdlib.h>
  230. #include <stdio.h>
  231. #include <malloc.h>
  232. #include <mem.h>
  233.  
  234. void *memRealloc(void *allocated, size_t bytes, char *tag)
  235. {
  236.    memTrack_free(allocated, tag);
  237.    allocated = realloc(allocated, bytes);
  238.    if (allocated)
  239.       {
  240.       memTrack_alloc(allocated, tag);
  241.       }
  242.    return(allocated);
  243. }
  244.  
  245. /* memStrdup() -- Same as strdup(), but registers activity using memTrack().
  246. *  Copyright (c) 1990, Cornerstone Systems Group, Inc.
  247. */
  248. #include <stdlib.h>
  249. #include <stdio.h>
  250. #include <malloc.h>
  251. #include <string.h>
  252. #include <mem.h>
  253.  
  254. void *memStrdup(void *string, char *tag)
  255. {
  256.    void *allocated;
  257.    allocated = strdup(string);
  258.    memTrack_alloc(allocated, tag);
  259.    return(allocated);
  260. }
  261.  
  262.  
  263.  
  264. [LISTING FOUR]
  265.  
  266.  
  267. /* MEM.H  -- ** Copyright (c) 1990, Cornerstone Systems Group, Inc. */
  268.  
  269. #ifdef MEMTRACK
  270.  
  271. void *memCalloc(size_t num_elems, size_t bytes_per_elem, char *tag);
  272. void  memFree(void *vp, char *tag);
  273. void *memMalloc(size_t bytes, char *tag);
  274. void *memRealloc(void *oldloc, size_t newbytes, char *tag);
  275. void *memStrdup(void *string, char *tag);
  276.      /* The next two functions are only called by the other mem functions   */
  277. void memTrack_alloc(void *vp, char *tag);
  278. int  memTrack_free(void *vp, char *tag);
  279. #else
  280. #define  memCalloc(NUM,BYTES_EACH,TAG)       calloc(NUM,BYTES_EACH)
  281. #define  memFree(POINTER,TAG)                free(POINTER)
  282. #define  memMalloc(BYTES,TAG)                malloc(BYTES)
  283. #define  memRealloc(OLD_POINTER,BYTES,TAG)   realloc(OLD_POINTER,BYTES)
  284. #define  memStrdup(STRING, TAG)              strdup(STRING)
  285. #endif
  286.  
  287.  
  288. [LISTING FIVE]
  289.  
  290. /* DEMOHEAP.C - Demonstrate use of heap...() functions.
  291. *  Copyright (c) 1990 - Cornerstone Systems Group, Inc.
  292. */
  293.  
  294. #include <stdio.h>
  295. #include <malloc.h>
  296. #include <heap.h>
  297.  
  298. static void my_own_msg_func(char *msg);
  299.  
  300. main()
  301. {
  302.    char *allocated_but_never_freed;
  303.    char *this_one_is_ok;
  304.    char *freed_but_never_allocated;
  305.    heapPrt_set_msg_func(my_own_msg_func);
  306.    allocated_but_never_freed = malloc(10);
  307.    heapPrt("after first malloc()");
  308.    this_one_is_ok            = malloc(20);
  309.    heapPrt("after second malloc()");
  310.    free(this_one_is_ok);
  311.    heapPrt("after first free()");
  312.    free(freed_but_never_allocated);
  313.    heapPrt("after second free()");
  314.    return(0);
  315. }
  316.  
  317. /* heapPrt() makes its report with puts() by default.  This will not be
  318. *  appropriate for some applications, so we will demonstrate the use of an
  319. *  alternative message function.  This one writes to stderr.
  320. *  The alternative function should take one argument (a char *).  Its 
  321. *  return value is ignored, so it might as well be void.
  322. */
  323. static void my_own_msg_func(char *msg)
  324. {
  325.    fprintf(stderr,"My own message function: %s\n",msg);
  326. }
  327. OUTPUT:
  328. My own message function:     1 allocations,     10 bytes, after first malloc()
  329. My own message function:     2 allocations,     30 bytes, after second malloc()
  330. My own message function:     1 allocations,     10 bytes, after first free()
  331. My own message function:     1 allocations,     10 bytes, after second free()
  332.  
  333.  
  334. [LISTING SIX] 
  335.  
  336. /* heap.h - Header file for use with heap...() functions.
  337. *   Copyright (c) 1990 - Cornerstone Systems Group, Inc.
  338. */
  339.  
  340. void heapPrt(char *tag);
  341. void heapPrt_set_msg_func(void (*new_msg_func)() );
  342. void heapUsed(unsigned int *numused, long *totbytes);
  343.  
  344. /* HEAPUSED.C -- Tell how much of heap has been used. For use with MS C 5.x
  345. *  Copyright (c) 1990, Cornerstone Systems Group, Inc.
  346. */
  347. #include <malloc.h>
  348. #include <heap.h>
  349.  
  350. void heapUsed(
  351. unsigned int   *numused,
  352. long           *totbytes)
  353. {
  354.    struct _heapinfo hinfo;
  355.    int    status;
  356.    *numused  = 0;
  357.    *totbytes = 0L;
  358.    hinfo._pentry = (char *)0;
  359.    while ( (status=_heapwalk(&hinfo)) == _HEAPOK)
  360.       {
  361.       if (hinfo._useflag == _USEDENTRY)
  362.          {
  363.          ++ (*numused);
  364.          *totbytes += hinfo._size;
  365.          }
  366.       }
  367. }
  368.  
  369. /* HEAPPRT.C -- Print summary information about heap. For use with MS C 5.x
  370. *   This module contains two functions:
  371. *     heapPrt() prints the summary information.
  372. *     heapPrt_set_msg_func() allows you to specify a function for heapPrt()
  373. *        to use, other than printf().
  374. *   Copyright (c) 1990, Cornerstone Systems Group, Inc.
  375. */
  376. #include <stdio.h>
  377. #include <malloc.h>
  378. #include <heap.h>
  379. static void (*heapPrt_msg_func)() = 0;
  380.  
  381. /*--------------------------------------------------------------------------*/
  382. void heapPrt(
  383. char  *tag)        /* Description of where you are in processing            */
  384. {
  385.    unsigned int   numused;          /* Number of allocations used           */
  386.    long           totbytes;         /* Total bytes allocated                */
  387.    char           msg[80];          /* Message to display                   */
  388.    heapUsed(&numused, &totbytes);
  389.    if (!heapPrt_msg_func)
  390.       heapPrt_msg_func = puts;
  391.    sprintf(msg, "%5u allocations, %6ld bytes, %s",numused,totbytes,tag);
  392.    heapPrt_msg_func(msg);
  393. }
  394. /*--------------------------------------------------------------------------*/
  395. void heapPrt_set_msg_func(
  396. void (*new_msg_func)())
  397. {
  398.    heapPrt_msg_func = new_msg_func;
  399. }
  400. /*--------------------------------------------------------------------------*/
  401.  
  402.