190792Sgshapiro/* 2261363Sgshapiro * Copyright (c) 2000-2001, 2004 Proofpoint, Inc. and its suppliers. 390792Sgshapiro * All rights reserved. 490792Sgshapiro * 590792Sgshapiro * By using this file, you agree to the terms and conditions set 690792Sgshapiro * forth in the LICENSE file which can be found at the top level of 790792Sgshapiro * the sendmail distribution. 890792Sgshapiro */ 990792Sgshapiro 1090792Sgshapiro#include <sm/gen.h> 11266692SgshapiroSM_RCSID("@(#)$Id: heap.c,v 1.52 2013-11-22 20:51:43 ca Exp $") 1290792Sgshapiro 1390792Sgshapiro/* 1490792Sgshapiro** debugging memory allocation package 1590792Sgshapiro** See heap.html for documentation. 1690792Sgshapiro*/ 1790792Sgshapiro 1890792Sgshapiro#include <string.h> 1990792Sgshapiro 2090792Sgshapiro#include <sm/assert.h> 2190792Sgshapiro#include <sm/debug.h> 2290792Sgshapiro#include <sm/exc.h> 2390792Sgshapiro#include <sm/heap.h> 2490792Sgshapiro#include <sm/io.h> 2590792Sgshapiro#include <sm/signal.h> 2690792Sgshapiro#include <sm/xtrap.h> 2790792Sgshapiro 2890792Sgshapiro/* undef all macro versions of the "functions" so they can be specified here */ 2990792Sgshapiro#undef sm_malloc 3090792Sgshapiro#undef sm_malloc_x 3190792Sgshapiro#undef sm_malloc_tagged 3290792Sgshapiro#undef sm_malloc_tagged_x 3390792Sgshapiro#undef sm_free 3490792Sgshapiro#undef sm_free_tagged 3590792Sgshapiro#undef sm_realloc 3690792Sgshapiro#if SM_HEAP_CHECK 3790792Sgshapiro# undef sm_heap_register 3890792Sgshapiro# undef sm_heap_checkptr 3990792Sgshapiro# undef sm_heap_report 4090792Sgshapiro#endif /* SM_HEAP_CHECK */ 4190792Sgshapiro 4290792Sgshapiro#if SM_HEAP_CHECK 4390792SgshapiroSM_DEBUG_T SmHeapCheck = SM_DEBUG_INITIALIZER("sm_check_heap", 4490792Sgshapiro "@(#)$Debug: sm_check_heap - check sm_malloc, sm_realloc, sm_free calls $"); 4590792Sgshapiro# define HEAP_CHECK sm_debug_active(&SmHeapCheck, 1) 46141858Sgshapirostatic int ptrhash __P((void *p)); 4790792Sgshapiro#endif /* SM_HEAP_CHECK */ 4890792Sgshapiro 4990792Sgshapiroconst SM_EXC_TYPE_T SmHeapOutOfMemoryType = 5090792Sgshapiro{ 5190792Sgshapiro SmExcTypeMagic, 5290792Sgshapiro "F:sm.heap", 5390792Sgshapiro "", 5490792Sgshapiro sm_etype_printf, 5590792Sgshapiro "out of memory", 5690792Sgshapiro}; 5790792Sgshapiro 5890792SgshapiroSM_EXC_T SmHeapOutOfMemory = SM_EXC_INITIALIZER(&SmHeapOutOfMemoryType, NULL); 5990792Sgshapiro 6090792Sgshapiro 6190792Sgshapiro/* 6290792Sgshapiro** The behaviour of malloc with size==0 is platform dependent (it 6390792Sgshapiro** says so in the C standard): it can return NULL or non-NULL. We 6490792Sgshapiro** don't want sm_malloc_x(0) to raise an exception on some platforms 6590792Sgshapiro** but not others, so this case requires special handling. We've got 6690792Sgshapiro** two choices: "size = 1" or "return NULL". We use the former in the 6790792Sgshapiro** following. 6890792Sgshapiro** If we had something like autoconf we could figure out the 6990792Sgshapiro** behaviour of the platform and either use this hack or just 7090792Sgshapiro** use size. 7190792Sgshapiro*/ 7290792Sgshapiro 7390792Sgshapiro#define MALLOC_SIZE(size) ((size) == 0 ? 1 : (size)) 7490792Sgshapiro 7590792Sgshapiro/* 7690792Sgshapiro** SM_MALLOC_X -- wrapper around malloc(), raises an exception on error. 7790792Sgshapiro** 7890792Sgshapiro** Parameters: 7990792Sgshapiro** size -- size of requested memory. 8090792Sgshapiro** 8190792Sgshapiro** Returns: 8290792Sgshapiro** Pointer to memory region. 8390792Sgshapiro** 8490792Sgshapiro** Note: 8590792Sgshapiro** sm_malloc_x only gets called from source files in which heap 8690792Sgshapiro** debugging is disabled at compile time. Otherwise, a call to 8790792Sgshapiro** sm_malloc_x is macro expanded to a call to sm_malloc_tagged_x. 8890792Sgshapiro** 8990792Sgshapiro** Exceptions: 9090792Sgshapiro** F:sm_heap -- out of memory 9190792Sgshapiro*/ 9290792Sgshapiro 9390792Sgshapirovoid * 9490792Sgshapirosm_malloc_x(size) 9590792Sgshapiro size_t size; 9690792Sgshapiro{ 9790792Sgshapiro void *ptr; 9890792Sgshapiro 9990792Sgshapiro ENTER_CRITICAL(); 10090792Sgshapiro ptr = malloc(MALLOC_SIZE(size)); 10190792Sgshapiro LEAVE_CRITICAL(); 10290792Sgshapiro if (ptr == NULL) 10390792Sgshapiro sm_exc_raise_x(&SmHeapOutOfMemory); 10490792Sgshapiro return ptr; 10590792Sgshapiro} 10690792Sgshapiro 10790792Sgshapiro#if !SM_HEAP_CHECK 10890792Sgshapiro 10990792Sgshapiro/* 11090792Sgshapiro** SM_MALLOC -- wrapper around malloc() 11190792Sgshapiro** 11290792Sgshapiro** Parameters: 11390792Sgshapiro** size -- size of requested memory. 11490792Sgshapiro** 11590792Sgshapiro** Returns: 11690792Sgshapiro** Pointer to memory region. 11790792Sgshapiro*/ 11890792Sgshapiro 11990792Sgshapirovoid * 12090792Sgshapirosm_malloc(size) 12190792Sgshapiro size_t size; 12290792Sgshapiro{ 12390792Sgshapiro void *ptr; 12490792Sgshapiro 12590792Sgshapiro ENTER_CRITICAL(); 12690792Sgshapiro ptr = malloc(MALLOC_SIZE(size)); 12790792Sgshapiro LEAVE_CRITICAL(); 12890792Sgshapiro return ptr; 12990792Sgshapiro} 13090792Sgshapiro 13190792Sgshapiro/* 13290792Sgshapiro** SM_REALLOC -- wrapper for realloc() 13390792Sgshapiro** 13490792Sgshapiro** Parameters: 13590792Sgshapiro** ptr -- pointer to old memory area. 13690792Sgshapiro** size -- size of requested memory. 13790792Sgshapiro** 13890792Sgshapiro** Returns: 13990792Sgshapiro** Pointer to new memory area, NULL on failure. 14090792Sgshapiro*/ 14190792Sgshapiro 14290792Sgshapirovoid * 14390792Sgshapirosm_realloc(ptr, size) 14490792Sgshapiro void *ptr; 14590792Sgshapiro size_t size; 14690792Sgshapiro{ 14790792Sgshapiro void *newptr; 14890792Sgshapiro 14990792Sgshapiro ENTER_CRITICAL(); 15090792Sgshapiro newptr = realloc(ptr, MALLOC_SIZE(size)); 15190792Sgshapiro LEAVE_CRITICAL(); 15290792Sgshapiro return newptr; 15390792Sgshapiro} 15490792Sgshapiro 15590792Sgshapiro/* 15690792Sgshapiro** SM_REALLOC_X -- wrapper for realloc() 15790792Sgshapiro** 15890792Sgshapiro** Parameters: 15990792Sgshapiro** ptr -- pointer to old memory area. 16090792Sgshapiro** size -- size of requested memory. 16190792Sgshapiro** 16290792Sgshapiro** Returns: 16390792Sgshapiro** Pointer to new memory area. 16490792Sgshapiro** 16590792Sgshapiro** Exceptions: 16690792Sgshapiro** F:sm_heap -- out of memory 16790792Sgshapiro*/ 16890792Sgshapiro 16990792Sgshapirovoid * 17090792Sgshapirosm_realloc_x(ptr, size) 17190792Sgshapiro void *ptr; 17290792Sgshapiro size_t size; 17390792Sgshapiro{ 17490792Sgshapiro void *newptr; 17590792Sgshapiro 17690792Sgshapiro ENTER_CRITICAL(); 17790792Sgshapiro newptr = realloc(ptr, MALLOC_SIZE(size)); 17890792Sgshapiro LEAVE_CRITICAL(); 17990792Sgshapiro if (newptr == NULL) 18090792Sgshapiro sm_exc_raise_x(&SmHeapOutOfMemory); 18190792Sgshapiro return newptr; 18290792Sgshapiro} 18390792Sgshapiro/* 18490792Sgshapiro** SM_FREE -- wrapper around free() 18590792Sgshapiro** 18690792Sgshapiro** Parameters: 18790792Sgshapiro** ptr -- pointer to memory region. 18890792Sgshapiro** 18990792Sgshapiro** Returns: 19090792Sgshapiro** none. 19190792Sgshapiro*/ 19290792Sgshapiro 19390792Sgshapirovoid 19490792Sgshapirosm_free(ptr) 19590792Sgshapiro void *ptr; 19690792Sgshapiro{ 19790792Sgshapiro if (ptr == NULL) 19890792Sgshapiro return; 19990792Sgshapiro ENTER_CRITICAL(); 20090792Sgshapiro free(ptr); 20190792Sgshapiro LEAVE_CRITICAL(); 20290792Sgshapiro return; 20390792Sgshapiro} 20490792Sgshapiro 20590792Sgshapiro#else /* !SM_HEAP_CHECK */ 20690792Sgshapiro 20790792Sgshapiro/* 20890792Sgshapiro** Each allocated block is assigned a "group number". 20990792Sgshapiro** By default, all blocks are assigned to group #1. 21090792Sgshapiro** By convention, group #0 is for memory that is never freed. 21190792Sgshapiro** You can use group numbers any way you want, in order to help make 21290792Sgshapiro** sense of sm_heap_report output. 21390792Sgshapiro*/ 21490792Sgshapiro 21590792Sgshapiroint SmHeapGroup = 1; 21690792Sgshapiroint SmHeapMaxGroup = 1; 21790792Sgshapiro 21890792Sgshapiro/* 21990792Sgshapiro** Total number of bytes allocated. 22090792Sgshapiro** This is only maintained if the sm_check_heap debug category is active. 22190792Sgshapiro*/ 22290792Sgshapiro 22390792Sgshapirosize_t SmHeapTotal = 0; 22490792Sgshapiro 22590792Sgshapiro/* 22690792Sgshapiro** High water mark: the most that SmHeapTotal has ever been. 22790792Sgshapiro*/ 22890792Sgshapiro 22990792Sgshapirosize_t SmHeapMaxTotal = 0; 23090792Sgshapiro 23190792Sgshapiro/* 23290792Sgshapiro** Maximum number of bytes that may be allocated at any one time. 23390792Sgshapiro** 0 means no limit. 23490792Sgshapiro** This is only honoured if sm_check_heap is active. 23590792Sgshapiro*/ 23690792Sgshapiro 23790792SgshapiroSM_DEBUG_T SmHeapLimit = SM_DEBUG_INITIALIZER("sm_heap_limit", 23890792Sgshapiro "@(#)$Debug: sm_heap_limit - max # of bytes permitted in heap $"); 23990792Sgshapiro 24090792Sgshapiro/* 24190792Sgshapiro** This is the data structure that keeps track of all currently 24290792Sgshapiro** allocated blocks of memory known to the heap package. 24390792Sgshapiro*/ 24490792Sgshapiro 24590792Sgshapirotypedef struct sm_heap_item SM_HEAP_ITEM_T; 24690792Sgshapirostruct sm_heap_item 24790792Sgshapiro{ 24890792Sgshapiro void *hi_ptr; 24990792Sgshapiro size_t hi_size; 25090792Sgshapiro char *hi_tag; 25190792Sgshapiro int hi_num; 25290792Sgshapiro int hi_group; 25390792Sgshapiro SM_HEAP_ITEM_T *hi_next; 25490792Sgshapiro}; 25590792Sgshapiro 25690792Sgshapiro#define SM_HEAP_TABLE_SIZE 256 25790792Sgshapirostatic SM_HEAP_ITEM_T *SmHeapTable[SM_HEAP_TABLE_SIZE]; 25890792Sgshapiro 25990792Sgshapiro/* 26090792Sgshapiro** This is a randomly generated table 26190792Sgshapiro** which contains exactly one occurrence 26290792Sgshapiro** of each of the numbers between 0 and 255. 26390792Sgshapiro** It is used by ptrhash. 26490792Sgshapiro*/ 26590792Sgshapiro 26690792Sgshapirostatic unsigned char hashtab[SM_HEAP_TABLE_SIZE] = 26790792Sgshapiro{ 26890792Sgshapiro 161, 71, 77,187, 15,229, 9,176,221,119,239, 21, 85,138,203, 86, 26990792Sgshapiro 102, 65, 80,199,235, 32,140, 96,224, 78,126,127,144, 0, 11,179, 27090792Sgshapiro 64, 30,120, 23,225,226, 33, 50,205,167,130,240,174, 99,206, 73, 27190792Sgshapiro 231,210,189,162, 48, 93,246, 54,213,141,135, 39, 41,192,236,193, 27290792Sgshapiro 157, 88, 95,104,188, 63,133,177,234,110,158,214,238,131,233, 91, 27390792Sgshapiro 125, 82, 94, 79, 66, 92,151, 45,252, 98, 26,183, 7,191,171,106, 27490792Sgshapiro 145,154,251,100,113, 5, 74, 62, 76,124, 14,217,200, 75,115,190, 27590792Sgshapiro 103, 28,198,196,169,219, 37,118,150, 18,152,175, 49,136, 6,142, 27690792Sgshapiro 89, 19,243,254, 47,137, 24,166,180, 10, 40,186,202, 46,184, 67, 27790792Sgshapiro 148,108,181, 81, 25,241, 13,139, 58, 38, 84,253,201, 12,116, 17, 27890792Sgshapiro 195, 22,112, 69,255, 43,147,222,111, 56,194,216,149,244, 42,173, 27990792Sgshapiro 232,220,249,105,207, 51,197,242, 72,211,208, 59,122,230,237,170, 28090792Sgshapiro 165, 44, 68,123,129,245,143,101, 8,209,215,247,185, 57,218, 53, 28190792Sgshapiro 114,121, 3,128, 4,204,212,146, 2,155, 83,250, 87, 29, 31,159, 28290792Sgshapiro 60, 27,107,156,227,182, 1, 61, 36,160,109, 97, 90, 20,168,132, 28390792Sgshapiro 223,248, 70,164, 55,172, 34, 52,163,117, 35,153,134, 16,178,228 28490792Sgshapiro}; 28590792Sgshapiro 28690792Sgshapiro/* 28790792Sgshapiro** PTRHASH -- hash a pointer value 28890792Sgshapiro** 28990792Sgshapiro** Parameters: 29090792Sgshapiro** p -- pointer. 29190792Sgshapiro** 29290792Sgshapiro** Returns: 29390792Sgshapiro** hash value. 29490792Sgshapiro** 29590792Sgshapiro** ptrhash hashes a pointer value to a uniformly distributed random 29690792Sgshapiro** number between 0 and 255. 29790792Sgshapiro** 29890792Sgshapiro** This hash algorithm is based on Peter K. Pearson, 29990792Sgshapiro** "Fast Hashing of Variable-Length Text Strings", 30090792Sgshapiro** in Communications of the ACM, June 1990, vol 33 no 6. 30190792Sgshapiro*/ 30290792Sgshapiro 30390792Sgshapirostatic int 30490792Sgshapiroptrhash(p) 30590792Sgshapiro void *p; 30690792Sgshapiro{ 30790792Sgshapiro int h; 30890792Sgshapiro 30990792Sgshapiro if (sizeof(void*) == 4 && sizeof(unsigned long) == 4) 31090792Sgshapiro { 31190792Sgshapiro unsigned long n = (unsigned long)p; 31290792Sgshapiro 31390792Sgshapiro h = hashtab[n & 0xFF]; 31490792Sgshapiro h = hashtab[h ^ ((n >> 8) & 0xFF)]; 31590792Sgshapiro h = hashtab[h ^ ((n >> 16) & 0xFF)]; 31690792Sgshapiro h = hashtab[h ^ ((n >> 24) & 0xFF)]; 31790792Sgshapiro } 31890792Sgshapiro# if 0 31990792Sgshapiro else if (sizeof(void*) == 8 && sizeof(unsigned long) == 8) 32090792Sgshapiro { 32190792Sgshapiro unsigned long n = (unsigned long)p; 32290792Sgshapiro 32390792Sgshapiro h = hashtab[n & 0xFF]; 32490792Sgshapiro h = hashtab[h ^ ((n >> 8) & 0xFF)]; 32590792Sgshapiro h = hashtab[h ^ ((n >> 16) & 0xFF)]; 32690792Sgshapiro h = hashtab[h ^ ((n >> 24) & 0xFF)]; 32790792Sgshapiro h = hashtab[h ^ ((n >> 32) & 0xFF)]; 32890792Sgshapiro h = hashtab[h ^ ((n >> 40) & 0xFF)]; 32990792Sgshapiro h = hashtab[h ^ ((n >> 48) & 0xFF)]; 33090792Sgshapiro h = hashtab[h ^ ((n >> 56) & 0xFF)]; 33190792Sgshapiro } 33290792Sgshapiro# endif /* 0 */ 33390792Sgshapiro else 33490792Sgshapiro { 33590792Sgshapiro unsigned char *cp = (unsigned char *)&p; 33690792Sgshapiro int i; 33790792Sgshapiro 33890792Sgshapiro h = 0; 33990792Sgshapiro for (i = 0; i < sizeof(void*); ++i) 34090792Sgshapiro h = hashtab[h ^ cp[i]]; 34190792Sgshapiro } 34290792Sgshapiro return h; 34390792Sgshapiro} 34490792Sgshapiro 34590792Sgshapiro/* 34690792Sgshapiro** SM_MALLOC_TAGGED -- wrapper around malloc(), debugging version. 34790792Sgshapiro** 34890792Sgshapiro** Parameters: 34990792Sgshapiro** size -- size of requested memory. 35090792Sgshapiro** tag -- tag for debugging. 35190792Sgshapiro** num -- additional value for debugging. 35290792Sgshapiro** group -- heap group for debugging. 35390792Sgshapiro** 35490792Sgshapiro** Returns: 35590792Sgshapiro** Pointer to memory region. 35690792Sgshapiro*/ 35790792Sgshapiro 35890792Sgshapirovoid * 35990792Sgshapirosm_malloc_tagged(size, tag, num, group) 36090792Sgshapiro size_t size; 36190792Sgshapiro char *tag; 36290792Sgshapiro int num; 36390792Sgshapiro int group; 36490792Sgshapiro{ 36590792Sgshapiro void *ptr; 36690792Sgshapiro 36790792Sgshapiro if (!HEAP_CHECK) 36890792Sgshapiro { 36990792Sgshapiro ENTER_CRITICAL(); 37090792Sgshapiro ptr = malloc(MALLOC_SIZE(size)); 37190792Sgshapiro LEAVE_CRITICAL(); 37290792Sgshapiro return ptr; 37390792Sgshapiro } 37490792Sgshapiro 37590792Sgshapiro if (sm_xtrap_check()) 37690792Sgshapiro return NULL; 37790792Sgshapiro if (sm_debug_active(&SmHeapLimit, 1) 37890792Sgshapiro && sm_debug_level(&SmHeapLimit) < SmHeapTotal + size) 37990792Sgshapiro return NULL; 38090792Sgshapiro ENTER_CRITICAL(); 38190792Sgshapiro ptr = malloc(MALLOC_SIZE(size)); 38290792Sgshapiro LEAVE_CRITICAL(); 38390792Sgshapiro if (ptr != NULL && !sm_heap_register(ptr, size, tag, num, group)) 38490792Sgshapiro { 38590792Sgshapiro ENTER_CRITICAL(); 38690792Sgshapiro free(ptr); 38790792Sgshapiro LEAVE_CRITICAL(); 38890792Sgshapiro ptr = NULL; 38990792Sgshapiro } 39090792Sgshapiro SmHeapTotal += size; 39190792Sgshapiro if (SmHeapTotal > SmHeapMaxTotal) 39290792Sgshapiro SmHeapMaxTotal = SmHeapTotal; 39390792Sgshapiro return ptr; 39490792Sgshapiro} 39590792Sgshapiro 39690792Sgshapiro/* 39790792Sgshapiro** SM_MALLOC_TAGGED_X -- wrapper around malloc(), debugging version. 39890792Sgshapiro** 39990792Sgshapiro** Parameters: 40090792Sgshapiro** size -- size of requested memory. 40190792Sgshapiro** tag -- tag for debugging. 40290792Sgshapiro** num -- additional value for debugging. 40390792Sgshapiro** group -- heap group for debugging. 40490792Sgshapiro** 40590792Sgshapiro** Returns: 40690792Sgshapiro** Pointer to memory region. 40790792Sgshapiro** 40890792Sgshapiro** Exceptions: 40990792Sgshapiro** F:sm_heap -- out of memory 41090792Sgshapiro*/ 41190792Sgshapiro 41290792Sgshapirovoid * 41390792Sgshapirosm_malloc_tagged_x(size, tag, num, group) 41490792Sgshapiro size_t size; 41590792Sgshapiro char *tag; 41690792Sgshapiro int num; 41790792Sgshapiro int group; 41890792Sgshapiro{ 41990792Sgshapiro void *ptr; 42090792Sgshapiro 42190792Sgshapiro if (!HEAP_CHECK) 42290792Sgshapiro { 42390792Sgshapiro ENTER_CRITICAL(); 42490792Sgshapiro ptr = malloc(MALLOC_SIZE(size)); 42590792Sgshapiro LEAVE_CRITICAL(); 42690792Sgshapiro if (ptr == NULL) 42790792Sgshapiro sm_exc_raise_x(&SmHeapOutOfMemory); 42890792Sgshapiro return ptr; 42990792Sgshapiro } 43090792Sgshapiro 43190792Sgshapiro sm_xtrap_raise_x(&SmHeapOutOfMemory); 43290792Sgshapiro if (sm_debug_active(&SmHeapLimit, 1) 43390792Sgshapiro && sm_debug_level(&SmHeapLimit) < SmHeapTotal + size) 43490792Sgshapiro { 43590792Sgshapiro sm_exc_raise_x(&SmHeapOutOfMemory); 43690792Sgshapiro } 43790792Sgshapiro ENTER_CRITICAL(); 43890792Sgshapiro ptr = malloc(MALLOC_SIZE(size)); 43990792Sgshapiro LEAVE_CRITICAL(); 44090792Sgshapiro if (ptr != NULL && !sm_heap_register(ptr, size, tag, num, group)) 44190792Sgshapiro { 44290792Sgshapiro ENTER_CRITICAL(); 44390792Sgshapiro free(ptr); 44490792Sgshapiro LEAVE_CRITICAL(); 44590792Sgshapiro ptr = NULL; 44690792Sgshapiro } 44790792Sgshapiro if (ptr == NULL) 44890792Sgshapiro sm_exc_raise_x(&SmHeapOutOfMemory); 44990792Sgshapiro SmHeapTotal += size; 45090792Sgshapiro if (SmHeapTotal > SmHeapMaxTotal) 45190792Sgshapiro SmHeapMaxTotal = SmHeapTotal; 45290792Sgshapiro return ptr; 45390792Sgshapiro} 45490792Sgshapiro 45590792Sgshapiro/* 45690792Sgshapiro** SM_HEAP_REGISTER -- register a pointer into the heap for debugging. 45790792Sgshapiro** 45890792Sgshapiro** Parameters: 45990792Sgshapiro** ptr -- pointer to register. 46090792Sgshapiro** size -- size of requested memory. 46190792Sgshapiro** tag -- tag for debugging. 46290792Sgshapiro** num -- additional value for debugging. 46390792Sgshapiro** group -- heap group for debugging. 46490792Sgshapiro** 46590792Sgshapiro** Returns: 46690792Sgshapiro** true iff successfully registered (not yet in table). 46790792Sgshapiro*/ 46890792Sgshapiro 46990792Sgshapirobool 47090792Sgshapirosm_heap_register(ptr, size, tag, num, group) 47190792Sgshapiro void *ptr; 47290792Sgshapiro size_t size; 47390792Sgshapiro char *tag; 47490792Sgshapiro int num; 47590792Sgshapiro int group; 47690792Sgshapiro{ 47790792Sgshapiro int i; 47890792Sgshapiro SM_HEAP_ITEM_T *hi; 47990792Sgshapiro 48090792Sgshapiro if (!HEAP_CHECK) 48190792Sgshapiro return true; 48290792Sgshapiro SM_REQUIRE(ptr != NULL); 48390792Sgshapiro i = ptrhash(ptr); 48490792Sgshapiro# if SM_CHECK_REQUIRE 48590792Sgshapiro 48690792Sgshapiro /* 48790792Sgshapiro ** We require that ptr is not already in SmHeapTable. 48890792Sgshapiro */ 48990792Sgshapiro 49090792Sgshapiro for (hi = SmHeapTable[i]; hi != NULL; hi = hi->hi_next) 49190792Sgshapiro { 49290792Sgshapiro if (hi->hi_ptr == ptr) 49390792Sgshapiro sm_abort("sm_heap_register: ptr %p is already registered (%s:%d)", 49490792Sgshapiro ptr, hi->hi_tag, hi->hi_num); 49590792Sgshapiro } 49690792Sgshapiro# endif /* SM_CHECK_REQUIRE */ 49790792Sgshapiro ENTER_CRITICAL(); 49890792Sgshapiro hi = (SM_HEAP_ITEM_T *) malloc(sizeof(SM_HEAP_ITEM_T)); 49990792Sgshapiro LEAVE_CRITICAL(); 50090792Sgshapiro if (hi == NULL) 50190792Sgshapiro return false; 50290792Sgshapiro hi->hi_ptr = ptr; 50390792Sgshapiro hi->hi_size = size; 50490792Sgshapiro hi->hi_tag = tag; 50590792Sgshapiro hi->hi_num = num; 50690792Sgshapiro hi->hi_group = group; 50790792Sgshapiro hi->hi_next = SmHeapTable[i]; 50890792Sgshapiro SmHeapTable[i] = hi; 50990792Sgshapiro return true; 51090792Sgshapiro} 51190792Sgshapiro/* 51290792Sgshapiro** SM_REALLOC -- wrapper for realloc(), debugging version. 51390792Sgshapiro** 51490792Sgshapiro** Parameters: 51590792Sgshapiro** ptr -- pointer to old memory area. 51690792Sgshapiro** size -- size of requested memory. 51790792Sgshapiro** 51890792Sgshapiro** Returns: 51990792Sgshapiro** Pointer to new memory area, NULL on failure. 52090792Sgshapiro*/ 52190792Sgshapiro 52290792Sgshapirovoid * 52390792Sgshapirosm_realloc(ptr, size) 52490792Sgshapiro void *ptr; 52590792Sgshapiro size_t size; 52690792Sgshapiro{ 52790792Sgshapiro void *newptr; 52890792Sgshapiro SM_HEAP_ITEM_T *hi, **hp; 52990792Sgshapiro 53090792Sgshapiro if (!HEAP_CHECK) 53190792Sgshapiro { 53290792Sgshapiro ENTER_CRITICAL(); 53390792Sgshapiro newptr = realloc(ptr, MALLOC_SIZE(size)); 53490792Sgshapiro LEAVE_CRITICAL(); 53590792Sgshapiro return newptr; 53690792Sgshapiro } 53790792Sgshapiro 53890792Sgshapiro if (ptr == NULL) 53990792Sgshapiro return sm_malloc_tagged(size, "realloc", 0, SmHeapGroup); 54090792Sgshapiro 54190792Sgshapiro for (hp = &SmHeapTable[ptrhash(ptr)]; *hp != NULL; hp = &(**hp).hi_next) 54290792Sgshapiro { 54390792Sgshapiro if ((**hp).hi_ptr == ptr) 54490792Sgshapiro { 54590792Sgshapiro if (sm_xtrap_check()) 54690792Sgshapiro return NULL; 54790792Sgshapiro hi = *hp; 54890792Sgshapiro if (sm_debug_active(&SmHeapLimit, 1) 54990792Sgshapiro && sm_debug_level(&SmHeapLimit) 55090792Sgshapiro < SmHeapTotal - hi->hi_size + size) 55190792Sgshapiro { 55290792Sgshapiro return NULL; 55390792Sgshapiro } 55490792Sgshapiro ENTER_CRITICAL(); 55590792Sgshapiro newptr = realloc(ptr, MALLOC_SIZE(size)); 55690792Sgshapiro LEAVE_CRITICAL(); 55790792Sgshapiro if (newptr == NULL) 55890792Sgshapiro return NULL; 55990792Sgshapiro SmHeapTotal = SmHeapTotal - hi->hi_size + size; 56090792Sgshapiro if (SmHeapTotal > SmHeapMaxTotal) 56190792Sgshapiro SmHeapMaxTotal = SmHeapTotal; 56290792Sgshapiro *hp = hi->hi_next; 56390792Sgshapiro hi->hi_ptr = newptr; 56490792Sgshapiro hi->hi_size = size; 56590792Sgshapiro hp = &SmHeapTable[ptrhash(newptr)]; 56690792Sgshapiro hi->hi_next = *hp; 56790792Sgshapiro *hp = hi; 56890792Sgshapiro return newptr; 56990792Sgshapiro } 57090792Sgshapiro } 57190792Sgshapiro sm_abort("sm_realloc: bad argument (%p)", ptr); 57290792Sgshapiro /* NOTREACHED */ 57390792Sgshapiro return NULL; /* keep Irix compiler happy */ 57490792Sgshapiro} 57590792Sgshapiro 57690792Sgshapiro/* 57790792Sgshapiro** SM_REALLOC_X -- wrapper for realloc(), debugging version. 57890792Sgshapiro** 57990792Sgshapiro** Parameters: 58090792Sgshapiro** ptr -- pointer to old memory area. 58190792Sgshapiro** size -- size of requested memory. 58290792Sgshapiro** 58390792Sgshapiro** Returns: 58490792Sgshapiro** Pointer to new memory area. 58590792Sgshapiro** 58690792Sgshapiro** Exceptions: 58790792Sgshapiro** F:sm_heap -- out of memory 58890792Sgshapiro*/ 58990792Sgshapiro 59090792Sgshapirovoid * 59190792Sgshapirosm_realloc_x(ptr, size) 59290792Sgshapiro void *ptr; 59390792Sgshapiro size_t size; 59490792Sgshapiro{ 59590792Sgshapiro void *newptr; 59690792Sgshapiro SM_HEAP_ITEM_T *hi, **hp; 59790792Sgshapiro 59890792Sgshapiro if (!HEAP_CHECK) 59990792Sgshapiro { 60090792Sgshapiro ENTER_CRITICAL(); 60190792Sgshapiro newptr = realloc(ptr, MALLOC_SIZE(size)); 60290792Sgshapiro LEAVE_CRITICAL(); 60390792Sgshapiro if (newptr == NULL) 60490792Sgshapiro sm_exc_raise_x(&SmHeapOutOfMemory); 60590792Sgshapiro return newptr; 60690792Sgshapiro } 60790792Sgshapiro 60890792Sgshapiro if (ptr == NULL) 60990792Sgshapiro return sm_malloc_tagged_x(size, "realloc", 0, SmHeapGroup); 61090792Sgshapiro 61190792Sgshapiro for (hp = &SmHeapTable[ptrhash(ptr)]; *hp != NULL; hp = &(**hp).hi_next) 61290792Sgshapiro { 61390792Sgshapiro if ((**hp).hi_ptr == ptr) 61490792Sgshapiro { 61590792Sgshapiro sm_xtrap_raise_x(&SmHeapOutOfMemory); 61690792Sgshapiro hi = *hp; 61790792Sgshapiro if (sm_debug_active(&SmHeapLimit, 1) 61890792Sgshapiro && sm_debug_level(&SmHeapLimit) 61990792Sgshapiro < SmHeapTotal - hi->hi_size + size) 62090792Sgshapiro { 62190792Sgshapiro sm_exc_raise_x(&SmHeapOutOfMemory); 62290792Sgshapiro } 62390792Sgshapiro ENTER_CRITICAL(); 62490792Sgshapiro newptr = realloc(ptr, MALLOC_SIZE(size)); 62590792Sgshapiro LEAVE_CRITICAL(); 62690792Sgshapiro if (newptr == NULL) 62790792Sgshapiro sm_exc_raise_x(&SmHeapOutOfMemory); 62890792Sgshapiro SmHeapTotal = SmHeapTotal - hi->hi_size + size; 62990792Sgshapiro if (SmHeapTotal > SmHeapMaxTotal) 63090792Sgshapiro SmHeapMaxTotal = SmHeapTotal; 63190792Sgshapiro *hp = hi->hi_next; 63290792Sgshapiro hi->hi_ptr = newptr; 63390792Sgshapiro hi->hi_size = size; 63490792Sgshapiro hp = &SmHeapTable[ptrhash(newptr)]; 63590792Sgshapiro hi->hi_next = *hp; 63690792Sgshapiro *hp = hi; 63790792Sgshapiro return newptr; 63890792Sgshapiro } 63990792Sgshapiro } 64090792Sgshapiro sm_abort("sm_realloc_x: bad argument (%p)", ptr); 64190792Sgshapiro /* NOTREACHED */ 64290792Sgshapiro return NULL; /* keep Irix compiler happy */ 64390792Sgshapiro} 64490792Sgshapiro 64590792Sgshapiro/* 64690792Sgshapiro** SM_FREE_TAGGED -- wrapper around free(), debugging version. 64790792Sgshapiro** 64890792Sgshapiro** Parameters: 64990792Sgshapiro** ptr -- pointer to memory region. 65090792Sgshapiro** tag -- tag for debugging. 65190792Sgshapiro** num -- additional value for debugging. 65290792Sgshapiro** 65390792Sgshapiro** Returns: 65490792Sgshapiro** none. 65590792Sgshapiro*/ 65690792Sgshapiro 65790792Sgshapirovoid 65890792Sgshapirosm_free_tagged(ptr, tag, num) 65990792Sgshapiro void *ptr; 66090792Sgshapiro char *tag; 66190792Sgshapiro int num; 66290792Sgshapiro{ 66390792Sgshapiro SM_HEAP_ITEM_T **hp; 66490792Sgshapiro 66590792Sgshapiro if (ptr == NULL) 66690792Sgshapiro return; 66790792Sgshapiro if (!HEAP_CHECK) 66890792Sgshapiro { 66990792Sgshapiro ENTER_CRITICAL(); 67090792Sgshapiro free(ptr); 67190792Sgshapiro LEAVE_CRITICAL(); 67290792Sgshapiro return; 67390792Sgshapiro } 67490792Sgshapiro for (hp = &SmHeapTable[ptrhash(ptr)]; *hp != NULL; hp = &(**hp).hi_next) 67590792Sgshapiro { 67690792Sgshapiro if ((**hp).hi_ptr == ptr) 67790792Sgshapiro { 67890792Sgshapiro SM_HEAP_ITEM_T *hi = *hp; 67990792Sgshapiro 68090792Sgshapiro *hp = hi->hi_next; 68190792Sgshapiro 68290792Sgshapiro /* 68390792Sgshapiro ** Fill the block with zeros before freeing. 68490792Sgshapiro ** This is intended to catch problems with 68590792Sgshapiro ** dangling pointers. The block is filled with 68690792Sgshapiro ** zeros, not with some non-zero value, because 68790792Sgshapiro ** it is common practice in some C code to store 68890792Sgshapiro ** a zero in a structure member before freeing the 68990792Sgshapiro ** structure, as a defense against dangling pointers. 69090792Sgshapiro */ 69190792Sgshapiro 69290792Sgshapiro (void) memset(ptr, 0, hi->hi_size); 69390792Sgshapiro SmHeapTotal -= hi->hi_size; 69490792Sgshapiro ENTER_CRITICAL(); 69590792Sgshapiro free(ptr); 69690792Sgshapiro free(hi); 69790792Sgshapiro LEAVE_CRITICAL(); 69890792Sgshapiro return; 69990792Sgshapiro } 70090792Sgshapiro } 70190792Sgshapiro sm_abort("sm_free: bad argument (%p) (%s:%d)", ptr, tag, num); 70290792Sgshapiro} 70390792Sgshapiro 70490792Sgshapiro/* 70590792Sgshapiro** SM_HEAP_CHECKPTR_TAGGED -- check whether ptr is a valid argument to sm_free 70690792Sgshapiro** 70790792Sgshapiro** Parameters: 70890792Sgshapiro** ptr -- pointer to memory region. 70990792Sgshapiro** tag -- tag for debugging. 71090792Sgshapiro** num -- additional value for debugging. 71190792Sgshapiro** 71290792Sgshapiro** Returns: 71390792Sgshapiro** none. 71490792Sgshapiro** 71590792Sgshapiro** Side Effects: 71690792Sgshapiro** aborts if check fails. 71790792Sgshapiro*/ 71890792Sgshapiro 71990792Sgshapirovoid 72090792Sgshapirosm_heap_checkptr_tagged(ptr, tag, num) 72190792Sgshapiro void *ptr; 72290792Sgshapiro char *tag; 72390792Sgshapiro int num; 72490792Sgshapiro{ 72590792Sgshapiro SM_HEAP_ITEM_T *hp; 72690792Sgshapiro 72790792Sgshapiro if (!HEAP_CHECK) 72890792Sgshapiro return; 72990792Sgshapiro if (ptr == NULL) 73090792Sgshapiro return; 73190792Sgshapiro for (hp = SmHeapTable[ptrhash(ptr)]; hp != NULL; hp = hp->hi_next) 73290792Sgshapiro { 73390792Sgshapiro if (hp->hi_ptr == ptr) 73490792Sgshapiro return; 73590792Sgshapiro } 73690792Sgshapiro sm_abort("sm_heap_checkptr(%p): bad ptr (%s:%d)", ptr, tag, num); 73790792Sgshapiro} 73890792Sgshapiro 73990792Sgshapiro/* 74090792Sgshapiro** SM_HEAP_REPORT -- output "map" of used heap. 74190792Sgshapiro** 74290792Sgshapiro** Parameters: 74390792Sgshapiro** stream -- the file pointer to write to. 74490792Sgshapiro** verbosity -- how much info? 74590792Sgshapiro** 74690792Sgshapiro** Returns: 74790792Sgshapiro** none. 74890792Sgshapiro*/ 74990792Sgshapiro 75090792Sgshapirovoid 75190792Sgshapirosm_heap_report(stream, verbosity) 75290792Sgshapiro SM_FILE_T *stream; 75390792Sgshapiro int verbosity; 75490792Sgshapiro{ 75590792Sgshapiro int i; 75690792Sgshapiro unsigned long group0total, group1total, otherstotal, grandtotal; 75790792Sgshapiro 75890792Sgshapiro if (!HEAP_CHECK || verbosity <= 0) 75990792Sgshapiro return; 76090792Sgshapiro group0total = group1total = otherstotal = grandtotal = 0; 76190792Sgshapiro for (i = 0; i < sizeof(SmHeapTable) / sizeof(SmHeapTable[0]); ++i) 76290792Sgshapiro { 76390792Sgshapiro SM_HEAP_ITEM_T *hi = SmHeapTable[i]; 76490792Sgshapiro 76590792Sgshapiro while (hi != NULL) 76690792Sgshapiro { 76790792Sgshapiro if (verbosity > 2 76890792Sgshapiro || (verbosity > 1 && hi->hi_group != 0)) 76990792Sgshapiro { 77090792Sgshapiro sm_io_fprintf(stream, SM_TIME_DEFAULT, 77190792Sgshapiro "%4d %*lx %7lu bytes", 77290792Sgshapiro hi->hi_group, 77390792Sgshapiro (int) sizeof(void *) * 2, 77490792Sgshapiro (long)hi->hi_ptr, 77590792Sgshapiro (unsigned long)hi->hi_size); 77690792Sgshapiro if (hi->hi_tag != NULL) 77790792Sgshapiro { 77890792Sgshapiro sm_io_fprintf(stream, SM_TIME_DEFAULT, 77990792Sgshapiro " %s", 78090792Sgshapiro hi->hi_tag); 78190792Sgshapiro if (hi->hi_num) 78290792Sgshapiro { 78390792Sgshapiro sm_io_fprintf(stream, 78490792Sgshapiro SM_TIME_DEFAULT, 78590792Sgshapiro ":%d", 78690792Sgshapiro hi->hi_num); 78790792Sgshapiro } 78890792Sgshapiro } 78990792Sgshapiro sm_io_fprintf(stream, SM_TIME_DEFAULT, "\n"); 79090792Sgshapiro } 79190792Sgshapiro switch (hi->hi_group) 79290792Sgshapiro { 79390792Sgshapiro case 0: 79490792Sgshapiro group0total += hi->hi_size; 79590792Sgshapiro break; 79690792Sgshapiro case 1: 79790792Sgshapiro group1total += hi->hi_size; 79890792Sgshapiro break; 79990792Sgshapiro default: 80090792Sgshapiro otherstotal += hi->hi_size; 80190792Sgshapiro break; 80290792Sgshapiro } 80390792Sgshapiro grandtotal += hi->hi_size; 80490792Sgshapiro hi = hi->hi_next; 80590792Sgshapiro } 80690792Sgshapiro } 80790792Sgshapiro sm_io_fprintf(stream, SM_TIME_DEFAULT, 80890792Sgshapiro "heap max=%lu, total=%lu, ", 80990792Sgshapiro (unsigned long) SmHeapMaxTotal, grandtotal); 81090792Sgshapiro sm_io_fprintf(stream, SM_TIME_DEFAULT, 81190792Sgshapiro "group 0=%lu, group 1=%lu, others=%lu\n", 81290792Sgshapiro group0total, group1total, otherstotal); 81390792Sgshapiro if (grandtotal != SmHeapTotal) 81490792Sgshapiro { 81590792Sgshapiro sm_io_fprintf(stream, SM_TIME_DEFAULT, 81690792Sgshapiro "BUG => SmHeapTotal: got %lu, expected %lu\n", 81790792Sgshapiro (unsigned long) SmHeapTotal, grandtotal); 81890792Sgshapiro } 81990792Sgshapiro} 82090792Sgshapiro#endif /* !SM_HEAP_CHECK */ 821