source: trunk/third/sendmail/libsm/heap.c @ 19204

Revision 19204, 17.3 KB checked in by zacheiss, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r19203, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
3 *      All rights reserved.
4 *
5 * By using this file, you agree to the terms and conditions set
6 * forth in the LICENSE file which can be found at the top level of
7 * the sendmail distribution.
8 */
9
10#include <sm/gen.h>
11SM_RCSID("@(#)$Id: heap.c,v 1.1.1.1 2003-04-08 15:06:04 zacheiss Exp $")
12
13/*
14**  debugging memory allocation package
15**  See heap.html for documentation.
16*/
17
18#include <string.h>
19
20#include <sm/assert.h>
21#include <sm/debug.h>
22#include <sm/exc.h>
23#include <sm/heap.h>
24#include <sm/io.h>
25#include <sm/signal.h>
26#include <sm/xtrap.h>
27
28/* undef all macro versions of the "functions" so they can be specified here */
29#undef sm_malloc
30#undef sm_malloc_x
31#undef sm_malloc_tagged
32#undef sm_malloc_tagged_x
33#undef sm_free
34#undef sm_free_tagged
35#undef sm_realloc
36#if SM_HEAP_CHECK
37# undef sm_heap_register
38# undef sm_heap_checkptr
39# undef sm_heap_report
40#endif /* SM_HEAP_CHECK */
41
42#if SM_HEAP_CHECK
43SM_DEBUG_T SmHeapCheck = SM_DEBUG_INITIALIZER("sm_check_heap",
44    "@(#)$Debug: sm_check_heap - check sm_malloc, sm_realloc, sm_free calls $");
45# define HEAP_CHECK sm_debug_active(&SmHeapCheck, 1)
46#endif /* SM_HEAP_CHECK */
47
48const SM_EXC_TYPE_T SmHeapOutOfMemoryType =
49{
50        SmExcTypeMagic,
51        "F:sm.heap",
52        "",
53        sm_etype_printf,
54        "out of memory",
55};
56
57SM_EXC_T SmHeapOutOfMemory = SM_EXC_INITIALIZER(&SmHeapOutOfMemoryType, NULL);
58
59
60/*
61**  The behaviour of malloc with size==0 is platform dependent (it
62**  says so in the C standard): it can return NULL or non-NULL.  We
63**  don't want sm_malloc_x(0) to raise an exception on some platforms
64**  but not others, so this case requires special handling.  We've got
65**  two choices: "size = 1" or "return NULL". We use the former in the
66**  following.
67**      If we had something like autoconf we could figure out the
68**      behaviour of the platform and either use this hack or just
69**      use size.
70*/
71
72#define MALLOC_SIZE(size)       ((size) == 0 ? 1 : (size))
73
74/*
75**  SM_MALLOC_X -- wrapper around malloc(), raises an exception on error.
76**
77**      Parameters:
78**              size -- size of requested memory.
79**
80**      Returns:
81**              Pointer to memory region.
82**
83**      Note:
84**              sm_malloc_x only gets called from source files in which heap
85**              debugging is disabled at compile time.  Otherwise, a call to
86**              sm_malloc_x is macro expanded to a call to sm_malloc_tagged_x.
87**
88**      Exceptions:
89**              F:sm_heap -- out of memory
90*/
91
92void *
93sm_malloc_x(size)
94        size_t size;
95{
96        void *ptr;
97
98        ENTER_CRITICAL();
99        ptr = malloc(MALLOC_SIZE(size));
100        LEAVE_CRITICAL();
101        if (ptr == NULL)
102                sm_exc_raise_x(&SmHeapOutOfMemory);
103        return ptr;
104}
105
106#if !SM_HEAP_CHECK
107
108/*
109**  SM_MALLOC -- wrapper around malloc()
110**
111**      Parameters:
112**              size -- size of requested memory.
113**
114**      Returns:
115**              Pointer to memory region.
116*/
117
118void *
119sm_malloc(size)
120        size_t size;
121{
122        void *ptr;
123
124        ENTER_CRITICAL();
125        ptr = malloc(MALLOC_SIZE(size));
126        LEAVE_CRITICAL();
127        return ptr;
128}
129
130/*
131**  SM_REALLOC -- wrapper for realloc()
132**
133**      Parameters:
134**              ptr -- pointer to old memory area.
135**              size -- size of requested memory.
136**
137**      Returns:
138**              Pointer to new memory area, NULL on failure.
139*/
140
141void *
142sm_realloc(ptr, size)
143        void *ptr;
144        size_t size;
145{
146        void *newptr;
147
148        ENTER_CRITICAL();
149        newptr = realloc(ptr, MALLOC_SIZE(size));
150        LEAVE_CRITICAL();
151        return newptr;
152}
153
154/*
155**  SM_REALLOC_X -- wrapper for realloc()
156**
157**      Parameters:
158**              ptr -- pointer to old memory area.
159**              size -- size of requested memory.
160**
161**      Returns:
162**              Pointer to new memory area.
163**
164**      Exceptions:
165**              F:sm_heap -- out of memory
166*/
167
168void *
169sm_realloc_x(ptr, size)
170        void *ptr;
171        size_t size;
172{
173        void *newptr;
174
175        ENTER_CRITICAL();
176        newptr = realloc(ptr, MALLOC_SIZE(size));
177        LEAVE_CRITICAL();
178        if (newptr == NULL)
179                sm_exc_raise_x(&SmHeapOutOfMemory);
180        return newptr;
181}
182/*
183**  SM_FREE -- wrapper around free()
184**
185**      Parameters:
186**              ptr -- pointer to memory region.
187**
188**      Returns:
189**              none.
190*/
191
192void
193sm_free(ptr)
194        void *ptr;
195{
196        if (ptr == NULL)
197                return;
198        ENTER_CRITICAL();
199        free(ptr);
200        LEAVE_CRITICAL();
201        return;
202}
203
204#else /* !SM_HEAP_CHECK */
205
206/*
207**  Each allocated block is assigned a "group number".
208**  By default, all blocks are assigned to group #1.
209**  By convention, group #0 is for memory that is never freed.
210**  You can use group numbers any way you want, in order to help make
211**  sense of sm_heap_report output.
212*/
213
214int SmHeapGroup = 1;
215int SmHeapMaxGroup = 1;
216
217/*
218**  Total number of bytes allocated.
219**  This is only maintained if the sm_check_heap debug category is active.
220*/
221
222size_t SmHeapTotal = 0;
223
224/*
225**  High water mark: the most that SmHeapTotal has ever been.
226*/
227
228size_t SmHeapMaxTotal = 0;
229
230/*
231**  Maximum number of bytes that may be allocated at any one time.
232**  0 means no limit.
233**  This is only honoured if sm_check_heap is active.
234*/
235
236SM_DEBUG_T SmHeapLimit = SM_DEBUG_INITIALIZER("sm_heap_limit",
237    "@(#)$Debug: sm_heap_limit - max # of bytes permitted in heap $");
238
239/*
240**  This is the data structure that keeps track of all currently
241**  allocated blocks of memory known to the heap package.
242*/
243
244typedef struct sm_heap_item SM_HEAP_ITEM_T;
245struct sm_heap_item
246{
247        void            *hi_ptr;
248        size_t          hi_size;
249        char            *hi_tag;
250        int             hi_num;
251        int             hi_group;
252        SM_HEAP_ITEM_T  *hi_next;
253};
254
255#define SM_HEAP_TABLE_SIZE      256
256static SM_HEAP_ITEM_T *SmHeapTable[SM_HEAP_TABLE_SIZE];
257
258/*
259**  This is a randomly generated table
260**  which contains exactly one occurrence
261**  of each of the numbers between 0 and 255.
262**  It is used by ptrhash.
263*/
264
265static unsigned char hashtab[SM_HEAP_TABLE_SIZE] =
266{
267        161, 71, 77,187, 15,229,  9,176,221,119,239, 21, 85,138,203, 86,
268        102, 65, 80,199,235, 32,140, 96,224, 78,126,127,144,  0, 11,179,
269         64, 30,120, 23,225,226, 33, 50,205,167,130,240,174, 99,206, 73,
270        231,210,189,162, 48, 93,246, 54,213,141,135, 39, 41,192,236,193,
271        157, 88, 95,104,188, 63,133,177,234,110,158,214,238,131,233, 91,
272        125, 82, 94, 79, 66, 92,151, 45,252, 98, 26,183,  7,191,171,106,
273        145,154,251,100,113,  5, 74, 62, 76,124, 14,217,200, 75,115,190,
274        103, 28,198,196,169,219, 37,118,150, 18,152,175, 49,136,  6,142,
275         89, 19,243,254, 47,137, 24,166,180, 10, 40,186,202, 46,184, 67,
276        148,108,181, 81, 25,241, 13,139, 58, 38, 84,253,201, 12,116, 17,
277        195, 22,112, 69,255, 43,147,222,111, 56,194,216,149,244, 42,173,
278        232,220,249,105,207, 51,197,242, 72,211,208, 59,122,230,237,170,
279        165, 44, 68,123,129,245,143,101,  8,209,215,247,185, 57,218, 53,
280        114,121,  3,128,  4,204,212,146,  2,155, 83,250, 87, 29, 31,159,
281         60, 27,107,156,227,182,  1, 61, 36,160,109, 97, 90, 20,168,132,
282        223,248, 70,164, 55,172, 34, 52,163,117, 35,153,134, 16,178,228
283};
284
285/*
286**  PTRHASH -- hash a pointer value
287**
288**      Parameters:
289**              p -- pointer.
290**
291**      Returns:
292**              hash value.
293**
294**  ptrhash hashes a pointer value to a uniformly distributed random
295**  number between 0 and 255.
296**
297**  This hash algorithm is based on Peter K. Pearson,
298**  "Fast Hashing of Variable-Length Text Strings",
299**  in Communications of the ACM, June 1990, vol 33 no 6.
300*/
301
302static int
303ptrhash(p)
304        void *p;
305{
306        int h;
307
308        if (sizeof(void*) == 4 && sizeof(unsigned long) == 4)
309        {
310                unsigned long n = (unsigned long)p;
311
312                h = hashtab[n & 0xFF];
313                h = hashtab[h ^ ((n >> 8) & 0xFF)];
314                h = hashtab[h ^ ((n >> 16) & 0xFF)];
315                h = hashtab[h ^ ((n >> 24) & 0xFF)];
316        }
317# if 0
318        else if (sizeof(void*) == 8 && sizeof(unsigned long) == 8)
319        {
320                unsigned long n = (unsigned long)p;
321
322                h = hashtab[n & 0xFF];
323                h = hashtab[h ^ ((n >> 8) & 0xFF)];
324                h = hashtab[h ^ ((n >> 16) & 0xFF)];
325                h = hashtab[h ^ ((n >> 24) & 0xFF)];
326                h = hashtab[h ^ ((n >> 32) & 0xFF)];
327                h = hashtab[h ^ ((n >> 40) & 0xFF)];
328                h = hashtab[h ^ ((n >> 48) & 0xFF)];
329                h = hashtab[h ^ ((n >> 56) & 0xFF)];
330        }
331# endif /* 0 */
332        else
333        {
334                unsigned char *cp = (unsigned char *)&p;
335                int i;
336
337                h = 0;
338                for (i = 0; i < sizeof(void*); ++i)
339                        h = hashtab[h ^ cp[i]];
340        }
341        return h;
342}
343
344/*
345**  SM_MALLOC_TAGGED -- wrapper around malloc(), debugging version.
346**
347**      Parameters:
348**              size -- size of requested memory.
349**              tag -- tag for debugging.
350**              num -- additional value for debugging.
351**              group -- heap group for debugging.
352**
353**      Returns:
354**              Pointer to memory region.
355*/
356
357void *
358sm_malloc_tagged(size, tag, num, group)
359        size_t size;
360        char *tag;
361        int num;
362        int group;
363{
364        void *ptr;
365
366        if (!HEAP_CHECK)
367        {
368                ENTER_CRITICAL();
369                ptr = malloc(MALLOC_SIZE(size));
370                LEAVE_CRITICAL();
371                return ptr;
372        }
373
374        if (sm_xtrap_check())
375                return NULL;
376        if (sm_debug_active(&SmHeapLimit, 1)
377            && sm_debug_level(&SmHeapLimit) < SmHeapTotal + size)
378                return NULL;
379        ENTER_CRITICAL();
380        ptr = malloc(MALLOC_SIZE(size));
381        LEAVE_CRITICAL();
382        if (ptr != NULL && !sm_heap_register(ptr, size, tag, num, group))
383        {
384                ENTER_CRITICAL();
385                free(ptr);
386                LEAVE_CRITICAL();
387                ptr = NULL;
388        }
389        SmHeapTotal += size;
390        if (SmHeapTotal > SmHeapMaxTotal)
391                SmHeapMaxTotal = SmHeapTotal;
392        return ptr;
393}
394
395/*
396**  SM_MALLOC_TAGGED_X -- wrapper around malloc(), debugging version.
397**
398**      Parameters:
399**              size -- size of requested memory.
400**              tag -- tag for debugging.
401**              num -- additional value for debugging.
402**              group -- heap group for debugging.
403**
404**      Returns:
405**              Pointer to memory region.
406**
407**      Exceptions:
408**              F:sm_heap -- out of memory
409*/
410
411void *
412sm_malloc_tagged_x(size, tag, num, group)
413        size_t size;
414        char *tag;
415        int num;
416        int group;
417{
418        void *ptr;
419
420        if (!HEAP_CHECK)
421        {
422                ENTER_CRITICAL();
423                ptr = malloc(MALLOC_SIZE(size));
424                LEAVE_CRITICAL();
425                if (ptr == NULL)
426                        sm_exc_raise_x(&SmHeapOutOfMemory);
427                return ptr;
428        }
429
430        sm_xtrap_raise_x(&SmHeapOutOfMemory);
431        if (sm_debug_active(&SmHeapLimit, 1)
432            && sm_debug_level(&SmHeapLimit) < SmHeapTotal + size)
433        {
434                sm_exc_raise_x(&SmHeapOutOfMemory);
435        }
436        ENTER_CRITICAL();
437        ptr = malloc(MALLOC_SIZE(size));
438        LEAVE_CRITICAL();
439        if (ptr != NULL && !sm_heap_register(ptr, size, tag, num, group))
440        {
441                ENTER_CRITICAL();
442                free(ptr);
443                LEAVE_CRITICAL();
444                ptr = NULL;
445        }
446        if (ptr == NULL)
447                sm_exc_raise_x(&SmHeapOutOfMemory);
448        SmHeapTotal += size;
449        if (SmHeapTotal > SmHeapMaxTotal)
450                SmHeapMaxTotal = SmHeapTotal;
451        return ptr;
452}
453
454/*
455**  SM_HEAP_REGISTER -- register a pointer into the heap for debugging.
456**
457**      Parameters:
458**              ptr -- pointer to register.
459**              size -- size of requested memory.
460**              tag -- tag for debugging.
461**              num -- additional value for debugging.
462**              group -- heap group for debugging.
463**
464**      Returns:
465**              true iff successfully registered (not yet in table).
466*/
467
468bool
469sm_heap_register(ptr, size, tag, num, group)
470        void *ptr;
471        size_t size;
472        char *tag;
473        int num;
474        int group;
475{
476        int i;
477        SM_HEAP_ITEM_T *hi;
478
479        if (!HEAP_CHECK)
480                return true;
481        SM_REQUIRE(ptr != NULL);
482        i = ptrhash(ptr);
483# if SM_CHECK_REQUIRE
484
485        /*
486        ** We require that ptr is not already in SmHeapTable.
487        */
488
489        for (hi = SmHeapTable[i]; hi != NULL; hi = hi->hi_next)
490        {
491                if (hi->hi_ptr == ptr)
492                        sm_abort("sm_heap_register: ptr %p is already registered (%s:%d)",
493                                 ptr, hi->hi_tag, hi->hi_num);
494        }
495# endif /* SM_CHECK_REQUIRE */
496        ENTER_CRITICAL();
497        hi = (SM_HEAP_ITEM_T *) malloc(sizeof(SM_HEAP_ITEM_T));
498        LEAVE_CRITICAL();
499        if (hi == NULL)
500                return false;
501        hi->hi_ptr = ptr;
502        hi->hi_size = size;
503        hi->hi_tag = tag;
504        hi->hi_num = num;
505        hi->hi_group = group;
506        hi->hi_next = SmHeapTable[i];
507        SmHeapTable[i] = hi;
508        return true;
509}
510/*
511**  SM_REALLOC -- wrapper for realloc(), debugging version.
512**
513**      Parameters:
514**              ptr -- pointer to old memory area.
515**              size -- size of requested memory.
516**
517**      Returns:
518**              Pointer to new memory area, NULL on failure.
519*/
520
521void *
522sm_realloc(ptr, size)
523        void *ptr;
524        size_t size;
525{
526        void *newptr;
527        SM_HEAP_ITEM_T *hi, **hp;
528
529        if (!HEAP_CHECK)
530        {
531                ENTER_CRITICAL();
532                newptr = realloc(ptr, MALLOC_SIZE(size));
533                LEAVE_CRITICAL();
534                return newptr;
535        }
536
537        if (ptr == NULL)
538                return sm_malloc_tagged(size, "realloc", 0, SmHeapGroup);
539
540        for (hp = &SmHeapTable[ptrhash(ptr)]; *hp != NULL; hp = &(**hp).hi_next)
541        {
542                if ((**hp).hi_ptr == ptr)
543                {
544                        if (sm_xtrap_check())
545                                return NULL;
546                        hi = *hp;
547                        if (sm_debug_active(&SmHeapLimit, 1)
548                            && sm_debug_level(&SmHeapLimit)
549                               < SmHeapTotal - hi->hi_size + size)
550                        {
551                                return NULL;
552                        }
553                        ENTER_CRITICAL();
554                        newptr = realloc(ptr, MALLOC_SIZE(size));
555                        LEAVE_CRITICAL();
556                        if (newptr == NULL)
557                                return NULL;
558                        SmHeapTotal = SmHeapTotal - hi->hi_size + size;
559                        if (SmHeapTotal > SmHeapMaxTotal)
560                                SmHeapMaxTotal = SmHeapTotal;
561                        *hp = hi->hi_next;
562                        hi->hi_ptr = newptr;
563                        hi->hi_size = size;
564                        hp = &SmHeapTable[ptrhash(newptr)];
565                        hi->hi_next = *hp;
566                        *hp = hi;
567                        return newptr;
568                }
569        }
570        sm_abort("sm_realloc: bad argument (%p)", ptr);
571        /* NOTREACHED */
572        return NULL;    /* keep Irix compiler happy */
573}
574
575/*
576**  SM_REALLOC_X -- wrapper for realloc(), debugging version.
577**
578**      Parameters:
579**              ptr -- pointer to old memory area.
580**              size -- size of requested memory.
581**
582**      Returns:
583**              Pointer to new memory area.
584**
585**      Exceptions:
586**              F:sm_heap -- out of memory
587*/
588
589void *
590sm_realloc_x(ptr, size)
591        void *ptr;
592        size_t size;
593{
594        void *newptr;
595        SM_HEAP_ITEM_T *hi, **hp;
596
597        if (!HEAP_CHECK)
598        {
599                ENTER_CRITICAL();
600                newptr = realloc(ptr, MALLOC_SIZE(size));
601                LEAVE_CRITICAL();
602                if (newptr == NULL)
603                        sm_exc_raise_x(&SmHeapOutOfMemory);
604                return newptr;
605        }
606
607        if (ptr == NULL)
608                return sm_malloc_tagged_x(size, "realloc", 0, SmHeapGroup);
609
610        for (hp = &SmHeapTable[ptrhash(ptr)]; *hp != NULL; hp = &(**hp).hi_next)
611        {
612                if ((**hp).hi_ptr == ptr)
613                {
614                        sm_xtrap_raise_x(&SmHeapOutOfMemory);
615                        hi = *hp;
616                        if (sm_debug_active(&SmHeapLimit, 1)
617                            && sm_debug_level(&SmHeapLimit)
618                               < SmHeapTotal - hi->hi_size + size)
619                        {
620                                sm_exc_raise_x(&SmHeapOutOfMemory);
621                        }
622                        ENTER_CRITICAL();
623                        newptr = realloc(ptr, MALLOC_SIZE(size));
624                        LEAVE_CRITICAL();
625                        if (newptr == NULL)
626                                sm_exc_raise_x(&SmHeapOutOfMemory);
627                        SmHeapTotal = SmHeapTotal - hi->hi_size + size;
628                        if (SmHeapTotal > SmHeapMaxTotal)
629                                SmHeapMaxTotal = SmHeapTotal;
630                        *hp = hi->hi_next;
631                        hi->hi_ptr = newptr;
632                        hi->hi_size = size;
633                        hp = &SmHeapTable[ptrhash(newptr)];
634                        hi->hi_next = *hp;
635                        *hp = hi;
636                        return newptr;
637                }
638        }
639        sm_abort("sm_realloc_x: bad argument (%p)", ptr);
640        /* NOTREACHED */
641        return NULL;    /* keep Irix compiler happy */
642}
643
644/*
645**  SM_FREE_TAGGED -- wrapper around free(), debugging version.
646**
647**      Parameters:
648**              ptr -- pointer to memory region.
649**              tag -- tag for debugging.
650**              num -- additional value for debugging.
651**
652**      Returns:
653**              none.
654*/
655
656void
657sm_free_tagged(ptr, tag, num)
658        void *ptr;
659        char *tag;
660        int num;
661{
662        SM_HEAP_ITEM_T **hp;
663
664        if (ptr == NULL)
665                return;
666        if (!HEAP_CHECK)
667        {
668                ENTER_CRITICAL();
669                free(ptr);
670                LEAVE_CRITICAL();
671                return;
672        }
673        for (hp = &SmHeapTable[ptrhash(ptr)]; *hp != NULL; hp = &(**hp).hi_next)
674        {
675                if ((**hp).hi_ptr == ptr)
676                {
677                        SM_HEAP_ITEM_T *hi = *hp;
678
679                        *hp = hi->hi_next;
680
681                        /*
682                        **  Fill the block with zeros before freeing.
683                        **  This is intended to catch problems with
684                        **  dangling pointers.  The block is filled with
685                        **  zeros, not with some non-zero value, because
686                        **  it is common practice in some C code to store
687                        **  a zero in a structure member before freeing the
688                        **  structure, as a defense against dangling pointers.
689                        */
690
691                        (void) memset(ptr, 0, hi->hi_size);
692                        SmHeapTotal -= hi->hi_size;
693                        ENTER_CRITICAL();
694                        free(ptr);
695                        free(hi);
696                        LEAVE_CRITICAL();
697                        return;
698                }
699        }
700        sm_abort("sm_free: bad argument (%p) (%s:%d)", ptr, tag, num);
701}
702
703/*
704**  SM_HEAP_CHECKPTR_TAGGED -- check whether ptr is a valid argument to sm_free
705**
706**      Parameters:
707**              ptr -- pointer to memory region.
708**              tag -- tag for debugging.
709**              num -- additional value for debugging.
710**
711**      Returns:
712**              none.
713**
714**      Side Effects:
715**              aborts if check fails.
716*/
717
718void
719sm_heap_checkptr_tagged(ptr, tag, num)
720        void *ptr;
721        char *tag;
722        int num;
723{
724        SM_HEAP_ITEM_T *hp;
725
726        if (!HEAP_CHECK)
727                return;
728        if (ptr == NULL)
729                return;
730        for (hp = SmHeapTable[ptrhash(ptr)]; hp != NULL; hp = hp->hi_next)
731        {
732                if (hp->hi_ptr == ptr)
733                        return;
734        }
735        sm_abort("sm_heap_checkptr(%p): bad ptr (%s:%d)", ptr, tag, num);
736}
737
738/*
739**  SM_HEAP_REPORT -- output "map" of used heap.
740**
741**      Parameters:
742**              stream -- the file pointer to write to.
743**              verbosity -- how much info?
744**
745**      Returns:
746**              none.
747*/
748
749void
750sm_heap_report(stream, verbosity)
751        SM_FILE_T *stream;
752        int verbosity;
753{
754        int i;
755        unsigned long group0total, group1total, otherstotal, grandtotal;
756
757        if (!HEAP_CHECK || verbosity <= 0)
758                return;
759        group0total = group1total = otherstotal = grandtotal = 0;
760        for (i = 0; i < sizeof(SmHeapTable) / sizeof(SmHeapTable[0]); ++i)
761        {
762                SM_HEAP_ITEM_T *hi = SmHeapTable[i];
763
764                while (hi != NULL)
765                {
766                        if (verbosity > 2
767                            || (verbosity > 1 && hi->hi_group != 0))
768                        {
769                                sm_io_fprintf(stream, SM_TIME_DEFAULT,
770                                        "%4d %*lx %7lu bytes",
771                                        hi->hi_group,
772                                        (int) sizeof(void *) * 2,
773                                        (long)hi->hi_ptr,
774                                        (unsigned long)hi->hi_size);
775                                if (hi->hi_tag != NULL)
776                                {
777                                        sm_io_fprintf(stream, SM_TIME_DEFAULT,
778                                                "  %s",
779                                                hi->hi_tag);
780                                        if (hi->hi_num)
781                                        {
782                                                sm_io_fprintf(stream,
783                                                        SM_TIME_DEFAULT,
784                                                        ":%d",
785                                                        hi->hi_num);
786                                        }
787                                }
788                                sm_io_fprintf(stream, SM_TIME_DEFAULT, "\n");
789                        }
790                        switch (hi->hi_group)
791                        {
792                          case 0:
793                                group0total += hi->hi_size;
794                                break;
795                          case 1:
796                                group1total += hi->hi_size;
797                                break;
798                          default:
799                                otherstotal += hi->hi_size;
800                                break;
801                        }
802                        grandtotal += hi->hi_size;
803                        hi = hi->hi_next;
804                }
805        }
806        sm_io_fprintf(stream, SM_TIME_DEFAULT,
807                "heap max=%lu, total=%lu, ",
808                (unsigned long) SmHeapMaxTotal, grandtotal);
809        sm_io_fprintf(stream, SM_TIME_DEFAULT,
810                "group 0=%lu, group 1=%lu, others=%lu\n",
811                group0total, group1total, otherstotal);
812        if (grandtotal != SmHeapTotal)
813        {
814                sm_io_fprintf(stream, SM_TIME_DEFAULT,
815                        "BUG => SmHeapTotal: got %lu, expected %lu\n",
816                        (unsigned long) SmHeapTotal, grandtotal);
817        }
818}
819#endif /* !SM_HEAP_CHECK */
Note: See TracBrowser for help on using the repository browser.