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