home *** CD-ROM | disk | FTP | other *** search
/ CD-ROM Aktief 1995 #6 / CDA_6.iso / shell / utils / disked29.arj / SOURCE.ZIP / ALLOC.C next >
Encoding:
C/C++ Source or Header  |  1995-02-19  |  7.6 KB  |  356 lines

  1. /***
  2. *alloc.c - disked malloc/free front-end.
  3. *
  4. *Copyright (c) 1993-1995, Gregg Jennings.  All wrongs reserved.
  5. *   P O Box 200, Falmouth, MA 02541-0200
  6. *
  7. *Purpose:
  8. *   Debugging support.
  9. *
  10. *Notice:
  11. *   This progam may be freely used and distributed.  Any distrubution
  12. *   with modifications must retain the above copyright statement and
  13. *   modifications noted.
  14. *   No pulp-publication, in whole or in part, permitted without
  15. *   permission (magazines or books).
  16. *******************************************************************************/
  17.  
  18. /*
  19.    Version
  20.  
  21.    2.6   20-Dec-1994    converted error references to function calls
  22.    2.5   18-Nov-1994    alloc_handler()
  23.    2.4   11-Sep-1994    removed DISKED ifdefs
  24.                         fixed heapstat()
  25.    2.3   25-Feb-1994    hugealloc(),hugefree(), etc
  26.    2.2   21-Feb-1994    fixed heapstat
  27.    2.1   13-Jan-1994    Borland stuff, heaptest was heapcheck
  28.    2.0   28-Nov-1993
  29.  
  30.    malloc() and free() front end or "wrappers".  This family of
  31.    functions can be called explicitly (as DISKED does) or via
  32.    macros:
  33.  
  34.       #define malloc(s)    alloc(1,s)
  35.       #define free(p)      freep(p)
  36.          etc.
  37.  
  38.    which will enable them to be used if needed for debugging.
  39.    The heaptest() function can find bounds errors; just add
  40.    this in your code to find it:
  41.  
  42.       if (heaptest() < 1)
  43.          printf("%s%d",__FILE__,__LINE__);
  44.  
  45.    Notes:   This unit can be a separate unit.  The only globals
  46.             referenced are the error message enums in ERROR.H.
  47.             The ERROR.C error message calls can be removed
  48.             without effect.
  49.  
  50.             Borland does not have a near heap in Large Memory model.
  51. */
  52.  
  53. #include <stdlib.h>
  54. #include <malloc.h>
  55.  
  56. #include "alloc.h"
  57. #include "error.h"
  58.  
  59. /* globals referenced here 
  60.  
  61.    error number definitions (enum ERROR_MSG, ERROR.H)
  62.  
  63. */
  64.  
  65. /* globals defined here */
  66.  
  67. unsigned int blocks = 0;               /* statistics only */
  68. unsigned int nblocks = 0;              /* used by DEBUG.C */
  69. unsigned int hblocks = 0;
  70. unsigned int frees = 0;
  71. unsigned int nfrees = 0;
  72. unsigned int hfrees = 0;
  73.  
  74.  
  75. /* internal functions */
  76.  
  77. static void default_alloc_handler(void);
  78.  
  79.  
  80. /***
  81. *alloc_handler -  got the idea from C++, this is called
  82. *                 for alloc failures
  83. *
  84. ***/
  85.  
  86. void (*alloc_handler)(void) = default_alloc_handler;
  87.  
  88. /***
  89. *default_alloc_handler -  handles memory allocation failure
  90. *
  91. *  So far only sets error message information.
  92. *
  93. ****/
  94.  
  95. static void default_alloc_handler(void)
  96. {
  97.    set_err_num(ALLOC_FAIL);            /* set error number */
  98.                                        /*  the module, function error */
  99.                                        /*  arg are set by the caller */
  100.    set_err_info("memavail: %lu",memavail()); /* set avail. mem. info */
  101. }
  102.  
  103. /***
  104. *set_alloc_handler   -  set the function to call upon malloc
  105. *                       failure
  106. *
  107. ****/
  108.  
  109. extern void set_alloc_handler(void (*func)(void))
  110. {
  111.    alloc_handler = (func) ? func : default_alloc_handler;
  112. }
  113.  
  114. /***
  115. *alloc   -  malloc/calloc replacement
  116. *
  117. ****/
  118.  
  119. extern void *alloc(size_t num, size_t size)
  120. {
  121. void *t;
  122.  
  123.    if (size == 0)
  124.    {
  125.       set_err_num(ALLOC_ZERO);
  126.       return NULL;
  127.    }
  128.    if ((t = calloc(num,size)) == NULL)
  129.       alloc_handler();
  130.  
  131.    ++blocks;
  132.    return t;
  133. }
  134.  
  135. #ifndef __BORLANDC__
  136.  
  137. extern void _near *nalloc(size_t num, size_t size)
  138. {
  139. void _near *t;
  140.  
  141.    if (size == 0)
  142.    {
  143.       set_err_num(ALLOC_ZERO);
  144.       return NULL;
  145.    }
  146.    if ((t = _ncalloc(num,size)) == NULL)
  147.       alloc_handler();
  148.  
  149.    ++nblocks;
  150.    return t;
  151. }
  152.  
  153. #endif   /* !__BORLANDC__ */
  154.  
  155. extern void _huge *hugealloc(long num, long size)
  156. {
  157. void _huge *t;
  158.  
  159.    if (size == 0)
  160.    {
  161.       set_err_num(ALLOC_ZERO);
  162.       return NULL;
  163.    }
  164.  
  165.    if ((t = huge_alloc(num,size)) == NULL)
  166.       alloc_handler();
  167.  
  168.    ++hblocks;
  169.    return t;
  170. }
  171.  
  172. /* realloc() */
  173.  
  174. extern void *newalloc(void *p, size_t size)
  175. {
  176.    if (p != NULL)
  177.       freep(p);
  178.    return alloc(1,size);
  179. }
  180.  
  181. extern void freep(void *addr)
  182. {
  183. int h;
  184.  
  185.    if (addr != NULL)
  186.    {
  187.       free(addr);
  188.       if ((h = _fheapset(254)) != _HEAPOK)
  189.       {
  190.          set_error(NULL,"alloc",HEAP_ERROR,"freep");
  191.          set_err_arg(heapstat(h));
  192.       }
  193.       addr = NULL;
  194.       ++frees;
  195.    }
  196.    else
  197.       set_err_num(FREE_NULL);
  198. }
  199.  
  200. #if !defined(__BORLANDC__)
  201.  
  202. extern void nfreep(void _near *addr)
  203. {
  204. int h;
  205.  
  206.    if (addr != NULL)
  207.    {
  208.       _nfree(addr);
  209.       if ((h = _nheapset(254)) != _HEAPOK)
  210.       {
  211.          set_error(NULL,"alloc",HEAP_ERROR,"nfreep");
  212.          set_err_arg(heapstat(h));
  213.       }
  214.       addr = NULL;
  215.       ++nfrees;
  216.    }
  217.    else
  218.       set_err_num(FREE_NULL);
  219. }
  220.  
  221. #endif
  222.  
  223. extern void hugefreep(void _huge *addr)
  224. {
  225.    if (addr != NULL)
  226.    {
  227.       huge_free(addr);
  228.       addr = NULL;
  229.       ++hfrees;
  230.    }
  231.    else
  232.       set_err_num(FREE_NULL);
  233. }
  234.  
  235.  
  236. /***
  237. *heaptest()
  238. *
  239. *   putting calls to this throughout the program can help find were the
  240. *   heap is getting corrupted:
  241. *
  242. *      if (heaptest() < 1)
  243. *         printf("%s%d",__FILE__,__LINE__);
  244. ***/
  245.  
  246. extern int heaptest(void)
  247. {
  248. int h;
  249.  
  250. #if !defined(__BORLANDC__)
  251.    if ((h = _fheapchk()) != _HEAPOK || (h = _nheapchk()) != _HEAPOK)
  252. #else
  253.    if ((h = _heapchk()) != _HEAPOK)
  254. #endif
  255.       return h;
  256.    else
  257.       return 1;
  258. }
  259.  
  260. /* AS IN MALLOC.H:
  261.  
  262. constants for _heapchk/_heapset/_heapwalk routines
  263.  
  264. Borland:
  265.  
  266. #define _HEAPEMPTY      1     // 0
  267. #define _HEAPOK         2     // 1
  268. #define _HEAPEND        5     // 4
  269. #define _HEAPCORRUPT   -1     // 5
  270. #define _BADNODE       -2     // 2
  271. #define _BADVALUE      -3     // 3
  272.  
  273. #define _FREEENTRY      3
  274. #define _USEDENTRY      4
  275.  
  276. Microsoft:
  277.  
  278. #define _HEAPEMPTY      (-1)
  279. #define _HEAPOK         (-2)           // _heapchk/_heapset only
  280. #define _HEAPBADBEGIN   (-3)
  281. #define _HEAPBADNODE    (-4)
  282. #define _HEAPEND        (-5)           // _heapwalk only
  283. #define _HEAPBADPTR     (-6)
  284.  
  285. #define _FREEENTRY      0
  286. #define _USEDENTRY      1
  287.  
  288. Watcom:
  289.  
  290. #define _HEAPOK         0
  291. #define _HEAPEMPTY      1  // heap isn't initialized
  292. #define _HEAPBADBEGIN   2  // heap header is corrupted
  293. #define _HEAPBADNODE    3  // heap entry is corrupted
  294. #define _HEAPEND        4  // end of heap entries (_heapwalk)
  295. #define _HEAPBADPTR     5  // invalid heap entry pointer (_heapwalk)
  296.  
  297. #define _FREEENTRY      1
  298. #define _USEDENTRY      0
  299.  
  300.  
  301. You can see the dificulty with these compiler library functions!
  302. */
  303.  
  304. /* heap status message - values are normalized to 0-N */
  305.  
  306. static char *heap_msg[] = {
  307. #ifdef _MSC_VER
  308.    "empty heap",
  309.    "heap is fine",
  310.    "bad start of heap",
  311.    "bad node in heap",
  312.    "end of heap",
  313.    "bad pointer to heap",
  314.    "bad heap",                /* unknown value */
  315. #elif __WATCOMC__
  316.    "heap is fine",
  317.    "empty heap",
  318.    "bad start of heap",
  319.    "bad node in heap",
  320.    "end of heap",
  321.    "bad pointer to heap",
  322.    "bad heap",                /* unknown value */
  323. #elif __BORLANDC__
  324.    "empty heap",
  325.    "heap is fine",
  326.    "bad node in heap",
  327.    "bad pointer to heap",
  328.    "end of heap",
  329.    "bad heap",                /* unknown value */
  330. #else
  331. #error put Your compiler messages here
  332. #endif
  333. };
  334.  
  335. /* get heap status message */
  336.  
  337. extern char *heapstat(int status)
  338. {
  339. #ifdef _MSC_VER
  340.    status = -status-1;     /* make offset into message array */
  341. #elif defined(__BORLANDC__)
  342.    if (status < 0)
  343.    {
  344.       if (status == -1)
  345.          status = 5;
  346.       else
  347.          status = -status;
  348.    }
  349.    else
  350.       --status;
  351. #endif
  352.    if (status < 0 || status > (sizeof(heap_msg)/sizeof(char *))-1)
  353.       status = (sizeof(heap_msg)/sizeof(char *))-1;
  354.    return heap_msg[status];
  355. }
  356.