home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / snip9707.zip / JMALLOC.C < prev    next >
C/C++ Source or Header  |  1997-07-05  |  22KB  |  664 lines

  1. /* +++Date last modified: 05-Jul-1997 */
  2.  
  3. /*--------------------------------------------------------------*/
  4. /* Debugging extension by Jeff Dunlop                           */
  5. /* Copyright 1992-1993, DB/Soft Publishing Co.                  */
  6. /* License is hereby granted for use of JMalloc as a debugging  */
  7. /* aid in any program.  JMalloc may not be sold or distributed  */
  8. /* as or part of any for-profit debugging program or library    */
  9. /* nor may it be included in any for-profit library that offers */
  10. /* debugging features.  Any redistribution of JMalloc source    */
  11. /* must include this copyright notice.                          */
  12. /*--------------------------------------------------------------*/
  13.  
  14. /*-------------------------[ jmalloc.c ]------------------------*/
  15. /*                 drop-in for malloc with diags                */
  16. /*--------------------------------------------------------------*/
  17.  
  18. /*--------------------------------------------------------------*/
  19. /*---------------------------[ notes ]--------------------------*/
  20. /*--------------------------------------------------------------*/
  21.  
  22. /*
  23.  
  24. The J... macros are intended for use on JMalloc'd memory blocks.  The
  25. A... macros are intended for use on auto array blocks and will only
  26. work if the base of the array is passed.  They will not work if the
  27. address of an array element is passed.  All functions are designed to
  28. be nearly drop-in replacements for standard library functions.  The one
  29. case where debugging libraries traditionally fall short is when a block
  30. operation occurs on an automatic array in a position other than at the
  31. head.  This library could conceivably be extended to include a class of
  32. functions that allow you to pass both a block and an offset into that
  33. block so that the block and its size can be checked.  My style of
  34. programming eschews this practice so I haven't had any motivation to so
  35. extend this library.  Note that such an extension would depart slightly
  36. from the standard syntax of the runtime library because of the
  37. additional passed parameter.
  38.  
  39. JMemcheck(0) may be called at any time for an overwrite check of all
  40. allocated blocks.  JMemcheck(1) additionally checks for orphaned blocks
  41. and should be called just before program shutdown.
  42.  
  43. All functions are designed to log any detectable errors when the errors
  44. occur, and to report either the line number of the overwrite, or the
  45. line number that the block was allocated on, depending on which is more
  46. useful.  Any blocks that are damaged by non-JMalloc functions will not
  47. be noticed until they are JFree'd and will be tougher to debug.
  48. Regardless of the damage that a function call produces, JMalloc never
  49. departs from the runtime library's behavior.  Its job is to report,
  50. nothing more.  All allocated blocks (except for JCalloc calls) are
  51. dirtied and all blocks are dirtied before they are freed.  If you are
  52. referencing freed memory or not initializing a new block, it will be
  53. very obvious.  All blocks have an extra check byte that is checked when
  54. the block is freed or during JMemcheck.  This doesn't catch random
  55. memory writes, but it does catch overruns.
  56.  
  57. */
  58.  
  59. /*--------------------------------------------------------------*/
  60. /*-----------------------[ header files ]-----------------------*/
  61. /*--------------------------------------------------------------*/
  62.  
  63. #define DBUG
  64.  
  65. #if defined __TURBOC__
  66.  #include <alloc.h>
  67.  #include <mem.h>
  68. #else
  69.  #if defined(__ZTC__)
  70.   #include <dos.h>
  71.  #else
  72.   #include <malloc.h>
  73.  #endif
  74. #endif
  75.  
  76. #include <stdarg.h>
  77. #include <stdio.h>
  78. #include <stdlib.h>
  79. #include <string.h>
  80. #include "jmalloc.h"
  81.  
  82. /*--------------------------------------------------------------*/
  83. /*--------------------[ local prototypes ]----------------------*/
  84. /*--------------------------------------------------------------*/
  85.  
  86. static MLINK *JMemOwner(char *Addr);
  87.  
  88. /*--------------------------------------------------------------*/
  89. /*---------------------[ global variables ]---------------------*/
  90. /*--------------------------------------------------------------*/
  91.  
  92. MLINK *MalTop;                        /* top of allocation chain */
  93.  
  94. void db_prn(char *fmt, ...)
  95. {
  96.     va_list p;
  97.  
  98.     va_start(p, fmt);
  99.     vprintf(fmt, p);
  100.     putchar('\n');
  101.     va_end(p);
  102. }
  103.  
  104. void *j_deref(void *a, char *file, int line)
  105. {
  106.     if ( a == NULL )
  107.     {
  108.         DBUG_PRINT("alloc", ("Dereferenced NULL pointer - %s: line %d",
  109.             file, line));
  110.     }
  111.     return a;
  112. }
  113.  
  114. /*-------------------------[ j_malloc ]-------------------------*/
  115. /*            Memory allocator with diagnostics                 */
  116. /*--------------------------------------------------------------*/
  117. /* input:                                                       */
  118. /*      Size = number of bytes to allocate                      */
  119. /* local:                                                       */
  120. /*      CurMal = pointer current mem struct                     */
  121. /*      PrevMal = pointer to previous mem struct                */
  122. /*      AllocAddr = pointer to allocated ram                    */
  123. /* return:                                                      */
  124. /*      address of allocated ram, or NULL on error              */
  125. /* note:                                                        */
  126. /*       use the JMalloc macro                                  */
  127. /*--------------------------------------------------------------*/
  128.  
  129. static int memc;
  130.  
  131. void *j_malloc(unsigned Size, char *file, int line)
  132. {
  133.     /* 1. Allocate the memory */
  134.     /* 2. Add to allocation chain */
  135.     /* 3. Fill with non-null */
  136.  
  137.     MLINK *CurMal = MalTop,
  138.           *PrevMal;
  139.  
  140.     void *AllocAddr;
  141.  
  142.     /* Allocate the memory + 1 (for check byte) */
  143.  
  144.     if ( (AllocAddr = malloc(Size + 1)) == NULL )
  145.     {
  146.         DBUG_PRINT("alloc", ("Allocation failed: %s Line %d", file, line));
  147.         return((void*)0);
  148.     }
  149.  
  150.     /* Add to the allocation chain */
  151.  
  152.     PrevMal = CurMal;
  153.     while ( CurMal != NULL )
  154.     {
  155.         PrevMal = CurMal;
  156.         CurMal = CurMal->NextLink;
  157.     }
  158.     if ( (CurMal = malloc(sizeof *CurMal)) == NULL )
  159.     {
  160.         DBUG_PRINT("alloc", ("Control allocation failed: %s Line %d", file,
  161.             line));
  162.         return(AllocAddr);
  163.     }
  164.  
  165.     /* Deal with bootstrap */
  166.     if ( PrevMal == NULL )
  167.         MalTop = CurMal;
  168.     else
  169.         PrevMal->NextLink = CurMal;
  170.     CurMal->NextLink = NULL;
  171.     CurMal->MAddr = AllocAddr;
  172.     CurMal->MSize = Size;
  173.     CurMal->MLine = line;
  174.     AStrCpy(CurMal->MFile, file);
  175.  
  176.     memset(AllocAddr, CKBYT, Size + 1);
  177.     memc++;
  178.     return(AllocAddr);
  179. }
  180.  
  181. /*-------------------------[ j_calloc ]-------------------------*/
  182. /*            Memory allocator with diagnostics                 */
  183. /*--------------------------------------------------------------*/
  184. /* method:                                                      */
  185. /*      - Allocate the memory via JMalloc                       */
  186. /*      - Fill with null                                        */
  187. /*      - Set check-byte                                        */
  188. /* input:                                                       */
  189. /*      Size = number of bytes to allocate                      */
  190. /* local:                                                       */
  191. /*      CurCal = pointer current mem struct                     */
  192. /*      PrevCal = pointer to previous mem struct                */
  193. /*      AllocAddr = pointer to allocated ram                    */
  194. /* return:                                                      */
  195. /*      address of allocated ram, or NULL on error              */
  196. /*  note:                                                       */
  197. /*      Use the JCalloc macro                                   */
  198. /*--------------------------------------------------------------*/
  199.  
  200. void *j_calloc(unsigned Size, unsigned SizEach, char *file, int line)
  201. {
  202.     char *AllocAddr;
  203.  
  204.     /* Allocate the memory + 1 (for check byte) */
  205.  
  206.     /* Do not piss over NULL return - JMalloc handled that */
  207.     if ( (AllocAddr = j_malloc(Size * SizEach, file, line)) != NULL )
  208.     {
  209.         /* Prep allocated ram */
  210.         memset(AllocAddr, 0, Size * SizEach);
  211.         AllocAddr[Size * SizEach] = CKBYT;
  212.     }
  213.  
  214.     return(AllocAddr);
  215. }
  216.  
  217. /*-------------------------[ j_realloc ]------------------------*/
  218. /*                     Reallocate memory                        */
  219. /*--------------------------------------------------------------*/
  220. /* input:                                                       */
  221. /*  Addr = block's current address                              */
  222. /*  Size = block's new size                                     */
  223. /* return:                                                      */
  224. /*  Block's new address, or NULL if memory not available.       */
  225. /* note:                                                        */
  226. /*  Use the JRealloc macro.                                     */
  227. /*  If NULL is returned, Addr was also freed                    */
  228. /*--------------------------------------------------------------*/
  229.  
  230. void *j_realloc(void *Addr, unsigned Size, char *file, int line)
  231. {
  232.     MLINK *CurMal = MalTop;
  233.  
  234.     void *tmp;
  235.  
  236.     if ( Addr == NULL )
  237.         return(j_malloc(Size, file, line));
  238.     /* Find the old block in the alloc list */
  239.     while ( CurMal->MAddr != Addr && CurMal != NULL )
  240.         CurMal = CurMal->NextLink;
  241.     if ( CurMal == NULL )
  242.     {
  243.         /* Just call the standard realloc since we don't know anything
  244.          * about this block
  245.          */
  246.         DBUG_PRINT("alloc", ("Realloc attempted on unrecorded block: %s "
  247.             "Line %d", file, line));
  248.         return(realloc(Addr, Size));
  249.     }
  250.     else
  251.     {
  252.         tmp = j_malloc(Size, file, line);
  253.         if ( tmp != NULL )
  254.         {
  255.             memcpy(tmp, Addr, min(CurMal->MSize, Size));
  256.             j_free(Addr, file, line);
  257.         }
  258.         else
  259.         {
  260.             j_free(Addr, file, line);
  261.             return NULL;
  262.         }
  263.     }
  264.     return(tmp);
  265. }
  266.  
  267. /*-------------------------[ j_free ]---------------------------*/
  268. /*           Memory deallocator with diagnostics                */
  269. /*--------------------------------------------------------------*/
  270. /* input:                                                       */
  271. /*      AllocAddr = pointer to ram to deallocate                */
  272. /* local:                                                       */
  273. /*      CurMal = pointer to current mem struct                  */
  274. /*      PrevMal = pointer to prev mem struct                    */
  275. /* note:                                                        */
  276. /*      This function is designed to be implemented with the    */
  277. /*      macro JFree                                             */
  278. /*--------------------------------------------------------------*/
  279.  
  280. void j_free(void *AllocAddr, char *file, int line)
  281. {
  282.     /* 1. Find the block in the alloc list */
  283.     /* 2. Check for check-byte overwrite   */
  284.     /* 3. Remove allocation record         */
  285.     /* 3. Free the ram                     */
  286.  
  287.     MLINK *CurMal = MalTop,
  288.           *PrevMal = MalTop;
  289.  
  290.     /* Find the block in the alloc list */
  291.     while ( CurMal != NULL && CurMal->MAddr != AllocAddr )
  292.     {
  293.         PrevMal = CurMal;
  294.         CurMal = CurMal->NextLink;
  295.     }
  296.     if ( CurMal == NULL )
  297.     {
  298.         DBUG_PRINT("alloc", ("Freeing an unrecorded block: %s %d", file,
  299.             line));
  300.     }
  301.     else
  302.     {
  303.         /* Check for check-byte overwrite */
  304.         if ( CurMal->MAddr[CurMal->MSize] != CKBYT )
  305.             DBUG_PRINT("alloc", ("Memory overrun detected on block allocated"
  306.             " at %s Line %d", CurMal->MFile, CurMal->MLine));
  307.         memset(AllocAddr, DIRTY, CurMal->MSize + 1);
  308.  
  309.         if ( CurMal == MalTop )
  310.             MalTop = CurMal->NextLink;
  311.         else
  312.             PrevMal->NextLink = CurMal->NextLink;
  313.         free(CurMal);
  314.     }
  315.  
  316.     /* Free the ram regardless of validity */
  317.     free(AllocAddr);
  318.     memc--;
  319.     return;
  320. }
  321.  
  322. /*-------------------------[ JMemcheck ]------------------------*/
  323. /*                Verify memory chain integrity                 */
  324. /*--------------------------------------------------------------*/
  325. /* input:                                                       */
  326. /*  CheckFree != if currently allocated blocks are to be        */
  327. /*  reported                                                    */
  328. /* local:                                                       */
  329. /*      i = link number                                         */
  330. /*      CurMal = link pointer                                   */
  331. /*      status = current error condition                        */
  332. /* return:                                                      */
  333. /*      -1 = error,                                             */
  334. /*      0 = no error detected                                   */
  335. /*--------------------------------------------------------------*/
  336.  
  337. int j_memcheck(int CheckFree)
  338. {
  339.     int status = 0;
  340.  
  341.     MLINK *CurMal = MalTop;
  342.  
  343.     /* Walk the alloc list */
  344.     if ( CheckFree >= 2 )
  345.     {
  346.         DBUG_PRINT("alloc", ("There should be %d unfreed blocks", memc));
  347.     }
  348.  
  349.     while ( CurMal != NULL )
  350.     {
  351.         if ( CurMal->MAddr[CurMal->MSize] != CKBYT )
  352.         {
  353.             DBUG_PRINT("alloc", ("Memory overrun detected in link "
  354.             "allocated at %s Line %d", CurMal->MFile, CurMal->MLine));
  355.             status = -1;
  356.         }
  357.         if ( CheckFree >= 1 )
  358.         {
  359.             DBUG_PRINT("alloc", ("Unfreed block of size %d allocated at "
  360.             "%s Line %d", CurMal->MSize, CurMal->MFile, CurMal->MLine));
  361.             status = -1;
  362.         }
  363.         CurMal = CurMal->NextLink;
  364.     }
  365.     return(status);
  366. }
  367.  
  368. /*-------------------------[ JMemValid ]------------------------*/
  369. /*          Verify an address is in a JMalloc space             */
  370. /*--------------------------------------------------------------*/
  371.  
  372. int JMemValid(char *Addr)
  373. {
  374.     MLINK *CurMal = MalTop;
  375.  
  376.     while ( CurMal != NULL )
  377.     {
  378.         if ( Addr >= CurMal->MAddr && Addr <= CurMal->MAddr + CurMal->MSize )
  379.             return(TRUE);
  380.         CurMal = CurMal->NextLink;
  381.     }
  382.  
  383.     return(FALSE);
  384. }
  385.  
  386. /*-------------------------[ JMemOwner ]------------------------*/
  387. /*            Return the owner of a block of ram                */
  388. /*--------------------------------------------------------------*/
  389.  
  390. static MLINK *JMemOwner(char *Addr)
  391. {
  392.     MLINK *CurMal = MalTop;
  393.  
  394.     while ( CurMal != NULL )
  395.     {
  396.         unsigned long Cur = (unsigned long)CurMal->MAddr,
  397.                       Adr = (unsigned long)Addr;
  398.         if ( Adr >= Cur && Adr <= Cur + CurMal->MSize )
  399.             return(CurMal);
  400.         CurMal = CurMal->NextLink;
  401.     }
  402.  
  403.     return((void*)NULL);
  404. }
  405.  
  406. /*-------------------------[ j_strcpy ]-------------------------*/
  407. /*          String copy with checks and protections             */
  408. /*--------------------------------------------------------------*/
  409.  
  410. char *j_strcpy(char *__dest, const char *__src, char *file, int line)
  411. {
  412.     MLINK *MemOwner = JMemOwner(__dest);
  413.  
  414.     if ( MemOwner == NULL )
  415.     {
  416.         DBUG_PRINT("alloc", ("Strcpy destination invalid - %s: line %d",
  417.             file, line));
  418.     }
  419.     else if ( strlen(__src) > MemOwner->MAddr + MemOwner->MSize - __dest )
  420.     {
  421.         DBUG_PRINT("alloc", ("Strcpy destination overrun - %s: line %d",
  422.             file, line));
  423.     }
  424.     return(strcpy(__dest, __src));
  425. }
  426.  
  427. /*-------------------------[ j_strncpy ]------------------------*/
  428. /*                 String n copy with checks                    */
  429. /*--------------------------------------------------------------*/
  430.  
  431. char *j_strncpy(char *__dest, const char *__src, size_t maxlen, char *file,
  432.                 int line)
  433. {
  434.     MLINK *MemOwner = JMemOwner(__dest);
  435.  
  436.     if ( MemOwner == NULL )
  437.     {
  438.         DBUG_PRINT("alloc", ("strncpy destination invalid - %s: line %d",
  439.             file, line));
  440.     }
  441.     else if ( maxlen > MemOwner->MAddr + MemOwner->MSize - __dest )
  442.     {
  443.         DBUG_PRINT("alloc", ("strncpy destination overrun - %s: line %d",
  444.             file, line));
  445.     }
  446.  
  447.     return(strncpy(__dest, __src, maxlen));
  448. }
  449.  
  450. char *j_strcat(char *__dest, char *__src, char *file, int line)
  451. {
  452.     MLINK *MemOwner = JMemOwner(__dest);
  453.  
  454.     if ( MemOwner == NULL )
  455.     {
  456.         DBUG_PRINT("alloc", ("strcat destination invalid - %s: line %d",
  457.             file, line));
  458.     }
  459.     else if ( strlen(MemOwner->MAddr) + strlen(__src) + 1 > MemOwner->MSize )
  460.     {
  461.         DBUG_PRINT("alloc", ("strcat destination overrun - %s: line %d",
  462.             file, line));
  463.     }
  464.  
  465.     return(strcat(__dest, __src));
  466. }
  467.  
  468. char *j_strdup(char *__str, char *file, int line)
  469. {
  470.     char *p = j_malloc(strlen(__str) + 1, file, line);
  471.  
  472.     if ( p != NULL )
  473.     {
  474.         j_strcpy(p, __str, file, line);
  475.     }
  476.     return(p);
  477. }
  478.  
  479. char *j_strnset(char *str, int ch, size_t n, char *file, int line)
  480. {
  481.     MLINK *MemOwner = JMemOwner(str);
  482.  
  483.     if ( MemOwner == NULL )
  484.     {
  485.         DBUG_PRINT("alloc", ("strnset destination invalid - %s: line %d",
  486.             file, line));
  487.     }
  488.     return(strnset(str, ch, n));
  489. }
  490.  
  491. char *j_strset(char *str, int ch, char *file, int line)
  492. {
  493.     MLINK *MemOwner = JMemOwner(str);
  494.  
  495.     if ( MemOwner == NULL )
  496.     {
  497.         DBUG_PRINT("alloc", ("strset destination invalid - %s: line %d",
  498.             file, line));
  499.     }
  500.     return(strset(str, ch));
  501. }
  502.  
  503. /*------------------------[ j_checkstr ]------------------------*/
  504. /*             Check a MLINK string for problems                */
  505. /* j_sprintf      sprintf replacement                           */
  506. /*--------------------------------------------------------------*/
  507.  
  508. int j_checkstr(MLINK *str)
  509. {
  510.     if ( str->MAddr[str->MSize] != CKBYT || strlen(str->MAddr) > str->MSize - 1 )
  511.     {
  512.         DBUG_PRINT("alloc",
  513.             ("Bad string, allocated at %s Line %d", str->MFile, str->MLine));
  514.         return 1;
  515.     }
  516.     return 0;
  517. }
  518.  
  519. void *j_memcpy(void *dest, const void *src, size_t n, char *file, int line)
  520. {
  521.     MLINK *MemOwner = JMemOwner(dest);
  522.  
  523.     if ( MemOwner == NULL )
  524.     {
  525.         DBUG_PRINT("alloc", ("memcpy destination invalid - %s: line %d",
  526.             file, line));
  527.     }
  528.     else if ( n > MemOwner->MAddr + MemOwner->MSize - (char *)dest )
  529.     {
  530.         DBUG_PRINT("alloc", ("memcpy destination overrun - %s: line %d",
  531.             file, line));
  532.     }
  533.  
  534.     return(memcpy(dest, src, n));
  535. }
  536.  
  537. void *j_memset(void *dest, int ch, size_t n, char *file, int line)
  538. {
  539.     MLINK *MemOwner = JMemOwner(dest);
  540.  
  541.     if ( MemOwner == NULL )
  542.     {
  543.         DBUG_PRINT("alloc", ("memset destination invalid - %s: line %d",
  544.             file, line));
  545.     }
  546.     else if ( n > MemOwner->MAddr + MemOwner->MSize - (char *)dest )
  547.     {
  548.         DBUG_PRINT("alloc", ("memset destination overrun - %s: line %d",
  549.             file, line));
  550.     }
  551.  
  552.     return(memset(dest, ch, n));
  553. }
  554.  
  555. char *a_strcpy(char *__dest, const char *__src, int size, char *file,
  556.     int line)
  557. {
  558.     if ( strlen(__src) >= size)
  559.         DBUG_PRINT("alloc", ("strcpy destination overrun - %s: line %d",
  560.             file, line));
  561.     return(strcpy(__dest, __src));
  562. }
  563.  
  564. char *a_strncpy(char *dest, const char *src, size_t n, int size, char *file,
  565.     int line)
  566. {
  567.     if ( n >= size )
  568.         DBUG_PRINT("alloc", ("strncpy destination overrun - %s: line %d",
  569.             file, line));
  570.     return(strncpy(dest, src, n));
  571. }
  572.  
  573. char *a_strcat(char *dest, const char *src, int size, char *file, int line)
  574. {
  575.     if ( strlen(dest) + strlen(src) + 1 > size )
  576.         DBUG_PRINT("alloc", ("strcat destination overrun = %s: line %d",
  577.             file, line));
  578.     return(strcat(dest, src));
  579. }
  580.  
  581. char *a_strnset(char *str, int ch, size_t n, int size, char *file, int line)
  582. {
  583.     if ( n + 1 > size )
  584.         DBUG_PRINT("alloc", ("strnset destination overrun - %s: line %d",
  585.             file, line));
  586.     return(strnset(str, ch, n));
  587. }
  588.  
  589. void *a_memcpy(void *dest, const void *src, size_t n, int size, char *file,
  590.              int line)
  591. {
  592.     if ( n > size )
  593.         DBUG_PRINT("alloc", ("memcpy destination overrun - %s: line %d",
  594.             file, line));
  595.     return(memcpy(dest, src, n));
  596. }
  597.  
  598. void *a_memset(void *dest, int ch, size_t n, int size, char *file, int line)
  599. {
  600.     if ( n > size )
  601.         DBUG_PRINT("alloc", ("memset destination overrun - %s: line %d",
  602.             file, line));
  603.     return memset(dest, ch, n);
  604. }
  605.  
  606. #ifdef TEST
  607.  
  608. #ifdef __WATCOMC__
  609.  #pragma off (unreferenced);
  610. #endif
  611. #ifdef __TURBOC__
  612.  #pragma argsused
  613. #endif
  614.  
  615. int main(int argc, char *argv[])
  616. {
  617.     char *new,
  618.          *p,
  619.          *q,
  620.          r[30],
  621.          *s[256] = {NULL};
  622.     int i = 1;
  623.  
  624.     while ( (p = argv[i++]) != NULL )
  625.     {
  626.         switch ( *p++ )
  627.             case '-':
  628.                 switch ( *p++ )
  629.                     case '#':
  630.                         DBUG_PUSH(argv[i - 1]);
  631.     }
  632.     new = JCalloc(64, 56);
  633.     new = JRealloc(new, 64);
  634.     JStrCpy(new + 10, "Test string");
  635.     DBUG_PRINT("alloc", ("r is invalid"));
  636.     JStrCpy(r, "Test");
  637.     q = JCalloc(4, 4);
  638.     q[4 * 4] = 3;
  639.  
  640.     DBUG_PRINT("alloc", ("p was never allocated"));
  641.     JFree(p);
  642.  
  643.     i = 0;
  644.  
  645.     DBUG_PRINT("alloc", ("Deplete memory"));
  646.     do
  647.     {
  648.         s[i] = JMalloc(32000);
  649.         i++;
  650.     } while ( s[i - 1] != NULL );
  651.  
  652.     i = 0;
  653.     while ( s[i] != NULL )
  654.     {
  655.         JFree(s[i++]);
  656.     }
  657.  
  658.     DBUG_PRINT("alloc", ("New and q are orphaned blocks"));
  659.     DBUG_PRINT("alloc", ("q has an overrun"));
  660.     JMemcheck(1);
  661.     return(0);
  662. }
  663. #endif
  664.