1: /*_ mem.c */
2: /* Memory management package */
3: /* Written by Walter Bright */
4:
5: #include <stdio.h>
6: #if MSDOS || __OS2__ || __NT__ || _WIN32
7: #include <io.h>
8: #else
9: #define _near
10: #include <sys/time.h>
11: #include <sys/resource.h>
12: #include <unistd.h>
13: #endif
14: #include <stdarg.h>
15: #include <stddef.h>
16:
17: #if __cplusplus
18: #if __DMC__
19: #include <new.h>
20: #else
21: #include <new>
22: #endif
23: #endif
24:
25: #ifndef malloc
26: #if __SC__ || __DMC__
27: #include <malloc.h>
28: #else
29: #include <stdlib.h>
30: #endif
31: #endif
32:
33: #ifndef MEM_H
34: #include "mem.h"
35: #endif
36:
37: #ifndef MEM_NOMEMCOUNT
38: #define MEM_NOMEMCOUNT 0
39: #endif
40:
41: #if !MEM_NONE
42:
43: #ifndef assert
44: #include <assert.h>
45: #endif
46:
47: #ifndef VAX11C
48: #ifdef BSDUNIX
49: #include <strings.h>
50: #else
51: #include <string.h>
52: #endif
53: #else
54: extern char *strcpy(),*memcpy();
55: extern int strlen();
56: #endif /* VAX11C */
57:
58: int mem_inited = 0; /* != 0 if initialized */
59:
60: static int mem_behavior = MEM_ABORTMSG;
61: static int (*fp)(void) = NULL; /* out-of-memory handler */
62: static int mem_count; /* # of allocs that haven't been free'd */
63: static int mem_scount; /* # of sallocs that haven't been free'd */
64:
65: /* Determine where to send error messages */
66: #if _WINDLL
67: void err_message(const char *,...);
68: #define PRINT err_message(
69: #elif MSDOS
70: #define PRINT printf( /* stderr can't be redirected with MS-DOS */
71: #else
72: #define ferr stderr
73: #define PRINT fprintf(ferr,
74: #endif
75:
76: /*******************************/
77:
78: void mem_setexception(enum MEM_E flag,...)
79: { va_list ap;
80: typedef int (*fp_t)(void);
81:
82: mem_behavior = flag;
83: va_start(ap,flag);
84: fp = (mem_behavior == MEM_CALLFP) ? va_arg(ap,fp_t) : 0;
85: va_end(ap);
86: #if MEM_DEBUG
87: assert(0 <= flag && flag <= MEM_RETRY);
88: #endif
89: }
90:
91: /*************************
92: * This is called when we're out of memory.
93: * Returns:
94: * 1: try again to allocate the memory
95: * 0: give up and return NULL
96: */
97:
98: int mem_exception()
99: { int behavior;
100:
101: behavior = mem_behavior;
102: while (1)
103: {
104: switch (behavior)
105: {
106: case MEM_ABORTMSG:
107: #if MSDOS || __OS2__ || __NT__ || _WIN32
108: /* Avoid linking in buffered I/O */
109: { static char msg[] = "Fatal error: out of memory\r\n";
110:
111: write(1,msg,sizeof(msg) - 1);
warning C4996: 'write': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _write. See online help for details.
c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\io.h(318) : see declaration of 'write'
warning C6031: Return value ignored: 'write'
112: }
113: #else
114: PRINT "Fatal error: out of memory\n");
115: #endif
116: /* FALL-THROUGH */
117: case MEM_ABORT:
118: exit(EXIT_FAILURE);
119: /* NOTREACHED */
120: case MEM_CALLFP:
121: assert(fp);
122: behavior = (*fp)();
123: break;
124: case MEM_RETNULL:
125: return 0;
126: case MEM_RETRY:
127: return 1;
128: default:
129: assert(0);
130: }
131: }
132: }
133:
134: /****************************/
135:
136: #if MEM_DEBUG
137:
138: #undef mem_strdup
139:
140: char *mem_strdup(const char *s)
141: {
142: return mem_strdup_debug(s,__FILE__,__LINE__);
143: }
144:
145: char *mem_strdup_debug(const char *s,const char *file,int line)
146: {
147: char *p;
148:
149: p = s
150: ? (char *) mem_malloc_debug((unsigned) strlen(s) + 1,file,line)
151: : NULL;
152: return p ? strcpy(p,s) : p;
153: }
154: #else
155: char *mem_strdup(const char *s)
156: {
157: char *p;
158: int len;
159:
160: if (s)
161: { len = strlen(s) + 1;
162: p = (char *) mem_malloc(len);
163: if (p)
164: return (char *)memcpy(p,s,len);
165: }
166: return NULL;
167: }
168:
169: #endif /* MEM_DEBUG */
170:
171: /************* C++ Implementation ***************/
172:
173: #if __cplusplus && !MEM_NONE
174: extern "C++"
175: {
176:
177: /* Cause initialization and termination functions to be called */
178: #if 0
179: static struct cMemDebug
180: {
181: cMemDebug() { mem_init(); }
182: ~cMemDebug() { mem_term(); }
183: } dummy;
184: #endif
185:
186: int __mem_line;
187: char *__mem_file;
188:
189: /********************
190: */
191:
192: #if __GNUC__
193: int (*_new_handler)(void);
194: #else
195: void (*_new_handler)(void);
196: #endif
197:
198: /*****************************
199: * Replacement for the standard C++ library operator new().
200: */
201:
202: #if !MEM_NONEW
203:
204: #if __GNUC__
205: void * operator new(size_t size)
206: #else
207: #undef new
208: void * __cdecl operator new(size_t size)
209: #endif
210: { void *p;
211:
212: while (1)
213: {
214: if (size == 0)
215: size++;
216: #if MEM_DEBUG
217: assert(mem_inited);
218: p = mem_malloc_debug(size,__mem_file,__mem_line);
219: #else
220: p = mem_malloc((unsigned)size);
221: #endif
222: if (p != NULL || _new_handler == NULL)
223: break;
224: (*_new_handler)();
225: }
226: return p;
227: }
228:
229: #if __GNUC__
230: void * operator new[](size_t size)
231: #else
232: void * __cdecl operator new[](size_t size)
233: #endif
234: { void *p;
235:
236: while (1)
237: {
238: if (size == 0)
239: size++;
240: #if MEM_DEBUG
241: assert(mem_inited);
242: p = mem_malloc_debug(size,__mem_file,__mem_line);
243: #else
244: p = mem_malloc((unsigned)size);
245: #endif
246: if (p != NULL || _new_handler == NULL)
247: break;
248: (*_new_handler)();
249: }
250: return p;
251: }
252:
253: /***********************
254: * Replacement for the standard C++ library operator delete().
255: */
256:
257: #undef delete
258: void __cdecl operator delete(void *p)
259: {
260: #if MEM_DEBUG
261: assert(mem_inited);
262: mem_free_debug(p,__mem_file,__mem_line);
263: #else
264: mem_free(p);
265: #endif
266: }
267:
268: void __cdecl operator delete[](void *p)
269: {
270: #if MEM_DEBUG
271: assert(mem_inited);
272: mem_free_debug(p,__mem_file,__mem_line);
273: #else
274: mem_free(p);
275: #endif
276: }
277: #endif
278: }
279: #endif
280:
281: #if MEM_DEBUG
282:
283: static long mem_maxalloc; /* max # of bytes allocated */
284: static long mem_numalloc; /* current # of bytes allocated */
285:
286: #define BEFOREVAL 0x4F464542 /* value to detect underrun */
287: #define AFTERVAL 0x45544641 /* value to detect overrun */
288:
289: #if SUN || SUN386
290: static long afterval = AFTERVAL; /* so we can do &afterval */
291: #endif
292:
293: /* The following should be selected to give maximum probability that */
294: /* pointers loaded with these values will cause an obvious crash. On */
295: /* Unix machines, a large value will cause a segment fault. */
296: /* MALLOCVAL is the value to set malloc'd data to. */
297:
298: #if MSDOS || __OS2__ || __NT__ || _WIN32
299: #define BADVAL 0xFF
300: #define MALLOCVAL 0xEE
301: #else
302: #define BADVAL 0x7A
303: #define MALLOCVAL 0xEE
304: #endif
305:
306: /* Disable mapping macros */
307: #undef mem_malloc
308: #undef mem_calloc
309: #undef mem_realloc
310: #undef mem_free
311:
312: /* Create a list of all alloc'ed pointers, retaining info about where */
313: /* each alloc came from. This is a real memory and speed hog, but who */
314: /* cares when you've got obscure pointer bugs. */
315:
316: static struct mem_debug
317: {
318: struct mem_debug *Mnext; /* next in list */
319: struct mem_debug *Mprev; /* previous value in list */
320: const char *Mfile; /* filename of where allocated */
321: int Mline; /* line number of where allocated */
322: unsigned Mnbytes; /* size of the allocation */
323: unsigned long Mbeforeval; /* detect underrun of data */
324: char data[1]; /* the data actually allocated */
325: } mem_alloclist =
326: {
327: (struct mem_debug *) NULL,
328: (struct mem_debug *) NULL,
329: NULL,
330: 11111,
331: 0,
332: BEFOREVAL,
333: #if !(linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4)
334: AFTERVAL
335: #endif
336: };
337:
338: /* Determine allocation size of a mem_debug */
339: #define mem_debug_size(n) (sizeof(struct mem_debug) - 1 + (n) + sizeof(AFTERVAL))
340:
341: /* Convert from a void *to a mem_debug struct. */
342: #define mem_ptrtodl(p) ((struct mem_debug *) ((char *)p - offsetof(struct mem_debug,data[0])))
343:
344: /* Convert from a mem_debug struct to a mem_ptr. */
345: #define mem_dltoptr(dl) ((void *) &((dl)->data[0]))
346:
347: /*****************************
348: * Set new value of file,line
349: */
350:
351: void mem_setnewfileline( void *ptr, const char *fil, int lin)
352: {
353: struct mem_debug *dl;
354:
355: dl = mem_ptrtodl(ptr);
356: dl->Mfile = fil;
357: dl->Mline = lin;
358: }
359:
360: /****************************
361: * Print out struct mem_debug.
362: */
363:
364: static void _near mem_printdl(struct mem_debug *dl)
365: {
366: PRINT "alloc'd from file '%s' line %d nbytes %d ptr %p\n",
367: dl->Mfile,dl->Mline,dl->Mnbytes,(long)mem_dltoptr(dl));
368: }
369:
370: /****************************
371: * Print out file and line number.
372: */
373:
374: static void _near mem_fillin(const char *fil, int lin)
375: {
376: PRINT "File '%s' line %d\n",fil,lin);
377: #ifdef ferr
378: fflush(ferr);
379: #endif
380: }
381:
382: /****************************
383: * If MEM_DEBUG is not on for some modules, these routines will get
384: * called.
385: */
386:
387: void *mem_calloc(unsigned u)
388: {
389: return mem_calloc_debug(u,__FILE__,__LINE__);
390: }
391:
392: void *mem_malloc(unsigned u)
393: {
394: return mem_malloc_debug(u,__FILE__,__LINE__);
395: }
396:
397: void *mem_realloc(void *p, unsigned u)
398: {
399: return mem_realloc_debug(p,u,__FILE__,__LINE__);
400: }
401:
402: void mem_free(void *p)
403: {
404: mem_free_debug(p,__FILE__,__LINE__);
405: }
406:
407:
408: /**************************/
409:
410: void mem_freefp(void *p)
411: {
412: mem_free(p);
413: }
414:
415: /***********************
416: * Debug versions of mem_calloc(), mem_free() and mem_realloc().
417: */
418:
419: void *mem_malloc_debug(unsigned n, const char *fil, int lin)
420: { void *p;
421:
422: p = mem_calloc_debug(n,fil,lin);
423: if (p)
424: memset(p,MALLOCVAL,n);
425: return p;
426: }
427:
428: void *mem_calloc_debug(unsigned n, const char *fil, int lin)
429: {
430: struct mem_debug *dl;
431:
432: do
433: dl = (struct mem_debug *) calloc(mem_debug_size(n),1);
434: while (dl == NULL && mem_exception());
435: if (dl == NULL)
436: return NULL;
437: dl->Mfile = fil;
438: dl->Mline = lin;
439: dl->Mnbytes = n;
440: dl->Mbeforeval = BEFOREVAL;
441: #if SUN || SUN386 /* bus error if we store a long at an odd address */
442: memcpy(&(dl->data[n]),&afterval,sizeof(AFTERVAL));
443: #else
444: *(long *) &(dl->data[n]) = AFTERVAL;
445: #endif
446:
447: /* Add dl to start of allocation list */
448: dl->Mnext = mem_alloclist.Mnext;
449: dl->Mprev = &mem_alloclist;
450: mem_alloclist.Mnext = dl;
451: if (dl->Mnext != NULL)
452: dl->Mnext->Mprev = dl;
453:
454: mem_count++;
455: mem_numalloc += n;
456: if (mem_numalloc > mem_maxalloc)
457: mem_maxalloc = mem_numalloc;
458: return mem_dltoptr(dl);
459: }
460:
461: void mem_free_debug(void *ptr, const char *fil, int lin)
462: {
463: struct mem_debug *dl;
464:
465: if (ptr == NULL)
466: return;
467: if (mem_count <= 0)
468: { PRINT "More frees than allocs at ");
469: goto err;
470: }
471: dl = mem_ptrtodl(ptr);
472: if (dl->Mbeforeval != BEFOREVAL)
473: {
474: PRINT "Pointer x%lx underrun\n",(long)ptr);
475: PRINT "'%s'(%d)\n",fil,lin);
476: goto err2;
477: }
478: #if SUN || SUN386 /* Bus error if we read a long from an odd address */
479: if (memcmp(&dl->data[dl->Mnbytes],&afterval,sizeof(AFTERVAL)) != 0)
480: #else
481: if (*(long *) &dl->data[dl->Mnbytes] != AFTERVAL)
482: #endif
483: {
484: PRINT "Pointer x%lx overrun\n",(long)ptr);
485: goto err2;
486: }
487: mem_numalloc -= dl->Mnbytes;
488: if (mem_numalloc < 0)
489: { PRINT "error: mem_numalloc = %ld, dl->Mnbytes = %d\n",
490: mem_numalloc,dl->Mnbytes);
491: goto err2;
492: }
493:
494: /* Remove dl from linked list */
495: if (dl->Mprev)
496: dl->Mprev->Mnext = dl->Mnext;
497: if (dl->Mnext)
498: dl->Mnext->Mprev = dl->Mprev;
499:
500: /* Stomp on the freed storage to help detect references */
501: /* after the storage was freed. */
502: memset((void *) dl,BADVAL,sizeof(*dl) + dl->Mnbytes);
503: mem_count--;
504:
505: free((void *) dl);
506: return;
507:
508: err2:
509: mem_printdl(dl);
510: err:
511: PRINT "free'd from ");
512: mem_fillin(fil,lin);
513: assert(0);
514: /* NOTREACHED */
515: }
516:
517: /*******************
518: * Debug version of mem_realloc().
519: */
520:
521: void *mem_realloc_debug(void *oldp, unsigned n, const char *fil, int lin)
522: { void *p;
523: struct mem_debug *dl;
524:
525: if (n == 0)
526: { mem_free_debug(oldp,fil,lin);
527: p = NULL;
528: }
529: else if (oldp == NULL)
530: p = mem_malloc_debug(n,fil,lin);
531: else
532: {
533: p = mem_malloc_debug(n,fil,lin);
534: if (p != NULL)
535: {
536: dl = mem_ptrtodl(oldp);
537: if (dl->Mnbytes < n)
538: n = dl->Mnbytes;
539: memcpy(p,oldp,n);
540: mem_free_debug(oldp,fil,lin);
541: }
542: }
543: return p;
544: }
545:
546: /***************************/
547:
548: static void mem_checkdl(struct mem_debug *dl)
549: { void *p;
550: #if (__SC__ || __DMC__) && !_WIN32
551: unsigned u;
552:
553: /* Take advantage of fact that SC's allocator stores the size of the
554: * alloc in the unsigned immediately preceding the allocation.
555: */
556: u = ((unsigned *)dl)[-1] - sizeof(unsigned);
557: assert((u & (sizeof(unsigned) - 1)) == 0 && u >= mem_debug_size(dl->Mnbytes));
558: #endif
559: p = mem_dltoptr(dl);
560: if (dl->Mbeforeval != BEFOREVAL)
561: {
562: PRINT "Pointer x%lx underrun\n",(long)p);
563: goto err2;
564: }
565: #if SUN || SUN386 /* Bus error if we read a long from an odd address */
566: if (memcmp(&dl->data[dl->Mnbytes],&afterval,sizeof(AFTERVAL)) != 0)
567: #else
568: if (*(long *) &dl->data[dl->Mnbytes] != AFTERVAL)
569: #endif
570: {
571: PRINT "Pointer x%lx overrun\n",(long)p);
572: goto err2;
573: }
574: return;
575:
576: err2:
577: mem_printdl(dl);
578: assert(0);
579: }
580:
581: /***************************/
582:
583: void mem_check()
584: { register struct mem_debug *dl;
585:
586: #if (__SC__ || _MSC_VER) && !defined(malloc)
587: int i;
588:
589: i = _heapset(0xF4);
590: assert(i == _HEAPOK);
591: #endif
592: for (dl = mem_alloclist.Mnext; dl != NULL; dl = dl->Mnext)
593: mem_checkdl(dl);
594: }
595:
596: /***************************/
597:
598: void mem_checkptr(void *p)
599: { register struct mem_debug *dl;
600:
601: for (dl = mem_alloclist.Mnext; dl != NULL; dl = dl->Mnext)
602: {
603: if (p >= (void *) &(dl->data[0]) &&
604: p < (void *)((char *)dl + sizeof(struct mem_debug)-1 + dl->Mnbytes))
605: goto L1;
606: }
607: assert(0);
608:
609: L1:
610: mem_checkdl(dl);
611: }
612:
613: #else
614:
615: /***************************/
616:
617: void *mem_malloc(unsigned numbytes)
618: { void *p;
619:
620: if (numbytes == 0)
621: return NULL;
622: while (1)
623: {
624: p = malloc(numbytes);
625: if (p == NULL)
626: { if (mem_exception())
627: continue;
628: }
629: #if !MEM_NOMEMCOUNT
630: else
631: mem_count++;
632: #endif
633: break;
634: }
635: /*printf("malloc(%d) = x%lx, mem_count = %d\n",numbytes,p,mem_count);*/
636: return p;
637: }
638:
639: /***************************/
640:
641: void *mem_calloc(unsigned numbytes)
642: { void *p;
643:
644: if (numbytes == 0)
645: return NULL;
646: while (1)
647: {
648: p = calloc(numbytes,1);
649: if (p == NULL)
650: { if (mem_exception())
651: continue;
652: }
653: #if !MEM_NOMEMCOUNT
654: else
655: mem_count++;
656: #endif
657: break;
658: }
659: /*printf("calloc(%d) = x%lx, mem_count = %d\n",numbytes,p,mem_count);*/
660: return p;
661: }
662:
663: /***************************/
664:
665: void *mem_realloc(void *oldmem_ptr,unsigned newnumbytes)
666: { void *p;
667:
668: if (oldmem_ptr == NULL)
669: p = mem_malloc(newnumbytes);
670: else if (newnumbytes == 0)
671: { mem_free(oldmem_ptr);
672: p = NULL;
673: }
674: else
675: {
676: do
677: p = realloc(oldmem_ptr,newnumbytes);
warning C6001: Using uninitialized memory 'oldmem_ptr': Lines: 666, 668, 670, 677
678: while (p == NULL && mem_exception());
679: }
680: /*printf("realloc(x%lx,%d) = x%lx, mem_count = %d\n",oldmem_ptr,newnumbytes,p,mem_count);*/
681: return p;
682: }
683:
684: /***************************/
685:
686: void mem_free(void *ptr)
687: {
688: /*printf("free(x%lx) mem_count=%d\n",ptr,mem_count);*/
689: if (ptr != NULL)
690: {
691: #if !MEM_NOMEMCOUNT
692: assert(mem_count != 0);
693: mem_count--;
694: #endif
695: free(ptr);
696: }
697: }
698:
699: /***************************/
700: /* This is our low-rent fast storage allocator */
701:
702: static char *heap;
703: static size_t heapleft;
704:
705: /***************************/
706:
707: #if 0 && __SC__ && __INTSIZE == 4 && __I86__ && !_DEBUG_TRACE && _WIN32 && (SCC || SCPP || JAVA)
708:
709: __declspec(naked) void *mem_fmalloc(unsigned numbytes)
710: {
711: __asm
712: {
713: mov EDX,4[ESP]
714: mov EAX,heap
715: add EDX,3
716: mov ECX,heapleft
717: and EDX,~3
718: je L5A
719: cmp EDX,ECX
720: ja L2D
721: sub ECX,EDX
722: add EDX,EAX
723: mov heapleft,ECX
724: mov heap,EDX
725: ret 4
726:
727: L2D: push EBX
728: mov EBX,EDX
729: // add EDX,03FFFh
730: // and EDX,~03FFFh
731: add EDX,03C00h
732: mov heapleft,EDX
733: L3D: push heapleft
734: call mem_malloc
735: test EAX,EAX
736: mov heap,EAX
737: jne L18
738: call mem_exception
739: test EAX,EAX
740: jne L3D
741: pop EBX
742: L5A: xor EAX,EAX
743: ret 4
744:
745: L18: add heap,EBX
746: sub heapleft,EBX
747: pop EBX
748: ret 4
749: }
750: }
751:
752: #else
753:
754: void *mem_fmalloc(unsigned numbytes)
755: { void *p;
756:
757: //printf("fmalloc(%d)\n",numbytes);
758: if (sizeof(size_t) == 2)
759: numbytes = (numbytes + 1) & ~1; /* word align */
760: else
761: numbytes = (numbytes + 3) & ~3; /* dword align */
762:
763: /* This ugly flow-of-control is so that the most common case
764: drops straight through.
765: */
766:
767: if (!numbytes)
768: return NULL;
769:
770: if (numbytes <= heapleft)
771: {
772: L2:
773: p = (void *)heap;
774: heap += numbytes;
775: heapleft -= numbytes;
776: return p;
777: }
778:
779: #if 1
780: heapleft = numbytes + 0x3C00;
781: if (heapleft >= 16372)
782: heapleft = numbytes;
783: #elif _WIN32
784: heapleft = (numbytes + 0x3FFF) & ~0x3FFF; /* round to next boundary */
785: #else
786: heapleft = 0x3F00;
787: assert(numbytes <= heapleft);
788: #endif
789: L1:
790: heap = (char *)malloc(heapleft);
791: if (!heap)
792: { if (mem_exception())
793: goto L1;
794: return NULL;
795: }
796: goto L2;
797: }
798:
799: #endif
800:
801: /***************************/
802:
803: void *mem_fcalloc(unsigned numbytes)
804: { void *p;
805:
806: p = mem_fmalloc(numbytes);
807: return p ? memset(p,0,numbytes) : p;
808: }
809:
810: /***************************/
811:
812: char *mem_fstrdup(const char *s)
813: {
814: char *p;
815: int len;
816:
817: if (s)
818: { len = strlen(s) + 1;
819: p = (char *) mem_fmalloc(len);
820: if (p)
821: return (char *)memcpy(p,s,len);
822: }
823: return NULL;
824: }
825:
826: #endif
827:
828: /***************************/
829:
830: void mem_init()
831: {
832: if (mem_inited == 0)
833: { mem_count = 0;
834: mem_scount = 0;
835: fp = NULL;
836: mem_behavior = MEM_ABORTMSG;
837: #if MEM_DEBUG
838: mem_numalloc = 0;
839: mem_maxalloc = 0;
840: mem_alloclist.Mnext = NULL;
841: #if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4
842: *(long *) &(mem_alloclist.data[0]) = AFTERVAL;
843: #endif
844: #endif
845: #if (__ZTC__ || __SC__ || __DMC__) && !defined(malloc)
846: free(malloc(1)); /* initialize storage allocator */
847: #endif
848: #if MEM_DEBUG && (__SC__ || _MSC_VER) && !defined(malloc)
849: { int i;
850:
851: i = _heapset(0xF4);
852: assert(i == _HEAPOK);
853: }
854: #endif
855: }
856: mem_inited++;
857: }
858:
859: /***************************/
860:
861: void mem_term()
862: {
863: if (mem_inited)
864: {
865: #if MEM_DEBUG
866: struct mem_debug *dl;
867:
868: for (dl = mem_alloclist.Mnext; dl; dl = dl->Mnext)
869: { PRINT "Unfreed pointer: ");
870: mem_printdl(dl);
871: }
872: #if 0
873: PRINT "Max amount ever allocated == %ld bytes\n",
874: mem_maxalloc);
875: #endif
876: #if (__SC__ || _MSC_VER) && !defined(malloc)
877: { int i;
878:
879: i = _heapset(0xF4);
880: assert(i == _HEAPOK);
881: }
882: #endif
883: #else
884: if (mem_count)
885: PRINT "%d unfreed items\n",mem_count);
886: if (mem_scount)
887: PRINT "%d unfreed s items\n",mem_scount);
888: #endif /* MEM_DEBUG */
889: assert(mem_count == 0 && mem_scount == 0);
890: }
891: mem_inited = 0;
892: }
893:
894: #endif /* !MEM_NONE */
895: