home *** CD-ROM | disk | FTP | other *** search
/ BCI NET / BCI NET Dec 94.iso / archives / programming / utilities / safemem2.lha / SafeMem.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-05  |  12.7 KB  |  617 lines

  1. #include <exec/types.h>
  2. #include <exec/memory.h>
  3. #include <devices/parallel.h>
  4. #include <proto/exec.h>
  5.  
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8.  
  9. /*
  10.  * STRUCT:
  11.  *   MemNode
  12.  *
  13.  * DESCRIPTION:
  14.  *     The MemNode structure is placed at the start of each memory block
  15.  *   managed by the safe_ functions.
  16.  *
  17.  * USAGE:
  18.  *     It is completely internal to the safe_ suite of functions, no other
  19.  *   source need know of it's existance.
  20.  */
  21. struct MemNode
  22. {
  23.   struct MemNode *child;             /* Next block in list        */
  24.  
  25.   char *file;                        /* File that allocated us    */
  26.   ULONG line;                        /* Line we were allocated on */
  27.  
  28.   ULONG size;                        /* Size of memory block      */
  29. };
  30.  
  31.  
  32. /*
  33.  * The head of our internal memory list
  34.  */
  35. static struct MemNode *far head;
  36.  
  37. /*
  38.  * When gbl_SafeMem == 0, the SafeMem routines merely call the real versions,
  39.  * without any of the SafeMem checking. This provides an easy way to disable
  40.  * SafeMem without recompiling your entire program.
  41.  */
  42. ULONG far gbl_SafeMem=1;
  43.  
  44. /*
  45.  * gbl_SafeMemOutput is the function that is called to print the messages.
  46.  * The default is a _writes() to stdout.
  47.  */
  48. void (*gbl_SafeMemOutput)() = (void (*)())_writes;
  49.  
  50. /*
  51.  * FUNCTION:
  52.  *   void *safe_AllocMem(Size, MemType, File, Line)
  53.  *
  54.  * DESCRIPTION:
  55.  *     Peforms a call to AllocMem() with enhanced error checking. Access
  56.  *   to this function should be through the macros in safemem.h -ONLY-.
  57.  *   Note that all memory allocated with the safe_ functions must be freed
  58.  *   with the safe_ functions.
  59.  *
  60.  * ARGUMENTS:
  61.  *   long Size;      Size of the block to allocate.
  62.  *   long MemType;   Type of memory to request.
  63.  *   char *File;     Calling file     (ie __FILE__)
  64.  *   int  Line;      Calling line     (ie __LINE__)
  65.  *
  66.  * RETURNS:
  67.  *   SUCCESS: A pointer to the new memory block
  68.  *   FAILURE: 0
  69.  *
  70.  * WRITTEN:
  71.  *   Friday 14-Dec-90 13:02:11 spb
  72.  */
  73. void *safe_AllocMem(Size, MemType, File, Line)
  74. ULONG Size;
  75. ULONG MemType;
  76. char *File;
  77. ULONG Line;
  78. {
  79.   if(gbl_SafeMem)
  80.   {
  81.     struct MemNode *t;
  82.     void *result = 0;
  83.  
  84.     Forbid();
  85.  
  86.     if(head)
  87.       t = head;
  88.     else
  89.       t = 0;
  90.  
  91.     head = (struct MemNode *)AllocMem(Size + sizeof(struct MemNode), MemType);
  92.  
  93.     if(head)
  94.     {
  95.       head->child = t;
  96.       head->file  = File;
  97.       head->line  = Line;
  98.       head->size  = Size;
  99.  
  100.       result = (void *)((long)head + sizeof(struct MemNode));
  101.     }
  102.     else
  103.       head = t;
  104.  
  105.     Permit();
  106.     return(result);
  107.   }
  108.   else
  109.     return((void *)AllocMem(Size, MemType));
  110. }
  111.  
  112. /*
  113.  * FUNCTION:
  114.  *   void *safe_AllocAbs(Size, Location, File, Line)
  115.  *
  116.  * DESCRIPTION:
  117.  *     Peforms a call to AllocAbs() with enhanced error checking. Access
  118.  *   to this function should be through the macros in safemem.h -ONLY-.
  119.  *   Note that all memory allocated with the safe_ functions must be freed
  120.  *   with the safe_ functions.
  121.  *
  122.  * ARGUMENTS:
  123.  *   ULONG Size;      Size of the block to allocate.
  124.  *   void *Location;  Where in memory it is
  125.  *   char *File;      Calling file     (ie __FILE__)
  126.  *   int  Line;       Calling line     (ie __LINE__)
  127.  *
  128.  * RETURNS:
  129.  *   SUCCESS: A pointer to the new memory block
  130.  *   FAILURE: 0
  131.  *
  132.  * WRITTEN:
  133.  *   Sunday 25-Aug-91 08:46:34 spb
  134.  */
  135. void *safe_AllocAbs(Size, Location, File, Line)
  136. ULONG Size;
  137. void *Location;
  138. char *File;
  139. ULONG Line;
  140. {
  141.   if(gbl_SafeMem)
  142.   {
  143.     struct MemNode *t;
  144.     void *result = 0;
  145.  
  146.     Forbid();
  147.  
  148.     if(head)
  149.       t = head;
  150.     else
  151.       t = 0;
  152.  
  153.     head = (struct MemNode *)AllocAbs(Size + sizeof(struct MemNode),
  154.                      (void *)((char *)Location - sizeof(struct MemNode)));
  155.  
  156.     if(head)
  157.     {
  158.       head->child = t;
  159.       head->file  = File;
  160.       head->line  = Line;
  161.       head->size  = Size;
  162.  
  163.       result = (void *)((long)head + sizeof(struct MemNode));
  164.     }
  165.     else
  166.       head = t;
  167.  
  168.     Permit();
  169.     return(result);
  170.   }
  171.   else
  172.     return((void *)AllocAbs(Size, Location));
  173. }
  174.  
  175. /*
  176.  * FUNCTION:
  177.  *   void safe_FreeMem(Address, Size, File, Line)
  178.  *
  179.  * DESCRIPTION:
  180.  *     Peforms a FreeMem() with the enhanced error checking. Must be accessed
  181.  *   through the macros in safemem.h. Note that all memory allocated with the
  182.  *   safe_ functions must be freed with the safe_ functions.
  183.  *
  184.  * ARGUMENTS:
  185.  *   ULONG Address; Location of block to free
  186.  *   ULONG Size;    Size of block to free
  187.  *   char *File;    Calling file     (__FILE__)
  188.  *   ULONG Line;    Calling line     (__LINE__)
  189.  *
  190.  * WRITTEN:
  191.  *   Friday 14-Dec-90 13:02:20 spb
  192.  */
  193. void safe_FreeMem(Address, Size, File, Line)
  194. void *Address;
  195. ULONG Size;
  196. char *File;
  197. ULONG Line;
  198. {
  199.   if(gbl_SafeMem)
  200.   {
  201.     struct MemNode *t1, *t2;
  202.     char buffer[256];
  203.  
  204.     Forbid();
  205.  
  206.    /*
  207.     * Search the list for the node
  208.     */
  209.     t1 = head;
  210.     t2 = 0;
  211.     while(t1)
  212.     {
  213.       if(Address == (void *)((long)t1+sizeof(struct MemNode)))
  214.       {
  215.        /*
  216.         * Found it, but it's the wrong size
  217.         */
  218.         if(Size != t1->size)
  219.         {
  220.           sprintf(buffer, "%s %d: Incorrect free size. (%d instead of %d)\n",
  221.                      File, Line, Size, t1->size);
  222.                      
  223.           gbl_SafeMemOutput(buffer);
  224.           Permit();
  225.           return;
  226.         }
  227.  
  228.        /*
  229.         * Right size, so remove block from the list 
  230.         */
  231.         if(t2)
  232.           t2->child = t1->child;
  233.         else
  234.           head = t1->child;
  235.  
  236.        /*
  237.         * Actually free the memory
  238.         */
  239.         FreeMem(t1, sizeof(struct MemNode)+t1->size);
  240.         Permit();
  241.         return;
  242.       }
  243.  
  244.       t2 = t1;
  245.       t1 = t1->child;
  246.     }
  247.  
  248.    /*
  249.     * We didn't find the block on the list, so it can't be freed.
  250.     * Either a free twice, or never allocated at all.
  251.     */
  252.     sprintf(buffer, "%s %d: Free twice (?) FreeMem($%lx, %d)\n",
  253.                      File, Line,                   Address, Size);
  254.     gbl_SafeMemOutput(buffer);
  255.     Permit();
  256.     return;
  257.   }
  258.   else
  259.   {
  260.     FreeMem(Address, Size);
  261.     return;
  262.   }
  263. }
  264.  
  265. /*
  266.  * FUNCTION:
  267.  *   ULONG safe_ShowMemList(File, Line)
  268.  *
  269.  * DESCRIPTION:
  270.  *     Displays a list of currently unfreed blocks (if there are any) that
  271.  *   were allocated with safe_AllocMem. Along with each memory block
  272.  *   is the file, function and line it was allocated from.
  273.  *     If gbl_Safemem == 0, this function has no effect.
  274.  *
  275.  * ARGUMENTS:
  276.  *   char *File;    Calling File (__FILE__)
  277.  *   ULONG Line;    Calling Line (__LINE__)
  278.  *
  279.  * RETURNS:
  280.  *   ULONG   Number of memoryblocks in the list.
  281.  *
  282.  * WRITTEN:
  283.  *   Friday 14-Dec-90 13:02:26 spb
  284.  */
  285.  
  286. ULONG safe_ShowMemList(File, Line)
  287. char *File;
  288. ULONG Line;
  289. {
  290.   if(gbl_SafeMem)
  291.   {
  292.     char buffer[256];
  293.     ULONG c=0;
  294.     struct MemNode *t;
  295.  
  296.     Forbid(); /* Slightly pointless when printing to the screen, eh? */
  297.     if(head)
  298.     {
  299.       t = head;
  300.       sprintf(buffer, "%s %d: Memory List\n", File, Line);
  301.       gbl_SafeMemOutput(buffer);
  302.       sprintf(buffer, "    %-12s %-12s %-16s %-4s\n",
  303.              "Address", "Size", "File", "Line");
  304.       gbl_SafeMemOutput(buffer);
  305.       sprintf(buffer, "    %-12s %-12s %-16s %-4s\n",
  306.              "-------", "----", "----", "----");
  307.       gbl_SafeMemOutput(buffer);
  308.  
  309.       while(t)
  310.       {
  311.         sprintf(buffer, "    $%-11lx %-12d %-16s %-4d\n",
  312.                 t, t->size, t->file, t->line);
  313.         gbl_SafeMemOutput(buffer);
  314.  
  315.         t = t->child;
  316.         c++;
  317.       }
  318.     }
  319.     Permit();
  320.     return(c);
  321.   }
  322.   else
  323.     return(0);
  324. }
  325.  
  326. /*
  327.  * FUNCTION:
  328.  *   ULONG safe_FreeMemList(File, Line)
  329.  *
  330.  * DESCRIPTION:
  331.  *     Frees all the memoryblocks present in the safe_ list. This ensures
  332.  *   the environment will get all it's memory back even though the program
  333.  *   is faulty, speeding development time.
  334.  *     If gbl_SafeMem == 0, this function has no effect.
  335.  *
  336.  * ARGUMENTS:
  337.  *   char *File; Calling file (__FILE__)
  338.  *   ULONG Line; Calling line (__LINE__)
  339.  *
  340.  * RETURNS:
  341.  *   long Number of blocks freed.
  342.  *
  343.  * WRITTEN:
  344.  *   Friday 14-Dec-90 13:52:16 spb
  345.  */
  346.  
  347. ULONG safe_FreeMemList(File, Line)
  348. char *File;
  349. ULONG Line;
  350. {
  351.   if(gbl_SafeMem)
  352.   {
  353.     char buffer[256];
  354.     ULONG c=0;
  355.     struct MemNode *t1, *t2;
  356.  
  357.     Forbid();
  358.     if(head)
  359.     {
  360.       t1 = head;
  361.       sprintf(buffer, "%s %d: Freeing Memory List\n", File, Line);
  362.       gbl_SafeMemOutput(buffer);
  363.  
  364.       while(t1)
  365.       {
  366.         t2 = t1->child;
  367.         FreeMem(t1, t1->size + sizeof(struct MemNode));
  368.         t1 = t2;
  369.         c++;
  370.       }
  371.     }
  372.  
  373.     head = 0;
  374.  
  375.     Permit();
  376.     return(c);
  377.   }
  378.   else
  379.     return(0);
  380. }
  381.  
  382. /*
  383.  * FUNCTION:
  384.  *   void *safe_malloc(size, file, line)
  385.  *
  386.  * DESCRIPTION:
  387.  *      malloc() with  with enhanced error checking. Access
  388.  *   to this function should be through the macros in safemem.h -ONLY-.
  389.  *   Note that all memory allocated with the safe_ functions must be freed
  390.  *   with the safe_ functions.
  391.  *
  392.  *      malloc(x) is equivalent to AllocMem(x ,MEMF_PUBLIC|MEMF_CLEAR).
  393.  *
  394.  * ARGUMENTS:
  395.  *   ULONG size;
  396.  *   char *file;
  397.  *   ULONG line;
  398.  *
  399.  * RETURNS:
  400.  *   SUCCESS: A pointer to the block allocated
  401.  *   FAILURE: 0
  402.  *
  403.  * WRITTEN:
  404.  *   Saturday 05-Dec-92 16:34:
  405.  */
  406. void *safe_malloc(size, file, line)
  407. ULONG size;
  408. char *file;
  409. ULONG line;
  410. {
  411.   struct MemNode *newnode;
  412.   void *result;
  413.  
  414.   if(gbl_SafeMem)
  415.   {
  416.     Forbid();
  417.  
  418.     newnode = (struct MemNode *)AllocMem(size + sizeof(struct MemNode), 
  419.                                          MEMF_PUBLIC | MEMF_CLEAR);
  420.  
  421.     if(newnode)
  422.     {
  423.       newnode->child = head;
  424.       newnode->file  = file;
  425.       newnode->line  = line;
  426.       newnode->size  = size;
  427.       head           = newnode;
  428.  
  429.       result = (void *)((long)newnode + sizeof(struct MemNode));
  430.     }
  431.     else
  432.       result = 0;
  433.  
  434.     Permit();
  435.     return(result);
  436.   }
  437.   else
  438.     return(malloc(size));
  439. }
  440.  
  441. /*
  442.  * FUNCTION:
  443.  *   void safe_free(address, file, line)
  444.  *
  445.  * DESCRIPTION:
  446.  *     Safe version of free(). Access should be through the macros.
  447.  *
  448.  * ARGUMENTS:
  449.  *   void *address;
  450.  *   char *file;
  451.  *   ULONG line;
  452.  *
  453.  * WRITTEN:
  454.  *   Saturday 05-Dec-92 16:41:
  455.  */
  456. void safe_free(address, file, line)
  457. void *address;
  458. char *file;
  459. ULONG line;
  460. {
  461.   struct MemNode *node, *prev;
  462.  
  463.   if(gbl_SafeMem)
  464.   {
  465.     if(address)
  466.     {
  467.       char buffer[256];
  468.     
  469.       Forbid();
  470.  
  471.       prev = 0;
  472.       node = head;
  473.  
  474.       while(node)
  475.       {
  476.         if(address == (void *)((long)node+sizeof(struct MemNode)))
  477.         {
  478.          /*
  479.           * Remove block from the list
  480.           */
  481.           if(prev)
  482.             prev->child = node->child;
  483.           else
  484.             head = node->child;
  485.  
  486.          /*
  487.           * Free the memory
  488.           */
  489.           FreeMem(node, node->size + sizeof(struct MemNode));
  490.           return;
  491.         }
  492.  
  493.         prev = node;
  494.         node = node->child;
  495.       }
  496.  
  497.       sprintf(buffer, "%s %d: Free twice (?) free($%lx)\n",
  498.                        file, line,                address);
  499.       gbl_SafeMemOutput(buffer);
  500.  
  501.       Permit();
  502.     }
  503.   }
  504.   else
  505.     free(address);
  506. }
  507.  
  508. /*
  509.  * FUNCTION:
  510.  *   void *safe_realloc(block, newsize, file, line)
  511.  *
  512.  * DESCRIPTION:
  513.  *   Safe version of realloc().
  514.  *
  515.  * ARGUMENTS:
  516.  *   void *block;
  517.  *   ULONG newsize;
  518.  *   char *file;
  519.  *   ULONG line;
  520.  *
  521.  * RETURNS:
  522.  *   SUCCESS: Pointer to new block (pointer may be different to the old block,
  523.  *            but the contents will be preserved).
  524.  *   FAILURE: 0
  525.  *
  526.  * WRITTEN:
  527.  *   Saturday 05-Dec-92 16:42:
  528.  */
  529. void *safe_realloc(block, newsize, file, line)
  530. void *block;
  531. ULONG newsize;
  532. char *file;
  533. ULONG line;
  534. {
  535.   void *newblock;
  536.   struct MemNode *node;
  537.   long oldsize;
  538.  
  539.   if(gbl_SafeMem)
  540.   {
  541.    /*
  542.     * if the oldblock was 0, then this operation is equivalent to a
  543.     * malloc().
  544.     */
  545.     if(!block)
  546.       return(safe_malloc(newsize, file, line));
  547.   
  548.     Forbid();
  549.   
  550.    /*
  551.     * Find the size of the current block
  552.     */
  553.     oldsize = -1;
  554.     node = head;
  555.     while(node)
  556.     {
  557.       if(block == (void *)((long)node+sizeof(struct MemNode)))
  558.       {
  559.         oldsize = node->size;
  560.         break;
  561.       }
  562.   
  563.       node = node->child;
  564.     }
  565.   
  566.     if(oldsize == -1)
  567.     {
  568.       char buffer[256];
  569.       sprintf(buffer, "%s %d: Illegal realloc(%lx, %ld)\n",
  570.                        file, line,            block, newsize);
  571.       gbl_SafeMemOutput(buffer);                 
  572.       Permit();
  573.       return(0);
  574.     }
  575.   
  576.     newblock = safe_malloc(newsize, file, line);
  577.     if(newblock)
  578.     {
  579.       memcpy(newblock, block, min(newsize, oldsize));
  580.       safe_free(block, file, line);
  581.     }
  582.   
  583.     Permit();
  584.     return(newblock);
  585.   }
  586.   else
  587.     return(realloc(block, newsize));
  588. }
  589.  
  590. /*
  591.  * FUNCTION:
  592.  *   void *safe_calloc(elements, elementsize, file, line)
  593.  *
  594.  * DESCRIPTION:
  595.  *     Safe version of calloc().
  596.  *     Equivalent to malloc(elements*elementsize).
  597.  *
  598.  * ARGUMENTS:
  599.  *   ULONG elements, elementsize;
  600.  *   char *file;
  601.  *   ULONG line;
  602.  *
  603.  * RETURNS:
  604.  *   SUCCESS: Pointer to allocated block
  605.  *   FAILURE: 0
  606.  *
  607.  * WRITTEN:
  608.  *   Saturday 05-Dec-92 16:44:
  609.  */
  610. void *safe_calloc(elements, elementsize, file, line)
  611. ULONG elements, elementsize;
  612. char *file;
  613. ULONG line;
  614. {
  615.   return(safe_malloc(elements * elementsize, file, line));
  616. }
  617.