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> |
---|
11 | SM_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 |
---|
43 | SM_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 | |
---|
48 | const SM_EXC_TYPE_T SmHeapOutOfMemoryType = |
---|
49 | { |
---|
50 | SmExcTypeMagic, |
---|
51 | "F:sm.heap", |
---|
52 | "", |
---|
53 | sm_etype_printf, |
---|
54 | "out of memory", |
---|
55 | }; |
---|
56 | |
---|
57 | SM_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 | |
---|
92 | void * |
---|
93 | sm_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 | |
---|
118 | void * |
---|
119 | sm_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 | |
---|
141 | void * |
---|
142 | sm_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 | |
---|
168 | void * |
---|
169 | sm_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 | |
---|
192 | void |
---|
193 | sm_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 | |
---|
214 | int SmHeapGroup = 1; |
---|
215 | int 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 | |
---|
222 | size_t SmHeapTotal = 0; |
---|
223 | |
---|
224 | /* |
---|
225 | ** High water mark: the most that SmHeapTotal has ever been. |
---|
226 | */ |
---|
227 | |
---|
228 | size_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 | |
---|
236 | SM_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 | |
---|
244 | typedef struct sm_heap_item SM_HEAP_ITEM_T; |
---|
245 | struct 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 |
---|
256 | static 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 | |
---|
265 | static 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 | |
---|
302 | static int |
---|
303 | ptrhash(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 | |
---|
357 | void * |
---|
358 | sm_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 | |
---|
411 | void * |
---|
412 | sm_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 | |
---|
468 | bool |
---|
469 | sm_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 | |
---|
521 | void * |
---|
522 | sm_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 | |
---|
589 | void * |
---|
590 | sm_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 | |
---|
656 | void |
---|
657 | sm_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 | |
---|
718 | void |
---|
719 | sm_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 | |
---|
749 | void |
---|
750 | sm_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 */ |
---|