home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / MISC / NETWORK / TEL23SRC.ZIP / DEBUG / MEMDEBUG.C < prev   
Encoding:
C/C++ Source or Header  |  1991-08-19  |  15.4 KB  |  673 lines

  1. /*----------------------------------------------------------------------
  2.  *
  3.  *  memdebug.c
  4.  *  Memory management utilities
  5.  *
  6.  *  Description
  7.  *
  8.  *    memdebug.c contains routines to protect the programmer
  9.  *    from errors in calling memory allocation/free routines.
  10.  *    The programmer must use the memory calls defined
  11.  *    in memdebug.h. When these calls are used, the
  12.  *    allocation routines in this module add a data structure
  13.  *    to the top of allocated memory blocks which tags them as
  14.  *    legal memory blocks.
  15.  *
  16.  *    When the free routine is called, the memory block to
  17.  *    be freed is checked for legality tag.  If the block
  18.  *    is not legal, the memory list is dumped to stderr and
  19.  *    the program is terminated.
  20.  *
  21.  *  Compilation Options
  22.  *
  23.  *    MEM_LIST    Link all allocated memory blocks onto
  24.  *            an internal list. The list can be
  25.  *            displayed using Mem_Display().
  26.  *
  27.  *    MEM_WHERE    Save the file/line number of allocated
  28.  *            blocks in the header.
  29.  *            Requires that the compilier supports
  30.  *            __FILE__ and __LINE__ preprocessor
  31.  *            directives.
  32.  *            Also requires that the __FILE__ string
  33.  *            have a static or global scope.
  34.  *
  35.  *    MEM_HEADER    Place a header and footer section around each
  36.  *            allocated block to detect overwrites on the beginning
  37.  *            and the ending of the allocated block.
  38.  *
  39.  *    MEM_COMP_FREE    Complement the free'd memory.
  40.  *
  41.  */
  42.  
  43. #define __MEMDEBUG__
  44. /*#define DEBUG_LIST */
  45.  
  46. #include <stdio.h>
  47. #include <stdlib.h>
  48. #include <string.h>
  49. #include "memdebug.h"
  50. #ifdef __TURBOC__
  51. #include "turboc.h"
  52. #endif
  53.  
  54. /* External variables just for debugging telnet */
  55. /* -------------------------------------------- */
  56. extern char path_name[];
  57.  
  58. /* Constants */
  59. /* --------- */
  60. #define MEMTAG    0xa55a            /* Value for mh_tag */
  61. #define HEADERTAG    0x5a        /* Value for the header and footer data */
  62.  
  63. /* Structures */
  64. /* ---------- */
  65. typedef struct memnod {            /* Memory block header info    */
  66.     unsigned int    mh_tag ;    /* Special ident tag        */
  67.     size_t        mh_size ;        /* Size of allocation block    */
  68. #if defined(MEM_LIST)
  69.     struct memnod    *mh_next ;    /* Next memory block        */
  70.     struct memnod    *mh_prev ;    /* Previous memory block    */
  71. #endif
  72. #if defined(MEM_WHERE)
  73.     char        *mh_file ;        /* File allocation was from    */
  74.     unsigned int    mh_line ;    /* Line allocation was from    */
  75. #endif
  76. } MEMHDR;
  77.  
  78. /* Alignment macros */
  79. /* ---------------- */
  80. #define PC
  81. #if defined(PC)
  82. #define ALIGN_SIZE sizeof(unsigned char)
  83. #else
  84. #define ALIGN_SIZE sizeof(double)
  85. #endif
  86.  
  87. #define HDR_SIZE sizeof(MEMHDR)
  88.  
  89. #if defined(MEM_HEADER)
  90. #define BLOCK_SIZE    5
  91. #define HEADER_SIZE    (sizeof(unsigned char)*BLOCK_SIZE)
  92. #define RESERVE_SIZE ((((HDR_SIZE+(ALIGN_SIZE-1))/ALIGN_SIZE)*ALIGN_SIZE)+HEADER_SIZE)
  93. #else
  94. #define BLOCK_SIZE    0
  95. #define HEADER_SIZE    0
  96. #define RESERVE_SIZE (((HDR_SIZE+(ALIGN_SIZE-1))/ALIGN_SIZE)*ALIGN_SIZE)
  97. #endif
  98.  
  99. /* Conversion macros */
  100. /* ----------------- */
  101. #define CLIENT_2_HDR(a) ((MEMHDR *) (((char *)(a)) - RESERVE_SIZE))
  102. #define HDR_2_CLIENT(a) ((void *) (((char *)(a)) + RESERVE_SIZE))
  103.  
  104. /* Local variables */
  105. /* --------------- */
  106. static unsigned long    mem_size = 0 ;    /* Amount of memory used */
  107. #if defined(MEM_LIST)
  108. static MEMHDR    *memlist = NULL ;    /* List of memory blocks */
  109. #endif
  110.  
  111. /* Local functions */
  112. /* --------------- */
  113. static    void    mem_tag_err(void *, char *, int) ;    /* Tag error */
  114. #if defined(MEM_LIST)
  115. static    void    mem_list_add(MEMHDR *) ;        /* Add block to list */
  116. static    void    mem_list_delete(MEMHDR *) ;        /* Delete block from list */
  117. #define Mem_Tag_Err(a) mem_tag_err(a,fil,lin)
  118. #else
  119. #define Mem_Tag_Err(a) mem_tag_err(a,__FILE__,__LINE__)
  120. #endif
  121.  
  122. /************************************************************************/
  123. /**** Functions accessed only through macros ****************************/
  124. /************************************************************************/
  125.  
  126. /*----------------------------------------------------------------------
  127.  *
  128.  *  mem_alloc()
  129.  *  Allocate a memory block
  130.  *
  131.  *  Usage:
  132.  *
  133.  *    void *mem_alloc(size_t    size)
  134.  *
  135.  *  Parameters:
  136.  *
  137.  *    size        Size of block in bytes to allocate
  138.  *
  139.  *  Return Value:
  140.  *
  141.  *    Pointer to allocated memory block
  142.  *    NULL if not enough memory
  143.  *
  144.  *  Description:
  145.  *
  146.  *    mem_alloc() makes a protected call to malloc()
  147.  *
  148.  *  Notes
  149.  *
  150.  *    Access this routine using the malloc() macro in memdebug.h
  151.  *
  152.  *
  153.  */
  154.  
  155. void *mem_alloc(
  156. #if defined(MEM_WHERE)
  157. size_t    size,
  158. char    *fil,
  159. int        lin
  160. #else
  161. size_t    size
  162. #endif
  163. )
  164.  
  165. {
  166.     MEMHDR    *p;
  167.  
  168. /* Allocate memory block */
  169. /* --------------------- */
  170.     p=malloc(RESERVE_SIZE + size + HEADER_SIZE);
  171.     if(p==NULL)
  172.         return(NULL);
  173.  
  174. /* Init header */
  175. /* ----------- */
  176.     p->mh_tag=MEMTAG;
  177.     p->mh_size=size;
  178.     mem_size+=size;
  179. #if defined(MEM_WHERE)
  180.     p->mh_file=fil;
  181.     p->mh_line=lin;
  182. #endif
  183.  
  184. #if defined(MEM_HEADER)
  185.     memset((char *)HDR_2_CLIENT(p)-HEADER_SIZE,HEADERTAG,HEADER_SIZE);
  186.     memset((char *)HDR_2_CLIENT(p)+size,HEADERTAG,HEADER_SIZE);
  187. #endif
  188.  
  189. #if defined(MEM_LIST)
  190.     mem_list_add(p);
  191. #endif
  192.  
  193. /* Return pointer to client data */
  194. /* ----------------------------- */
  195.     return(HDR_2_CLIENT(p));
  196. }    /* end mem_alloc() */
  197.  
  198. /*----------------------------------------------------------------------
  199.  *
  200.  *  mem_realloc()
  201.  *  Reallocate a memory block
  202.  *
  203.  *  Usage:
  204.  *
  205.  *    void *mem_realloc(void    *ptr,size_t    size)
  206.  *
  207.  *  Parameters:
  208.  *
  209.  *    ptr        Pointer to current block
  210.  *    size    Size to adjust block to
  211.  *
  212.  *  Return Value:
  213.  *
  214.  *    Pointer to new memory block
  215.  *    NULL if memory cannot be reallocated
  216.  *
  217.  *  Description:
  218.  *
  219.  *    mem_realloc() makes a protected call to realloc().
  220.  *
  221.  *  Notes:
  222.  *
  223.  *    Access this routine using the realloc() macro in memdebug.h
  224.  *
  225.  *
  226.  */
  227.  
  228. void *mem_realloc(
  229. #if defined(MEM_WHERE)
  230. void        *ptr,
  231. size_t        size,
  232. char        *fil,
  233. int        lin
  234. #else
  235. void        *ptr,
  236. size_t        size
  237. #endif
  238. )
  239.  
  240. {
  241.     MEMHDR    *p;
  242. #if defined(MEM_HEADER) || defined(MEM_COMP_FREE)
  243.     unsigned char *q;
  244.     register int i;
  245. #endif
  246.  
  247. /* Convert client pointer to header pointer */
  248. /* ---------------------------------------- */
  249.     p=CLIENT_2_HDR(ptr);
  250.  
  251. /* Check for valid block */
  252. /* --------------------- */
  253.     if(p->mh_tag!=MEMTAG) {
  254.         Mem_Tag_Err(p);
  255.         return(NULL);
  256.       }    /* end if */
  257.  
  258. /* Check for overwrites into the header & footer */
  259. /* --------------------------------------------- */
  260. #if defined(MEM_HEADER)
  261.     q=(unsigned char *)ptr-HEADER_SIZE;        /* Check the Header to consistancy */
  262.     for(i=0; i<BLOCK_SIZE; i++) {
  263.         if(q[i]!=HEADERTAG) {
  264.             Mem_Tag_Err(p);
  265.             return(NULL);
  266.           }    /* end if */
  267.       }    /* end for */
  268.     q=(unsigned char *)ptr+p->mh_size;        /* Check the Footer for consistancy */
  269.     for(i=0; i<BLOCK_SIZE; i++) {
  270.         if(q[i]!=HEADERTAG) {
  271.             Mem_Tag_Err(p);
  272.             return(NULL);
  273.           }    /* end if */
  274.       }    /* end for */
  275. #endif
  276.  
  277. /* Invalidate header */
  278. /* ----------------- */
  279.     p->mh_tag=~MEMTAG;
  280.     mem_size-=p->mh_size;
  281.  
  282. /* Invalidate the block of memory to be free'd */
  283. /* ------------------------------------------- */
  284. #if defined(MEM_COMP_FREE)
  285.     q=(unsigned char *)ptr;
  286.     for(i=0; i < ((int)p->mh_size); i++)
  287.         q[i]=(unsigned char) (~q[i]);
  288. #endif
  289.  
  290. #if defined(MEM_WHERE)
  291.     mem_list_delete(p);    /* Remove block from list */
  292. #endif
  293.  
  294. /* Reallocate memory block */
  295. /* ----------------------- */
  296.     p=(MEMHDR *)realloc(p,RESERVE_SIZE+size+HEADER_SIZE);
  297.     if(p==NULL)
  298.         return(NULL);
  299.  
  300. /* Update header */
  301. /* ------------- */
  302.     p->mh_tag=MEMTAG;
  303.     p->mh_size=size;
  304.     mem_size+=size;
  305. #if defined(MEM_LIST)
  306.     p->mh_file=fil;
  307.     p->mh_line=lin;
  308. #endif
  309.  
  310. #if defined(MEM_WHERE)
  311.     mem_list_add(p);    /* Add block to list */
  312. #endif
  313.  
  314. #if defined(MEM_HEADER)
  315.     memset((char *)HDR_2_CLIENT(p)-HEADER_SIZE,HEADERTAG,HEADER_SIZE);
  316.     memset((char *)HDR_2_CLIENT(p)+size,HEADERTAG,HEADER_SIZE);
  317. #endif
  318.  
  319. /* Return pointer to client data */
  320. /* ----------------------------- */
  321.     return(HDR_2_CLIENT(p));
  322. }    /* end mem_realloc() */
  323.  
  324. /*----------------------------------------------------------------------
  325.  *
  326.  *  mem_strdup()
  327.  *  Save a string in dynamic memory
  328.  *
  329.  *  Usage:
  330.  *
  331.  *    char *mem_strdup(char *str)
  332.  *
  333.  *  Parameters:
  334.  *
  335.  *    str        String to save
  336.  *
  337.  *  Return Value:
  338.  *
  339.  *    Pointer to allocated string
  340.  *    NULL if not enough memory
  341.  *
  342.  *  Description:
  343.  *
  344.  *    mem_strdup() saves the specified string in dynamic memory.
  345.  *
  346.  *  Notes:
  347.  *
  348.  *    Access this routine using the strdup() macro in memdebug.h
  349.  *
  350.  *
  351.  */
  352.  
  353. char *mem_strdup(
  354. #if defined(MEM_WHERE)
  355. char        *str,
  356. char        *fil,
  357. int        lin
  358. #else
  359. char        *str
  360. #endif
  361. )
  362.  
  363. {
  364.     char *s;
  365.  
  366. #if defined(MEM_WHERE)
  367.     s=mem_alloc(strlen(str)+1,fil,lin);
  368. #else
  369.     s=mem_alloc(strlen(str)+1);
  370. #endif
  371.  
  372.     if(s!=NULL)
  373.         strcpy(s,str);
  374.  
  375.     return(s);
  376. }    /* end mem_strdup() */
  377.  
  378. /*----------------------------------------------------------------------
  379.  *
  380.  *  mem_free()
  381.  *  Free a memory block
  382.  *
  383.  *  Usage:
  384.  *
  385.  *    void mem_free(void    *ptr)
  386.  *
  387.  *  Parameters:
  388.  *
  389.  *    ptr        Pointer to memory to free
  390.  *
  391.  *  Return Value:
  392.  *
  393.  *    None
  394.  *
  395.  *  Description:
  396.  *
  397.  *    mem_free() frees the specified memory block. The
  398.  *    block must be allocated using mem_alloc(), mem_realloc()
  399.  *    or mem_strdup().
  400.  *
  401.  *  Notes
  402.  *
  403.  *    Access this routine using the free() macro in memdebug.h
  404.  *
  405.  *
  406.  */
  407.  
  408. void mem_free(
  409. #if defined(MEM_WHERE)
  410. void        *ptr,
  411. char        *fil,
  412. int        lin
  413. #else
  414. void        *ptr
  415. #endif
  416. )
  417.  
  418. {
  419.     MEMHDR *p;
  420. #if defined(MEM_HEADER) || defined(MEM_COMP_FREE)
  421.     unsigned char *q;
  422.     register int i;
  423. #endif
  424.  
  425. /* Convert client pointer to header pointer */
  426. /* ---------------------------------------- */
  427.     p=CLIENT_2_HDR(ptr);
  428.  
  429. /* Check for valid block */
  430. /* --------------------- */
  431.     if(p->mh_tag!=MEMTAG) {
  432.         Mem_Tag_Err(p);
  433.         return;
  434.       }    /* end if */
  435.  
  436. /* Check for overwrites into the header & footer */
  437. /* --------------------------------------------- */
  438. #if defined(MEM_HEADER)
  439.     q=(unsigned char *)ptr-HEADER_SIZE;        /* Check the Header to consistancy */
  440.     for(i=0; i<BLOCK_SIZE; i++) {
  441.         if(q[i]!=HEADERTAG) {
  442.             Mem_Tag_Err(p);
  443.             return;
  444.           }    /* end if */
  445.       }    /* end for */
  446.     q=(unsigned char *)ptr+p->mh_size;        /* Check the Footer for consistancy */
  447.     for(i=0; i<BLOCK_SIZE; i++) {
  448.         if(q[i]!=HEADERTAG) {
  449.             Mem_Tag_Err(p);
  450.             return;
  451.           }    /* end if */
  452.       }    /* end for */
  453. #endif
  454.  
  455. /* Invalidate header */
  456. /* ----------------- */
  457.     p->mh_tag=~MEMTAG;
  458.     mem_size-=p->mh_size;
  459.  
  460. /* Invalidate the block of memory to be free'd */
  461. /* ------------------------------------------- */
  462. #if defined(MEM_COMP_FREE)
  463.     q=(unsigned char *)ptr;
  464.     for(i=0; i<(int) (p->mh_size); i++)
  465.         q[i]=(unsigned char)(~q[i]);
  466. #endif
  467.  
  468. #if defined(MEM_LIST)
  469.     mem_list_delete(p);    /* Remove block from list */
  470. #endif
  471.  
  472. /* Free memory block */
  473. /* ----------------- */
  474.     free(p);
  475. }    /* end mem_free() */
  476.  
  477. /************************************************************************/
  478. /**** Functions accessed directly ***************************************/
  479. /************************************************************************/
  480.  
  481. /*----------------------------------------------------------------------
  482.  *
  483.  *  Mem_Used()
  484.  *  Return amount of memory currently allocated
  485.  *
  486.  *  Usage:
  487.  *
  488.  *    unsigned long Mem_Used()
  489.  *
  490.  *  Parameters:
  491.  *
  492.  *    None.
  493.  *
  494.  *  Description:
  495.  *
  496.  *    Mem_Used() returns the number of bytes currently allocated
  497.  *    using the memory management system. The value returned is
  498.  *    simply the sum of the size requests to allocation routines.
  499.  *    It does not reflect any overhead required by the memory
  500.  *    management system.
  501.  *
  502.  *  Notes:
  503.  *
  504.  *    None
  505.  *
  506.  *
  507.  */
  508.  
  509. unsigned long Mem_Used(void)
  510. {
  511.     return(mem_size);
  512. }    /* end Mem_Used() */
  513.  
  514. /*----------------------------------------------------------------------
  515.  *
  516.  *  Mem_Display()
  517.  *  Display memory allocation list
  518.  *
  519.  *  Usage:
  520.  *
  521.  *    void Mem_Display(FILE *fp)
  522.  *
  523.  *  Parameters:
  524.  *
  525.  *    fp        File to output data to
  526.  *
  527.  *  Description:
  528.  *
  529.  *    Mem_Display() displays the contents of the memory
  530.  *    allocation list.
  531.  *
  532.  *    This function is a no-op if MEM_LIST is not defined.
  533.  *
  534.  *  Notes:
  535.  *
  536.  *    None
  537.  *
  538.  *
  539.  */
  540.  
  541. void Mem_Display(FILE *fp)
  542. {
  543. #if defined(MEM_LIST)
  544.     MEMHDR    *p;
  545.     int    idx;
  546. #if defined(MEM_HEADER)
  547.     unsigned char *q;
  548.     register int i;
  549. #endif
  550.  
  551. #if defined(MEM_WHERE)
  552.     fprintf(fp, "2.3:Index   Size  File(Line) - total size %lu\n",mem_size);
  553. #else
  554.     fprintf(fp, "2.3:Index   Size - total size %lu\n",mem_size);
  555. #endif
  556.  
  557.     idx=0;
  558.     p=memlist;
  559.     while(p!=NULL) {
  560.         fprintf(fp,"%-5d %6u",idx++,p->mh_size);
  561. #if defined(MEM_WHERE)
  562.         fprintf(fp, "  %s(%d)",p->mh_file,p->mh_line);
  563. #endif
  564.         if (p->mh_tag!=MEMTAG)
  565.             fprintf(fp," INVALID TAG");
  566.  
  567. /* Check for overwrites into the header & footer */
  568. /* --------------------------------------------- */
  569. #if defined(MEM_HEADER)
  570.         q=(unsigned char *)HDR_2_CLIENT(p)-HEADER_SIZE;        /* Check the Header to consistancy */
  571.         for(i=0; i<BLOCK_SIZE; i++) {
  572.             if(q[i]!=HEADERTAG) {
  573.                 fprintf(fp," HEADER OVERWRITTEN");
  574.                 break;
  575.               }    /* end if */
  576.           }    /* end for */
  577.         q=(unsigned char *)HDR_2_CLIENT(p)+p->mh_size;        /* Check the Footer for consistancy */
  578.         for(i=0; i<BLOCK_SIZE; i++) {
  579.             if(q[i]!=HEADERTAG) {
  580.                 fprintf(fp," FOOTER OVERWRITTEN");
  581.                 break;
  582.               }    /* end if */
  583.           }    /* end for */
  584. #endif
  585.         fprintf(fp,"\n");
  586.         p=p->mh_next;
  587.       }    /* end while */
  588. #else
  589.     fprintf(fp, "Memory list not compiled (MEM_LIST not defined)\n") ;
  590. #endif
  591. }    /* end Mem_Display() */
  592.  
  593. /************************************************************************/
  594. /**** Memory list manipulation functions ********************************/
  595. /************************************************************************/
  596.  
  597. /*
  598.  * mem_list_add()
  599.  * Add block to list
  600.  */
  601.  
  602. #if defined(MEM_LIST)
  603. static void mem_list_add(MEMHDR    *p)
  604. {
  605.     p->mh_next=memlist;
  606.     p->mh_prev=NULL;
  607.     if(memlist!=NULL)
  608.         memlist->mh_prev=p;
  609.     memlist=p;
  610.  
  611. #if defined(DEBUG_LIST)
  612.     printf("mem_list_add()\n");
  613.     Mem_Display(stdout);
  614. #endif
  615. }    /* end mem_list_add() */
  616. #endif
  617.  
  618. /*----------------------------------------------------------------------*/
  619.  
  620. /*
  621.  * mem_list_delete()
  622.  * Delete block from list
  623.  */
  624.  
  625. #if defined(MEM_LIST)
  626. static void mem_list_delete(MEMHDR    *p)
  627. {
  628.     if(p->mh_next!=NULL)
  629.         p->mh_next->mh_prev=p->mh_prev;
  630.     if(p->mh_prev!=NULL)
  631.         p->mh_prev->mh_next=p->mh_next;
  632.     else
  633.         memlist=p->mh_next;
  634.  
  635. #if defined(DEBUG_LIST)
  636.     printf("mem_list_delete()\n");
  637.     Mem_Display(stdout);
  638. #endif
  639. }    /* end mem_list_delete() */
  640. #endif
  641.  
  642. /************************************************************************/
  643. /**** Error display *****************************************************/
  644. /************************************************************************/
  645.  
  646. /*
  647.  *  mem_tag_err()
  648.  *  Display memory tag error
  649.  */
  650. static void mem_tag_err(void *p,char *fil,int lin)
  651. {
  652.     FILE *fp;
  653.     char file_name[_MAX_DRIVE+_MAX_DIR+_MAX_FNAME+_MAX_EXT];    /* buffer for the path name to write the file name into */
  654.  
  655.     strcpy(file_name,path_name);
  656.     strcat(file_name,"telnet.err");
  657.     fprintf(stderr,"Memory tag error - %p - %s(%d)\n",p,fil,lin);
  658.     fprintf(stderr,"Please! Mail the file %s to pctelbug@ncsa.uiuc.edu\n",file_name);
  659.     fprintf(stderr,"and tell us the circumstances of the error\n");
  660.     fprintf(stderr,"(Remember to tell us that this is the 2.3.03 release)\n");
  661.     fprintf(stderr,"Exitting Telnet soon is recommended\n");
  662.     if((fp=fopen(file_name,"wt+"))!=NULL) {    /* open telnet.err to output the error file */
  663.         fprintf(fp,"Memory tag error - %p - %s(%d)\n",p,fil,lin);
  664. #if defined(MEM_LIST)
  665.         Mem_Display(fp);
  666. #endif
  667.         fclose(fp);
  668.       }    /* end if */
  669. #ifdef QAK
  670.     exit(1);
  671. #endif
  672. }    /* end mem_tag_err() */
  673.