2 * Copyright (c) 2000-2001, 2004 Proofpoint, Inc. and its suppliers.
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.
11 SM_RCSID("@(#)$Id: heap.c,v 1.52 2013-11-22 20:51:43 ca Exp $")
14 ** debugging memory allocation package
15 ** See heap.html for documentation.
20 #include <sm/assert.h>
25 #include <sm/signal.h>
30 # include <sm/types.h>
35 /* undef all macro versions of the "functions" so they can be specified here */
38 #undef sm_malloc_tagged
39 #undef sm_malloc_tagged_x
44 # undef sm_heap_register
45 # undef sm_heap_checkptr
46 # undef sm_heap_report
47 #endif /* SM_HEAP_CHECK */
50 SM_DEBUG_T SmHeapCheck = SM_DEBUG_INITIALIZER("sm_check_heap",
51 "@(#)$Debug: sm_check_heap - check sm_malloc, sm_realloc, sm_free calls $");
52 # define HEAP_CHECK sm_debug_active(&SmHeapCheck, 1)
53 static int ptrhash __P((void *p));
54 #endif /* SM_HEAP_CHECK */
56 const SM_EXC_TYPE_T SmHeapOutOfMemoryType =
65 SM_EXC_T SmHeapOutOfMemory = SM_EXC_INITIALIZER(&SmHeapOutOfMemoryType, NULL);
69 ** The behaviour of malloc with size==0 is platform dependent (it
70 ** says so in the C standard): it can return NULL or non-NULL. We
71 ** don't want sm_malloc_x(0) to raise an exception on some platforms
72 ** but not others, so this case requires special handling. We've got
73 ** two choices: "size = 1" or "return NULL". We use the former in the
75 ** If we had something like autoconf we could figure out the
76 ** behaviour of the platform and either use this hack or just
80 #define MALLOC_SIZE(size) ((size) == 0 ? 1 : (size))
83 ** SM_MALLOC_X -- wrapper around malloc(), raises an exception on error.
86 ** size -- size of requested memory.
89 ** Pointer to memory region.
92 ** sm_malloc_x only gets called from source files in which heap
93 ** debugging is disabled at compile time. Otherwise, a call to
94 ** sm_malloc_x is macro expanded to a call to sm_malloc_tagged_x.
97 ** F:sm_heap -- out of memory
107 ptr = malloc(MALLOC_SIZE(size));
110 sm_exc_raise_x(&SmHeapOutOfMemory);
117 ** SM_MALLOC -- wrapper around malloc()
120 ** size -- size of requested memory.
123 ** Pointer to memory region.
133 ptr = malloc(MALLOC_SIZE(size));
139 ** SM_REALLOC -- wrapper for realloc()
142 ** ptr -- pointer to old memory area.
143 ** size -- size of requested memory.
146 ** Pointer to new memory area, NULL on failure.
150 sm_realloc(ptr, size)
157 newptr = realloc(ptr, MALLOC_SIZE(size));
163 ** SM_REALLOC_X -- wrapper for realloc()
166 ** ptr -- pointer to old memory area.
167 ** size -- size of requested memory.
170 ** Pointer to new memory area.
173 ** F:sm_heap -- out of memory
177 sm_realloc_x(ptr, size)
184 newptr = realloc(ptr, MALLOC_SIZE(size));
187 sm_exc_raise_x(&SmHeapOutOfMemory);
191 ** SM_FREE -- wrapper around free()
194 ** ptr -- pointer to memory region.
212 #else /* !SM_HEAP_CHECK */
215 ** Each allocated block is assigned a "group number".
216 ** By default, all blocks are assigned to group #1.
217 ** By convention, group #0 is for memory that is never freed.
218 ** You can use group numbers any way you want, in order to help make
219 ** sense of sm_heap_report output.
223 int SmHeapMaxGroup = 1;
226 ** Total number of bytes allocated.
227 ** This is only maintained if the sm_check_heap debug category is active.
230 size_t SmHeapTotal = 0;
233 ** High water mark: the most that SmHeapTotal has ever been.
236 size_t SmHeapMaxTotal = 0;
239 ** Maximum number of bytes that may be allocated at any one time.
241 ** This is only honoured if sm_check_heap is active.
244 SM_DEBUG_T SmHeapLimit = SM_DEBUG_INITIALIZER("sm_heap_limit",
245 "@(#)$Debug: sm_heap_limit - max # of bytes permitted in heap $");
248 ** This is the data structure that keeps track of all currently
249 ** allocated blocks of memory known to the heap package.
252 typedef struct sm_heap_item SM_HEAP_ITEM_T;
260 SM_HEAP_ITEM_T *hi_next;
263 #define SM_HEAP_TABLE_SIZE 256
264 static SM_HEAP_ITEM_T *SmHeapTable[SM_HEAP_TABLE_SIZE];
267 ** This is a randomly generated table
268 ** which contains exactly one occurrence
269 ** of each of the numbers between 0 and 255.
270 ** It is used by ptrhash.
273 static unsigned char hashtab[SM_HEAP_TABLE_SIZE] =
275 161, 71, 77,187, 15,229, 9,176,221,119,239, 21, 85,138,203, 86,
276 102, 65, 80,199,235, 32,140, 96,224, 78,126,127,144, 0, 11,179,
277 64, 30,120, 23,225,226, 33, 50,205,167,130,240,174, 99,206, 73,
278 231,210,189,162, 48, 93,246, 54,213,141,135, 39, 41,192,236,193,
279 157, 88, 95,104,188, 63,133,177,234,110,158,214,238,131,233, 91,
280 125, 82, 94, 79, 66, 92,151, 45,252, 98, 26,183, 7,191,171,106,
281 145,154,251,100,113, 5, 74, 62, 76,124, 14,217,200, 75,115,190,
282 103, 28,198,196,169,219, 37,118,150, 18,152,175, 49,136, 6,142,
283 89, 19,243,254, 47,137, 24,166,180, 10, 40,186,202, 46,184, 67,
284 148,108,181, 81, 25,241, 13,139, 58, 38, 84,253,201, 12,116, 17,
285 195, 22,112, 69,255, 43,147,222,111, 56,194,216,149,244, 42,173,
286 232,220,249,105,207, 51,197,242, 72,211,208, 59,122,230,237,170,
287 165, 44, 68,123,129,245,143,101, 8,209,215,247,185, 57,218, 53,
288 114,121, 3,128, 4,204,212,146, 2,155, 83,250, 87, 29, 31,159,
289 60, 27,107,156,227,182, 1, 61, 36,160,109, 97, 90, 20,168,132,
290 223,248, 70,164, 55,172, 34, 52,163,117, 35,153,134, 16,178,228
294 ** PTRHASH -- hash a pointer value
302 ** ptrhash hashes a pointer value to a uniformly distributed random
303 ** number between 0 and 255.
305 ** This hash algorithm is based on Peter K. Pearson,
306 ** "Fast Hashing of Variable-Length Text Strings",
307 ** in Communications of the ACM, June 1990, vol 33 no 6.
316 if (sizeof(void*) == 4 && sizeof(unsigned long) == 4)
318 unsigned long n = (unsigned long)p;
320 h = hashtab[n & 0xFF];
321 h = hashtab[h ^ ((n >> 8) & 0xFF)];
322 h = hashtab[h ^ ((n >> 16) & 0xFF)];
323 h = hashtab[h ^ ((n >> 24) & 0xFF)];
326 else if (sizeof(void*) == 8 && sizeof(unsigned long) == 8)
328 unsigned long n = (unsigned long)p;
330 h = hashtab[n & 0xFF];
331 h = hashtab[h ^ ((n >> 8) & 0xFF)];
332 h = hashtab[h ^ ((n >> 16) & 0xFF)];
333 h = hashtab[h ^ ((n >> 24) & 0xFF)];
334 h = hashtab[h ^ ((n >> 32) & 0xFF)];
335 h = hashtab[h ^ ((n >> 40) & 0xFF)];
336 h = hashtab[h ^ ((n >> 48) & 0xFF)];
337 h = hashtab[h ^ ((n >> 56) & 0xFF)];
342 unsigned char *cp = (unsigned char *)&p;
346 for (i = 0; i < sizeof(void*); ++i)
347 h = hashtab[h ^ cp[i]];
353 ** SM_MALLOC_TAGGED -- wrapper around malloc(), debugging version.
356 ** size -- size of requested memory.
357 ** tag -- tag for debugging.
358 ** num -- additional value for debugging.
359 ** group -- heap group for debugging.
362 ** Pointer to memory region.
366 sm_malloc_tagged(size, tag, num, group)
377 ptr = malloc(MALLOC_SIZE(size));
382 if (sm_xtrap_check())
384 if (sm_debug_active(&SmHeapLimit, 1)
385 && sm_debug_level(&SmHeapLimit) < SmHeapTotal + size)
388 ptr = malloc(MALLOC_SIZE(size));
390 if (ptr != NULL && !sm_heap_register(ptr, size, tag, num, group))
398 if (SmHeapTotal > SmHeapMaxTotal)
399 SmHeapMaxTotal = SmHeapTotal;
404 ** SM_MALLOC_TAGGED_X -- wrapper around malloc(), debugging version.
407 ** size -- size of requested memory.
408 ** tag -- tag for debugging.
409 ** num -- additional value for debugging.
410 ** group -- heap group for debugging.
413 ** Pointer to memory region.
416 ** F:sm_heap -- out of memory
420 sm_malloc_tagged_x(size, tag, num, group)
431 ptr = malloc(MALLOC_SIZE(size));
434 sm_exc_raise_x(&SmHeapOutOfMemory);
438 sm_xtrap_raise_x(&SmHeapOutOfMemory);
439 if (sm_debug_active(&SmHeapLimit, 1)
440 && sm_debug_level(&SmHeapLimit) < SmHeapTotal + size)
442 sm_exc_raise_x(&SmHeapOutOfMemory);
445 ptr = malloc(MALLOC_SIZE(size));
447 if (ptr != NULL && !sm_heap_register(ptr, size, tag, num, group))
455 sm_exc_raise_x(&SmHeapOutOfMemory);
457 if (SmHeapTotal > SmHeapMaxTotal)
458 SmHeapMaxTotal = SmHeapTotal;
463 ** SM_HEAP_REGISTER -- register a pointer into the heap for debugging.
466 ** ptr -- pointer to register.
467 ** size -- size of requested memory.
468 ** tag -- tag for debugging (this is NOT copied!)
469 ** num -- additional value for debugging.
470 ** group -- heap group for debugging.
473 ** true iff successfully registered (not yet in table).
477 sm_heap_register(ptr, size, tag, num, group)
489 SM_REQUIRE(ptr != NULL);
491 # if SM_CHECK_REQUIRE
494 ** We require that ptr is not already in SmHeapTable.
497 for (hi = SmHeapTable[i]; hi != NULL; hi = hi->hi_next)
499 if (hi->hi_ptr == ptr)
500 sm_abort("sm_heap_register: ptr %p is already registered (%s:%d)",
501 ptr, hi->hi_tag, hi->hi_num);
503 # endif /* SM_CHECK_REQUIRE */
505 hi = (SM_HEAP_ITEM_T *) malloc(sizeof(SM_HEAP_ITEM_T));
513 hi->hi_group = group;
514 hi->hi_next = SmHeapTable[i];
519 ** SM_REALLOC -- wrapper for realloc(), debugging version.
522 ** ptr -- pointer to old memory area.
523 ** size -- size of requested memory.
526 ** Pointer to new memory area, NULL on failure.
530 sm_realloc(ptr, size)
535 SM_HEAP_ITEM_T *hi, **hp;
540 newptr = realloc(ptr, MALLOC_SIZE(size));
546 return sm_malloc_tagged(size, "realloc", 0, SmHeapGroup);
548 for (hp = &SmHeapTable[ptrhash(ptr)]; *hp != NULL; hp = &(**hp).hi_next)
550 if ((**hp).hi_ptr == ptr)
552 if (sm_xtrap_check())
555 if (sm_debug_active(&SmHeapLimit, 1)
556 && sm_debug_level(&SmHeapLimit)
557 < SmHeapTotal - hi->hi_size + size)
562 newptr = realloc(ptr, MALLOC_SIZE(size));
566 SmHeapTotal = SmHeapTotal - hi->hi_size + size;
567 if (SmHeapTotal > SmHeapMaxTotal)
568 SmHeapMaxTotal = SmHeapTotal;
572 hp = &SmHeapTable[ptrhash(newptr)];
578 sm_abort("sm_realloc: bad argument (%p)", ptr);
580 return NULL; /* keep Irix compiler happy */
584 ** SM_REALLOC_X -- wrapper for realloc(), debugging version.
587 ** ptr -- pointer to old memory area.
588 ** size -- size of requested memory.
591 ** Pointer to new memory area.
594 ** F:sm_heap -- out of memory
598 sm_realloc_x(ptr, size)
603 SM_HEAP_ITEM_T *hi, **hp;
608 newptr = realloc(ptr, MALLOC_SIZE(size));
611 sm_exc_raise_x(&SmHeapOutOfMemory);
616 return sm_malloc_tagged_x(size, "realloc", 0, SmHeapGroup);
618 for (hp = &SmHeapTable[ptrhash(ptr)]; *hp != NULL; hp = &(**hp).hi_next)
620 if ((**hp).hi_ptr == ptr)
622 sm_xtrap_raise_x(&SmHeapOutOfMemory);
624 if (sm_debug_active(&SmHeapLimit, 1)
625 && sm_debug_level(&SmHeapLimit)
626 < SmHeapTotal - hi->hi_size + size)
628 sm_exc_raise_x(&SmHeapOutOfMemory);
631 newptr = realloc(ptr, MALLOC_SIZE(size));
634 sm_exc_raise_x(&SmHeapOutOfMemory);
635 SmHeapTotal = SmHeapTotal - hi->hi_size + size;
636 if (SmHeapTotal > SmHeapMaxTotal)
637 SmHeapMaxTotal = SmHeapTotal;
641 hp = &SmHeapTable[ptrhash(newptr)];
647 sm_abort("sm_realloc_x: bad argument (%p)", ptr);
649 return NULL; /* keep Irix compiler happy */
653 ** SM_FREE_TAGGED -- wrapper around free(), debugging version.
656 ** ptr -- pointer to memory region.
657 ** tag -- tag for debugging.
658 ** num -- additional value for debugging.
665 sm_free_tagged(ptr, tag, num)
681 for (hp = &SmHeapTable[ptrhash(ptr)]; *hp != NULL; hp = &(**hp).hi_next)
683 if ((**hp).hi_ptr == ptr)
685 SM_HEAP_ITEM_T *hi = *hp;
690 ** Fill the block with zeros before freeing.
691 ** This is intended to catch problems with
692 ** dangling pointers. The block is filled with
693 ** zeros, not with some non-zero value, because
694 ** it is common practice in some C code to store
695 ** a zero in a structure member before freeing the
696 ** structure, as a defense against dangling pointers.
699 (void) memset(ptr, 0, hi->hi_size);
700 SmHeapTotal -= hi->hi_size;
708 sm_abort("sm_free: bad argument (%p) (%s:%d)", ptr, tag, num);
712 ** SM_HEAP_CHECKPTR_TAGGED -- check whether ptr is a valid argument to sm_free
715 ** ptr -- pointer to memory region.
716 ** tag -- tag for debugging.
717 ** num -- additional value for debugging.
723 ** aborts if check fails.
727 sm_heap_checkptr_tagged(ptr, tag, num)
738 for (hp = SmHeapTable[ptrhash(ptr)]; hp != NULL; hp = hp->hi_next)
740 if (hp->hi_ptr == ptr)
743 sm_abort("sm_heap_checkptr(%p): bad ptr (%s:%d)", ptr, tag, num);
747 ** SM_HEAP_REPORT -- output "map" of used heap.
750 ** stream -- the file pointer to write to.
751 ** verbosity -- how much info?
758 sm_heap_report(stream, verbosity)
763 unsigned long group0total, group1total, otherstotal, grandtotal;
764 static char str[32] = "[1900-00-00/00:00:00] ";
768 if (!HEAP_CHECK || verbosity <= 0)
770 group0total = group1total = otherstotal = grandtotal = 0;
771 for (i = 0; i < sizeof(SmHeapTable) / sizeof(SmHeapTable[0]); ++i)
773 SM_HEAP_ITEM_T *hi = SmHeapTable[i];
778 || (verbosity > 1 && hi->hi_group != 0))
780 sm_io_fprintf(stream, SM_TIME_DEFAULT,
781 "%4d %*lx %7lu bytes",
783 (int) sizeof(void *) * 2,
785 (unsigned long)hi->hi_size);
786 if (hi->hi_tag != NULL)
788 sm_io_fprintf(stream, SM_TIME_DEFAULT,
793 sm_io_fprintf(stream,
799 sm_io_fprintf(stream, SM_TIME_DEFAULT, "\n");
801 switch (hi->hi_group)
804 group0total += hi->hi_size;
807 group1total += hi->hi_size;
810 otherstotal += hi->hi_size;
813 grandtotal += hi->hi_size;
818 currt = time((time_t *)0);
819 tmp = localtime(&currt);
820 snprintf(str, sizeof(str), "[%d-%02d-%02d/%02d:%02d:%02d] ",
821 1900 + tmp->tm_year, /* HACK */
824 tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
825 sm_io_fprintf(stream, SM_TIME_DEFAULT,
826 "pid=%ld time=%s\nheap max=%lu, total=%lu, group 0=%lu, group 1=%lu, others=%lu\n",
827 (long) getpid(), str,
828 (unsigned long) SmHeapMaxTotal, grandtotal,
829 group0total, group1total, otherstotal);
830 if (grandtotal != SmHeapTotal)
832 sm_io_fprintf(stream, SM_TIME_DEFAULT,
833 "BUG => SmHeapTotal: got %lu, expected %lu\n",
834 (unsigned long) SmHeapTotal, grandtotal);
837 #endif /* !SM_HEAP_CHECK */