home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / biology / gsrc208a.zip / MEM.C < prev    next >
C/C++ Source or Header  |  1993-07-16  |  15KB  |  711 lines

  1. /*_ mem.c   Fri Jan 26 1990   Modified by: Walter Bright */
  2. /* Memory management package                            */
  3.  
  4. #define MEM_DEBUG 1
  5.  
  6. #include        <stdio.h>
  7.  
  8. #if __ZTC__
  9. #include        <stdlib.h>
  10. #include        <io.h>
  11. #else
  12. extern void *malloc();
  13. extern void *calloc();
  14. extern void *realloc();
  15. #endif
  16.  
  17. #ifndef MEM_H
  18. #include        "mem.h"
  19. #endif
  20.  
  21. #ifndef assert
  22. #include        <assert.h>
  23. #endif
  24.  
  25. #if MSC
  26. #include        <dos.h>
  27. #endif
  28.  
  29. #ifndef VAX11C
  30. #ifdef BSDUNIX
  31. #include <strings.h>
  32. #else
  33. #include <string.h>
  34. #endif
  35. #else
  36. extern char *strcpy(),*memcpy();
  37. extern int strlen();
  38. #endif  /* VAX11C */
  39.  
  40. int mem_inited = 0;             /* != 0 if initialized                  */
  41.  
  42. static int mem_behavior = MEM_ABORTMSG;
  43. static int (*fp) P((void)) = NULL;      /* out-of-memory handler        */
  44. static int mem_count;           /* # of allocs that haven't been free'd */
  45. static int mem_scount;          /* # of sallocs that haven't been free'd */
  46.  
  47. /* Determine where to send error messages       */
  48. #if MSDOS
  49. #define ferr    stdout  /* stderr can't be redirected with MS-DOS       */
  50. #else
  51. #define ferr    stderr
  52. #endif
  53.  
  54. /*******************************/
  55.  
  56. void mem_setexception(flag,handler_fp)
  57. #if __ZTC__ && __cplusplus
  58. enum MEM_E flag;
  59. #else
  60. int flag;
  61. #endif
  62. int (*handler_fp) P((void));
  63. {
  64.     mem_behavior = flag;
  65.     fp = (mem_behavior == MEM_CALLFP) ? handler_fp : 0;
  66. #if MEM_DEBUG
  67.     assert(0 <= flag && flag <= MEM_RETRY);
  68. #endif
  69. }
  70.  
  71. /*************************
  72.  * This is called when we're out of memory.
  73.  * Returns:
  74.  *      1:      try again to allocate the memory
  75.  *      0:      give up and return NULL
  76.  */
  77.  
  78. static int near mem_exception()
  79. {   int behavior;
  80.  
  81.     behavior = mem_behavior;
  82.     while (1)
  83.     {
  84.     switch (behavior)
  85.     {
  86.         case MEM_ABORTMSG:
  87. #if MSDOS || __OS2__
  88.         /* Avoid linking in buffered I/O */
  89.         {   static char msg[] = "Fatal error: out of memory\r\n";
  90.  
  91.         write(1,msg,sizeof(msg) - 1);
  92.         }
  93. #else
  94.         fputs("Fatal error: out of memory\n",ferr);
  95. #endif
  96.         /* FALL-THROUGH */
  97.         case MEM_ABORT:
  98.         exit(EXIT_FAILURE);
  99.         /* NOTREACHED */
  100.         case MEM_CALLFP:
  101.         assert(fp);
  102.         behavior = (*fp)();
  103.         break;
  104.         case MEM_RETNULL:
  105.         return 0;
  106.         case MEM_RETRY:
  107.         return 1;
  108.         default:
  109.         assert(0);
  110.     }
  111.     }
  112. }
  113.  
  114. /****************************/
  115.  
  116. #if MEM_DEBUG
  117.  
  118. #undef mem_strdup
  119.  
  120. #if PROTOTYPING
  121. char *mem_strdup(const char *s)
  122. #else
  123. char *mem_strdup(s)
  124. const char *s;
  125. #endif
  126. {
  127.     return mem_strdup_debug(s,__FILE__,__LINE__);
  128. }
  129.  
  130. char *mem_strdup_debug(s,file,line)
  131. char *file;
  132. const char *s;
  133. int line;
  134. {
  135.     char *p;
  136.  
  137.     p = s
  138.         ? (char *) mem_malloc_debug((unsigned) strlen(s) + 1,file,line)
  139.         : NULL;
  140.     return p ? strcpy(p,s) : p;
  141. }
  142. #else
  143. #if PROTOTYPING
  144. char *mem_strdup(const char *s)
  145. #else
  146. char *mem_strdup(s)
  147. const char *s;
  148. #endif
  149. {
  150.     char *p;
  151.  
  152.     p = s ? (char *) mem_malloc((unsigned) strlen(s) + 1) : NULL;
  153.     return p ? strcpy(p,s) : p;
  154. }
  155.  
  156. #endif /* MEM_DEBUG */
  157.  
  158. #ifdef MEM_DEBUG
  159.  
  160. static long mem_maxalloc;       /* max # of bytes allocated             */
  161. static long mem_numalloc;       /* current # of bytes allocated         */
  162.  
  163. #define BEFOREVAL       0x12345678      /* value to detect underrun     */
  164. #define AFTERVAL        0x87654321      /* value to detect overrun      */
  165.  
  166. #if SUN || SUN386
  167. static long afterval = AFTERVAL;        /* so we can do &afterval       */
  168. #endif
  169.  
  170. /* The following should be selected to give maximum probability that    */
  171. /* pointers loaded with these values will cause an obvious crash. On    */
  172. /* Unix machines, a large value will cause a segment fault.             */
  173. /* MALLOCVAL is the value to set malloc'd data to.                      */
  174.  
  175. #if MSDOS || __OS2__
  176. #define BADVAL          0xFF
  177. #define MALLOCVAL       0xEE
  178. #else
  179. #define BADVAL          0x7A
  180. #define MALLOCVAL       0xEE
  181. #endif
  182.  
  183. /* Disable mapping macros       */
  184. #undef  mem_malloc
  185. #undef  mem_calloc
  186. #undef  mem_realloc
  187. #undef  mem_free
  188.  
  189. /* Create a list of all alloc'ed pointers, retaining info about where   */
  190. /* each alloc came from. This is a real memory and speed hog, but who   */
  191. /* cares when you've got obscure pointer bugs.                          */
  192.  
  193. static struct mem_debug
  194. {       struct mh
  195.     { struct mem_debug *Mnext;      /* next in list                 */
  196.       struct mem_debug *Mprev;      /* previous value in list       */
  197.       char *Mfile;          /* filename of where allocated          */
  198.       int Mline;            /* line number of where allocated       */
  199.       unsigned Mnbytes;     /* size of the allocation               */
  200.       long Mbeforeval;      /* detect underrun of data              */
  201.     } m;
  202.     char data[1];           /* the data actually allocated          */
  203. } mem_alloclist =
  204. {
  205.    {    (struct mem_debug *) NULL,
  206.     (struct mem_debug *) NULL,
  207.     "noname",
  208.     11111,
  209.     0,
  210.     BEFOREVAL
  211.    },
  212.    AFTERVAL
  213. };
  214.  
  215. /* Convert from a void *to a mem_debug struct.  */
  216. #define mem_ptrtodl(p)  ((struct mem_debug *) ((char *)p - sizeof(struct mh)))
  217.  
  218. /* Convert from a mem_debug struct to a mem_ptr.        */
  219. #define mem_dltoptr(dl) ((void *) &((dl)->data[0]))
  220.  
  221. #define next            m.Mnext
  222. #define prev            m.Mprev
  223. #define file            m.Mfile
  224. #define line            m.Mline
  225. #define nbytes          m.Mnbytes
  226. #define beforeval       m.Mbeforeval
  227.  
  228. /*****************************
  229.  * Set new value of file,line
  230.  */
  231.  
  232. void mem_setnewfileline(ptr,fil,lin)
  233. void *ptr;
  234. char *fil;
  235. int lin;
  236. {
  237.     struct mem_debug *dl;
  238.  
  239.     dl = mem_ptrtodl(ptr);
  240.     dl->file = fil;
  241.     dl->line = lin;
  242. }
  243.  
  244. /****************************
  245.  * Print out struct mem_debug.
  246.  */
  247.  
  248. static void near mem_printdl(dl)
  249. struct mem_debug *dl;
  250. {
  251.     fprintf(ferr,"alloc'd from file '%s' line %d nbytes %d ptr x%lx\n",
  252.         dl->file,dl->line,dl->nbytes,(long)mem_dltoptr(dl));
  253. }
  254.  
  255. /****************************
  256.  * Print out file and line number.
  257.  */
  258.  
  259. static void near mem_fillin(fil,lin)
  260. char *fil;
  261. int lin;
  262. {
  263.     fprintf(ferr,"File '%s' line %d\n",fil,lin);
  264.     fflush(ferr);
  265. }
  266.  
  267. /****************************
  268.  * If MEM_DEBUG is not on for some modules, these routines will get
  269.  * called.
  270.  */
  271.  
  272. void *mem_calloc(u)
  273. unsigned u;
  274. {
  275.     return mem_calloc_debug(u,__FILE__,__LINE__);
  276. }
  277.  
  278. void *mem_malloc(u)
  279. unsigned u;
  280. {
  281.     return mem_malloc_debug(u,__FILE__,__LINE__);
  282. }
  283.  
  284. void *mem_realloc(p,u)
  285. void *p;
  286. unsigned u;
  287. {
  288.     return mem_realloc_debug(p,u,__FILE__,__LINE__);
  289. }
  290.  
  291. void mem_free(p)
  292. void *p;
  293. {
  294.     mem_free_debug(p,__FILE__,__LINE__);
  295. }    
  296.  
  297.  
  298. /**************************/
  299.  
  300. void mem_freefp(p)
  301. void *p;
  302. {
  303.     mem_free(p);
  304. }
  305.  
  306. /***********************
  307.  * Debug versions of mem_calloc(), mem_free() and mem_realloc().
  308.  */
  309.  
  310. void *mem_malloc_debug(n,fil,lin)
  311. unsigned n;
  312. char *fil;
  313. int lin;
  314. {   void *p;
  315.  
  316.     p = mem_calloc_debug(n,fil,lin);
  317.     if (p)
  318.     memset(p,MALLOCVAL,n);
  319.     return p;
  320. }
  321.  
  322. void *mem_calloc_debug(n,fil,lin)
  323. unsigned n;
  324. char *fil;
  325. int lin;
  326. {
  327.     struct mem_debug *dl;
  328.  
  329.     do
  330.     dl = (struct mem_debug *)
  331.         calloc(sizeof(*dl) + n + sizeof(AFTERVAL) - 1,1);
  332.     while (dl == NULL && mem_exception());
  333.     if (dl == NULL)
  334.     {
  335. #if 0
  336.     printf("Insufficient memory for alloc of %d at ",n);
  337.     mem_fillin(fil,lin);
  338.     printf("Max allocated was: %ld\n",mem_maxalloc);
  339. #endif
  340.     return NULL;
  341.     }
  342.     dl->file = fil;
  343.     dl->line = lin;
  344.     dl->nbytes = n;
  345.     dl->beforeval = BEFOREVAL;
  346. #if SUN || SUN386 /* bus error if we store a long at an odd address */
  347.     memcpy(&(dl->data[n]),&afterval,sizeof(AFTERVAL));
  348. #else
  349.     *(long *) &(dl->data[n]) = AFTERVAL;
  350. #endif
  351.  
  352.     /* Add dl to start of allocation list       */
  353.     dl->next = mem_alloclist.next;
  354.     dl->prev = &mem_alloclist;
  355.     mem_alloclist.next = dl;
  356.     if (dl->next != NULL)
  357.     dl->next->prev = dl;
  358.  
  359.     mem_count++;
  360.     mem_numalloc += n;
  361.     if (mem_numalloc > mem_maxalloc)
  362.     mem_maxalloc = mem_numalloc;
  363.     return mem_dltoptr(dl);
  364. }
  365.  
  366. void mem_free_debug(ptr,fil,lin)
  367. void *ptr;
  368. char *fil;
  369. int lin;
  370. {
  371.     struct mem_debug *dl;
  372.  
  373.     if (ptr == NULL)
  374.         return;
  375.     if (mem_count <= 0)
  376.     {       fprintf(ferr,"More frees than allocs at ");
  377.         goto err;
  378.     }
  379.     dl = mem_ptrtodl(ptr);
  380.     if (dl->beforeval != BEFOREVAL)
  381.     {
  382.         fprintf(ferr,"Pointer x%lx underrun\n",(long)ptr);
  383.         goto err2;
  384.     }
  385. #if SUN || SUN386 /* Bus error if we read a long from an odd address    */
  386.     if (memcmp(&dl->data[dl->nbytes],&afterval,sizeof(AFTERVAL)) != 0)
  387. #else
  388.     if (*(long *) &dl->data[dl->nbytes] != AFTERVAL)
  389. #endif
  390.     {
  391.         fprintf(ferr,"Pointer x%lx overrun\n",(long)ptr);
  392.         goto err2;
  393.     }
  394.     mem_numalloc -= dl->nbytes;
  395.     if (mem_numalloc < 0)
  396.     {       fprintf(ferr,"error: mem_numalloc = %ld, dl->nbytes = %d\n",
  397.             mem_numalloc,dl->nbytes);
  398.         goto err2;
  399.     }
  400.  
  401.     /* Remove dl from linked list   */
  402.     if (dl->prev)
  403.         dl->prev->next = dl->next;
  404.     if (dl->next)
  405.         dl->next->prev = dl->prev;
  406.  
  407.     /* Stomp on the freed storage to help detect references */
  408.     /* after the storage was freed.                         */
  409.     memset((void *) dl,BADVAL,sizeof(*dl) + dl->nbytes);
  410.     mem_count--;
  411.  
  412.     /* Some compilers can detect errors in the heap.        */
  413. #if DLC
  414.     {       int i;
  415.         i = free(dl);
  416.         assert(i == 0);
  417.     }
  418. #else
  419.     free((void *) dl);
  420. #endif
  421.     return;
  422.  
  423. err2:
  424.     mem_printdl(dl);
  425. err:
  426.     fprintf(ferr,"free'd from ");
  427.     mem_fillin(fil,lin);
  428.     assert(0);
  429.     /* NOTREACHED */
  430. }
  431.  
  432. /*******************
  433.  * Debug version of mem_realloc().
  434.  */
  435.  
  436. void *mem_realloc_debug(oldp,n,fil,lin)
  437. void *oldp;
  438. unsigned n;
  439. char *fil;
  440. int lin;
  441. {   void *p;
  442.     struct mem_debug *dl;
  443.  
  444.     if (n == 0)
  445.     {   mem_free_debug(oldp,fil,lin);
  446.     p = NULL;
  447.     }
  448.     else if (oldp == NULL)
  449.     p = mem_malloc_debug(n,fil,lin);
  450.     else
  451.     {
  452.     p = mem_malloc_debug(n,fil,lin);
  453.     if (p != NULL)
  454.     {
  455.         dl = mem_ptrtodl(oldp);
  456.         if (dl->nbytes < n)
  457.         n = dl->nbytes;
  458.         memcpy(p,oldp,n);
  459.         mem_free_debug(oldp,fil,lin);
  460.     }
  461.     }
  462.     return p;
  463. }
  464.  
  465. /***************************/
  466.  
  467. void mem_check()
  468. {   register struct mem_debug *dl;
  469.  
  470.     for (dl = mem_alloclist.next; dl != NULL; dl = dl->next)
  471.     mem_checkptr(mem_dltoptr(dl));
  472. }
  473.  
  474. /***************************/
  475.  
  476. void mem_checkptr(p)
  477. register void *p;
  478. {   register struct mem_debug *dl;
  479.  
  480.     for (dl = mem_alloclist.next; dl != NULL; dl = dl->next)
  481.     {
  482.     if (p >= (void *) &(dl->data[0]) &&
  483.         p < (void *)((char *)dl + sizeof(struct mem_debug)-1 + dl->nbytes))
  484.         goto L1;
  485.     }
  486.     assert(0);
  487.  
  488. L1:
  489.     dl = mem_ptrtodl(p);
  490.     if (dl->beforeval != BEFOREVAL)
  491.     {
  492.         fprintf(ferr,"Pointer x%lx underrun\n",(long)p);
  493.         goto err2;
  494.     }
  495. #if SUN || SUN386 /* Bus error if we read a long from an odd address    */
  496.     if (memcmp(&dl->data[dl->nbytes],&afterval,sizeof(AFTERVAL)) != 0)
  497. #else
  498.     if (*(long *) &dl->data[dl->nbytes] != AFTERVAL)
  499. #endif
  500.     {
  501.         fprintf(ferr,"Pointer x%lx overrun\n",(long)p);
  502.         goto err2;
  503.     }
  504.     return;
  505.  
  506. err2:
  507.     mem_printdl(dl);
  508.     assert(0);
  509. }
  510.  
  511. #else
  512.  
  513. /***************************/
  514.  
  515. void *mem_malloc(numbytes)
  516. unsigned numbytes;
  517. {       void *p;
  518.  
  519.     if (numbytes == 0)
  520.         return NULL;
  521.     while (1)
  522.     {
  523.         p = malloc(numbytes);
  524.         if (p == NULL)
  525.         {       if (mem_exception())
  526.                 continue;
  527.         }
  528.         else
  529.             mem_count++;
  530.         break;
  531.     }
  532.     /*printf("malloc(%d) = x%lx\n",numbytes,p);*/
  533.     return p;
  534. }
  535.  
  536. /***************************/
  537.  
  538. void *mem_calloc(numbytes)
  539. unsigned numbytes;
  540. {       void *p;
  541.  
  542.     if (numbytes == 0)
  543.         return NULL;
  544.     while (1)
  545.     {
  546.         p = calloc(numbytes,1);
  547.         if (p == NULL)
  548.         {       if (mem_exception())
  549.                 continue;
  550.         }
  551.         else
  552.             mem_count++;
  553.         break;
  554.     }
  555.     /*printf("calloc(%d) = x%lx\n",numbytes,p);*/
  556.     return p;
  557. }
  558.  
  559. /***************************/
  560.  
  561. void *mem_realloc(oldmem_ptr,newnumbytes)
  562. void *oldmem_ptr;
  563. unsigned newnumbytes;
  564. {   void *p;
  565.  
  566.     if (oldmem_ptr == NULL)
  567.     p = mem_malloc(newnumbytes);
  568.     else if (newnumbytes == 0)
  569.     {   mem_free(oldmem_ptr);
  570.     p = NULL;
  571.     }
  572.     else
  573.     {
  574.     do
  575.         p = realloc(oldmem_ptr,newnumbytes);
  576.     while (p == NULL && mem_exception());
  577.     }
  578.     /*printf("realloc(x%lx,%d) = x%lx\n",oldmem_ptr,newnumbytes,p);*/
  579.     return p;
  580. }
  581.  
  582. /***************************/
  583.  
  584. void mem_free(ptr)
  585. void *ptr;
  586. {
  587.     /*printf("free(x%lx)\n",ptr);*/
  588.     if (ptr != NULL)
  589.     {   assert(mem_count != 0);
  590.     mem_count--;
  591. #if DLC
  592.     {       int i;
  593.  
  594.         i = free(ptr);
  595.         assert(i == 0);
  596.     }
  597. #else
  598.     free(ptr);
  599. #endif
  600.     }
  601. }
  602.  
  603. #if __ZTC__
  604.  
  605. /* Minimum size of a free block */
  606. #define MINBLKSIZE      (sizeof(size_t) + sizeof(void *))
  607. /* Boundary that allocations are aligned on     */
  608. #define ALIGNSIZE       (sizeof(size_t))
  609.  
  610. /*****************************/
  611.  
  612. void *mem_scalloc(numbytes)
  613. size_t numbytes;
  614. {   size_t *p;
  615.  
  616.     if (numbytes == 0)
  617.     return NULL;
  618.     if (numbytes < MINBLKSIZE)
  619.     numbytes = MINBLKSIZE;
  620.     else
  621.     numbytes = (numbytes + (ALIGNSIZE - 1)) & ~(ALIGNSIZE - 1);
  622.     p = (size_t *) mem_calloc(numbytes - sizeof(size_t));
  623.     if (p)
  624.     {
  625.     p--;
  626.     *p = 0;
  627.     mem_count--;
  628.     mem_scount++;
  629.     }
  630.     return p;
  631. }
  632.  
  633. /*****************************/
  634.  
  635. void mem_sfree(ptr,numbytes)
  636. void *ptr;
  637. size_t numbytes;
  638. {
  639.     if (ptr != NULL)
  640.     {   assert(mem_scount > 0);
  641.     mem_scount--;
  642.     if (numbytes < MINBLKSIZE)
  643.         numbytes = MINBLKSIZE;
  644.     else
  645.         numbytes = (numbytes + (ALIGNSIZE - 1)) & ~(ALIGNSIZE - 1);
  646.     *((size_t *)ptr)++ = numbytes;  /* store size of free block     */
  647.     free(ptr);
  648.     }
  649. }
  650.  
  651. #endif /* __ZTC__ */
  652.  
  653. #endif
  654.  
  655. /***************************/
  656.  
  657. void mem_init()
  658. {
  659.     if (mem_inited == 0)
  660.     {       mem_count = 0;
  661. #if MEM_DEBUG
  662.         mem_numalloc = 0;
  663.         mem_maxalloc = 0;
  664.         mem_alloclist.next = NULL;
  665. #endif
  666. #if __ZTC__
  667.         /* Necessary if mem_sfree() calls free() before any     */
  668.         /* calls to malloc().                                   */
  669.         free(malloc(1));        /* initialize storage allocator */
  670. #endif
  671.         mem_inited++;
  672.     }
  673. }
  674.  
  675. /***************************/
  676.  
  677. void mem_term()
  678. {
  679.  
  680.     if (mem_inited)
  681.     {
  682. #if MEM_DEBUG
  683.         register struct mem_debug *dl;
  684.  
  685.         for (dl = mem_alloclist.next; dl; dl = dl->next)
  686.         {       fprintf(ferr,"Unfreed pointer: ");
  687.             mem_printdl(dl);
  688.         }
  689. #if 0
  690.         fprintf(ferr,"Max amount ever allocated == %ld bytes\n",
  691.             mem_maxalloc);
  692. #endif
  693. #else
  694.         if (mem_count)
  695.             fprintf(ferr,"%d unfreed items\n",mem_count);
  696.         if (mem_scount)
  697.             fprintf(ferr,"%d unfreed s items\n",mem_scount);
  698. #endif /* MEM_DEBUG */
  699.         assert(mem_count == 0 && mem_scount == 0);
  700.         mem_inited = 0;
  701.     }
  702. }
  703.  
  704. #undef next
  705. #undef prev
  706. #undef file
  707. #undef line
  708. #undef nbytes
  709. #undef beforeval
  710.  
  711.