Line data Source code
1 : /*
2 : * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
3 : * Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.
4 : * Copyright (c) 1997 by Silicon Graphics. All rights reserved.
5 : * Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
6 : * Copyright (C) 2007 Free Software Foundation, Inc
7 : *
8 : * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
9 : * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
10 : *
11 : * Permission is hereby granted to use or copy this program
12 : * for any purpose, provided the above notices are retained on all copies.
13 : * Permission to modify the code and to distribute modified code is granted,
14 : * provided the above notices are retained, and a notice that the code was
15 : * modified is included with the above copyright notice.
16 : */
17 :
18 : #include "private/dbg_mlc.h"
19 :
20 : #ifndef MSWINCE
21 : # include <errno.h>
22 : #endif
23 : #include <string.h>
24 :
25 : #ifndef SHORT_DBG_HDRS
26 : /* Check whether object with base pointer p has debugging info. */
27 : /* p is assumed to point to a legitimate object in our part */
28 : /* of the heap. */
29 : /* This excludes the check as to whether the back pointer is */
30 : /* odd, which is added by the GC_HAS_DEBUG_INFO macro. */
31 : /* Note that if DBG_HDRS_ALL is set, uncollectable objects */
32 : /* on free lists may not have debug information set. Thus it's */
33 : /* not always safe to return TRUE (1), even if the client does */
34 : /* its part. Return -1 if the object with debug info has been */
35 : /* marked as deallocated. */
36 0 : GC_INNER int GC_has_other_debug_info(ptr_t p)
37 : {
38 0 : ptr_t body = (ptr_t)((oh *)p + 1);
39 0 : word sz = GC_size(p);
40 :
41 0 : if (HBLKPTR(p) != HBLKPTR((ptr_t)body)
42 : || sz < DEBUG_BYTES + EXTRA_BYTES) {
43 0 : return 0;
44 : }
45 0 : if (((oh *)p) -> oh_sf != (START_FLAG ^ (word)body)
46 0 : && ((word *)p)[BYTES_TO_WORDS(sz)-1] != (END_FLAG ^ (word)body)) {
47 0 : return 0;
48 : }
49 0 : if (((oh *)p)->oh_sz == sz) {
50 : /* Object may have had debug info, but has been deallocated */
51 0 : return -1;
52 : }
53 0 : return 1;
54 : }
55 : #endif /* !SHORT_DBG_HDRS */
56 :
57 : #ifdef KEEP_BACK_PTRS
58 :
59 : # include <stdlib.h>
60 :
61 : # if defined(__GLIBC__) || defined(SOLARIS) \
62 : || defined(HPUX) || defined(IRIX5) || defined(OSF1)
63 : # define RANDOM() random()
64 : # else
65 : # define RANDOM() (long)rand()
66 : # endif
67 :
68 : /* Store back pointer to source in dest, if that appears to be possible. */
69 : /* This is not completely safe, since we may mistakenly conclude that */
70 : /* dest has a debugging wrapper. But the error probability is very */
71 : /* small, and this shouldn't be used in production code. */
72 : /* We assume that dest is the real base pointer. Source will usually */
73 : /* be a pointer to the interior of an object. */
74 : GC_INNER void GC_store_back_pointer(ptr_t source, ptr_t dest)
75 : {
76 : if (GC_HAS_DEBUG_INFO(dest)) {
77 : ((oh *)dest) -> oh_back_ptr = HIDE_BACK_PTR(source);
78 : }
79 : }
80 :
81 : GC_INNER void GC_marked_for_finalization(ptr_t dest)
82 : {
83 : GC_store_back_pointer(MARKED_FOR_FINALIZATION, dest);
84 : }
85 :
86 : /* Store information about the object referencing dest in *base_p */
87 : /* and *offset_p. */
88 : /* source is root ==> *base_p = address, *offset_p = 0 */
89 : /* source is heap object ==> *base_p != 0, *offset_p = offset */
90 : /* Returns 1 on success, 0 if source couldn't be determined. */
91 : /* Dest can be any address within a heap object. */
92 : GC_API GC_ref_kind GC_CALL GC_get_back_ptr_info(void *dest, void **base_p,
93 : size_t *offset_p)
94 : {
95 : oh * hdr = (oh *)GC_base(dest);
96 : ptr_t bp;
97 : ptr_t bp_base;
98 :
99 : # ifdef LINT2
100 : /* Explicitly instruct the code analysis tool that */
101 : /* GC_get_back_ptr_info is not expected to be called with an */
102 : /* incorrect "dest" value. */
103 : if (!hdr) ABORT("Invalid GC_get_back_ptr_info argument");
104 : # endif
105 : if (!GC_HAS_DEBUG_INFO((ptr_t) hdr)) return GC_NO_SPACE;
106 : bp = GC_REVEAL_POINTER(hdr -> oh_back_ptr);
107 : if (MARKED_FOR_FINALIZATION == bp) return GC_FINALIZER_REFD;
108 : if (MARKED_FROM_REGISTER == bp) return GC_REFD_FROM_REG;
109 : if (NOT_MARKED == bp) return GC_UNREFERENCED;
110 : # if ALIGNMENT == 1
111 : /* Heuristically try to fix off by 1 errors we introduced by */
112 : /* insisting on even addresses. */
113 : {
114 : ptr_t alternate_ptr = bp + 1;
115 : ptr_t target = *(ptr_t *)bp;
116 : ptr_t alternate_target = *(ptr_t *)alternate_ptr;
117 :
118 : if (alternate_target >= GC_least_plausible_heap_addr
119 : && alternate_target <= GC_greatest_plausible_heap_addr
120 : && (target < GC_least_plausible_heap_addr
121 : || target > GC_greatest_plausible_heap_addr)) {
122 : bp = alternate_ptr;
123 : }
124 : }
125 : # endif
126 : bp_base = GC_base(bp);
127 : if (0 == bp_base) {
128 : *base_p = bp;
129 : *offset_p = 0;
130 : return GC_REFD_FROM_ROOT;
131 : } else {
132 : if (GC_HAS_DEBUG_INFO(bp_base)) bp_base += sizeof(oh);
133 : *base_p = bp_base;
134 : *offset_p = bp - bp_base;
135 : return GC_REFD_FROM_HEAP;
136 : }
137 : }
138 :
139 : /* Generate a random heap address. */
140 : /* The resulting address is in the heap, but */
141 : /* not necessarily inside a valid object. */
142 : GC_API void * GC_CALL GC_generate_random_heap_address(void)
143 : {
144 : size_t i;
145 : word heap_offset = RANDOM();
146 : if (GC_heapsize > RAND_MAX) {
147 : heap_offset *= RAND_MAX;
148 : heap_offset += RANDOM();
149 : }
150 : heap_offset %= GC_heapsize;
151 : /* This doesn't yield a uniform distribution, especially if */
152 : /* e.g. RAND_MAX = 1.5* GC_heapsize. But for typical cases, */
153 : /* it's not too bad. */
154 : for (i = 0; i < GC_n_heap_sects; ++ i) {
155 : size_t size = GC_heap_sects[i].hs_bytes;
156 : if (heap_offset < size) {
157 : return GC_heap_sects[i].hs_start + heap_offset;
158 : } else {
159 : heap_offset -= size;
160 : }
161 : }
162 : ABORT("GC_generate_random_heap_address: size inconsistency");
163 : /*NOTREACHED*/
164 : return 0;
165 : }
166 :
167 : /* Generate a random address inside a valid marked heap object. */
168 : GC_API void * GC_CALL GC_generate_random_valid_address(void)
169 : {
170 : ptr_t result;
171 : ptr_t base;
172 : do {
173 : result = GC_generate_random_heap_address();
174 : base = GC_base(result);
175 : } while (base == 0 || !GC_is_marked(base));
176 : return result;
177 : }
178 :
179 : /* Print back trace for p */
180 : GC_API void GC_CALL GC_print_backtrace(void *p)
181 : {
182 : void *current = p;
183 : int i;
184 : GC_ref_kind source;
185 : size_t offset;
186 : void *base;
187 :
188 : GC_print_heap_obj(GC_base(current));
189 : GC_err_printf("\n");
190 : for (i = 0; ; ++i) {
191 : source = GC_get_back_ptr_info(current, &base, &offset);
192 : if (GC_UNREFERENCED == source) {
193 : GC_err_printf("Reference could not be found\n");
194 : goto out;
195 : }
196 : if (GC_NO_SPACE == source) {
197 : GC_err_printf("No debug info in object: Can't find reference\n");
198 : goto out;
199 : }
200 : GC_err_printf("Reachable via %d levels of pointers from ", i);
201 : switch(source) {
202 : case GC_REFD_FROM_ROOT:
203 : GC_err_printf("root at %p\n\n", base);
204 : goto out;
205 : case GC_REFD_FROM_REG:
206 : GC_err_printf("root in register\n\n");
207 : goto out;
208 : case GC_FINALIZER_REFD:
209 : GC_err_printf("list of finalizable objects\n\n");
210 : goto out;
211 : case GC_REFD_FROM_HEAP:
212 : GC_err_printf("offset %ld in object:\n", (unsigned long)offset);
213 : /* Take GC_base(base) to get real base, i.e. header. */
214 : GC_print_heap_obj(GC_base(base));
215 : GC_err_printf("\n");
216 : break;
217 : default:
218 : GC_err_printf("INTERNAL ERROR: UNEXPECTED SOURCE!!!!\n");
219 : goto out;
220 : }
221 : current = base;
222 : }
223 : out:;
224 : }
225 :
226 : /* Force a garbage collection and generate a backtrace from a */
227 : /* random heap address. */
228 : GC_INNER void GC_generate_random_backtrace_no_gc(void)
229 : {
230 : void * current;
231 : current = GC_generate_random_valid_address();
232 : GC_printf("\n****Chosen address %p in object\n", current);
233 : GC_print_backtrace(current);
234 : }
235 :
236 : GC_API void GC_CALL GC_generate_random_backtrace(void)
237 : {
238 : if (GC_try_to_collect(GC_never_stop_func) == 0) {
239 : GC_err_printf("Cannot generate a backtrace: "
240 : "garbage collection is disabled!\n");
241 : return;
242 : }
243 : GC_generate_random_backtrace_no_gc();
244 : }
245 :
246 : #endif /* KEEP_BACK_PTRS */
247 :
248 : # define CROSSES_HBLK(p, sz) \
249 : (((word)(p + sizeof(oh) + sz - 1) ^ (word)p) >= HBLKSIZE)
250 :
251 : /* Store debugging info into p. Return displaced pointer. */
252 : /* This version assumes we do hold the allocation lock. */
253 0 : STATIC ptr_t GC_store_debug_info_inner(ptr_t p, word sz, const char *string,
254 : int linenum)
255 : {
256 0 : word * result = (word *)((oh *)p + 1);
257 :
258 : GC_ASSERT(GC_size(p) >= sizeof(oh) + sz);
259 : GC_ASSERT(!(SMALL_OBJ(sz) && CROSSES_HBLK(p, sz)));
260 : # ifdef KEEP_BACK_PTRS
261 : ((oh *)p) -> oh_back_ptr = HIDE_BACK_PTR(NOT_MARKED);
262 : # endif
263 : # ifdef MAKE_BACK_GRAPH
264 : ((oh *)p) -> oh_bg_ptr = HIDE_BACK_PTR((ptr_t)0);
265 : # endif
266 0 : ((oh *)p) -> oh_string = string;
267 0 : ((oh *)p) -> oh_int = (word)linenum;
268 : # ifndef SHORT_DBG_HDRS
269 0 : ((oh *)p) -> oh_sz = sz;
270 0 : ((oh *)p) -> oh_sf = START_FLAG ^ (word)result;
271 0 : ((word *)p)[BYTES_TO_WORDS(GC_size(p))-1] =
272 0 : result[SIMPLE_ROUNDED_UP_WORDS(sz)] = END_FLAG ^ (word)result;
273 : # endif
274 0 : return((ptr_t)result);
275 : }
276 :
277 0 : GC_INNER ptr_t GC_store_debug_info(ptr_t p, word sz, const char *string,
278 : int linenum)
279 : {
280 : ptr_t result;
281 : DCL_LOCK_STATE;
282 :
283 0 : LOCK();
284 0 : result = GC_store_debug_info_inner(p, sz, string, linenum);
285 0 : UNLOCK();
286 0 : return result;
287 : }
288 :
289 : #ifndef SHORT_DBG_HDRS
290 : /* Check the object with debugging info at ohdr. */
291 : /* Return NULL if it's OK. Else return clobbered */
292 : /* address. */
293 0 : STATIC ptr_t GC_check_annotated_obj(oh *ohdr)
294 : {
295 0 : ptr_t body = (ptr_t)(ohdr + 1);
296 0 : word gc_sz = GC_size((ptr_t)ohdr);
297 0 : if (ohdr -> oh_sz + DEBUG_BYTES > gc_sz) {
298 0 : return((ptr_t)(&(ohdr -> oh_sz)));
299 : }
300 0 : if (ohdr -> oh_sf != (START_FLAG ^ (word)body)) {
301 0 : return((ptr_t)(&(ohdr -> oh_sf)));
302 : }
303 0 : if (((word *)ohdr)[BYTES_TO_WORDS(gc_sz)-1] != (END_FLAG ^ (word)body)) {
304 0 : return((ptr_t)((word *)ohdr + BYTES_TO_WORDS(gc_sz)-1));
305 : }
306 0 : if (((word *)body)[SIMPLE_ROUNDED_UP_WORDS(ohdr -> oh_sz)]
307 0 : != (END_FLAG ^ (word)body)) {
308 0 : return((ptr_t)((word *)body + SIMPLE_ROUNDED_UP_WORDS(ohdr->oh_sz)));
309 : }
310 0 : return(0);
311 : }
312 : #endif /* !SHORT_DBG_HDRS */
313 :
314 : STATIC GC_describe_type_fn GC_describe_type_fns[MAXOBJKINDS] = {0};
315 :
316 0 : GC_API void GC_CALL GC_register_describe_type_fn(int kind,
317 : GC_describe_type_fn fn)
318 : {
319 0 : GC_describe_type_fns[kind] = fn;
320 0 : }
321 :
322 : /* Print a type description for the object whose client-visible address */
323 : /* is p. */
324 0 : STATIC void GC_print_type(ptr_t p)
325 : {
326 0 : hdr * hhdr = GC_find_header(p);
327 : char buffer[GC_TYPE_DESCR_LEN + 1];
328 0 : int kind = hhdr -> hb_obj_kind;
329 :
330 0 : if (0 != GC_describe_type_fns[kind] && GC_is_marked(GC_base(p))) {
331 : /* This should preclude free list objects except with */
332 : /* thread-local allocation. */
333 0 : buffer[GC_TYPE_DESCR_LEN] = 0;
334 0 : (GC_describe_type_fns[kind])(p, buffer);
335 : GC_ASSERT(buffer[GC_TYPE_DESCR_LEN] == 0);
336 0 : GC_err_puts(buffer);
337 : } else {
338 0 : switch(kind) {
339 : case PTRFREE:
340 0 : GC_err_puts("PTRFREE");
341 0 : break;
342 : case NORMAL:
343 0 : GC_err_puts("NORMAL");
344 0 : break;
345 : case UNCOLLECTABLE:
346 0 : GC_err_puts("UNCOLLECTABLE");
347 0 : break;
348 : # ifdef ATOMIC_UNCOLLECTABLE
349 : case AUNCOLLECTABLE:
350 0 : GC_err_puts("ATOMIC UNCOLLECTABLE");
351 0 : break;
352 : # endif
353 : case STUBBORN:
354 0 : GC_err_puts("STUBBORN");
355 0 : break;
356 : default:
357 0 : GC_err_printf("kind=%d descr=0x%lx", kind,
358 : (unsigned long)(hhdr -> hb_descr));
359 : }
360 : }
361 0 : }
362 :
363 : #define GET_OH_LINENUM(ohdr) ((int)(ohdr)->oh_int)
364 :
365 : /* Print a human-readable description of the object to stderr. p points */
366 : /* to somewhere inside an object with the debugging info. */
367 0 : STATIC void GC_print_obj(ptr_t p)
368 : {
369 0 : oh * ohdr = (oh *)GC_base(p);
370 :
371 : GC_ASSERT(I_DONT_HOLD_LOCK());
372 : # ifdef LINT2
373 : if (!ohdr) ABORT("Invalid GC_print_obj argument");
374 : # endif
375 0 : GC_err_printf("%p (", ((ptr_t)ohdr + sizeof(oh)));
376 0 : GC_err_puts(ohdr -> oh_string);
377 : # ifdef SHORT_DBG_HDRS
378 : GC_err_printf(":%d, ", GET_OH_LINENUM(ohdr));
379 : # else
380 0 : GC_err_printf(":%d, sz=%lu, ",
381 : GET_OH_LINENUM(ohdr), (unsigned long)(ohdr -> oh_sz));
382 : # endif
383 0 : GC_print_type((ptr_t)(ohdr + 1));
384 0 : GC_err_puts(")\n");
385 : PRINT_CALL_CHAIN(ohdr);
386 0 : }
387 :
388 0 : STATIC void GC_debug_print_heap_obj_proc(ptr_t p)
389 : {
390 : GC_ASSERT(I_DONT_HOLD_LOCK());
391 0 : if (GC_HAS_DEBUG_INFO(p)) {
392 0 : GC_print_obj(p);
393 : } else {
394 0 : GC_default_print_heap_obj_proc(p);
395 : }
396 0 : }
397 :
398 : #ifndef SHORT_DBG_HDRS
399 : /* Use GC_err_printf and friends to print a description of the object */
400 : /* whose client-visible address is p, and which was smashed at */
401 : /* clobbered_addr. */
402 0 : STATIC void GC_print_smashed_obj(const char *msg, ptr_t p,
403 : ptr_t clobbered_addr)
404 : {
405 0 : oh * ohdr = (oh *)GC_base(p);
406 :
407 : GC_ASSERT(I_DONT_HOLD_LOCK());
408 : # ifdef LINT2
409 : if (!ohdr) ABORT("Invalid GC_print_smashed_obj argument");
410 : # endif
411 0 : if (clobbered_addr <= (ptr_t)(&(ohdr -> oh_sz))
412 0 : || ohdr -> oh_string == 0) {
413 0 : GC_err_printf(
414 : "%s %p in or near object at %p(<smashed>, appr. sz = %lu)\n",
415 : msg, clobbered_addr, p,
416 : (unsigned long)(GC_size((ptr_t)ohdr) - DEBUG_BYTES));
417 : } else {
418 0 : GC_err_printf("%s %p in or near object at %p (%s:%d, sz=%lu)\n",
419 : msg, clobbered_addr, p,
420 0 : (word)(ohdr -> oh_string) < HBLKSIZE ? "(smashed string)" :
421 0 : ohdr -> oh_string[0] == '\0' ? "EMPTY(smashed?)" :
422 : ohdr -> oh_string,
423 : GET_OH_LINENUM(ohdr), (unsigned long)(ohdr -> oh_sz));
424 : PRINT_CALL_CHAIN(ohdr);
425 : }
426 0 : }
427 : #endif
428 :
429 : #ifndef SHORT_DBG_HDRS
430 : STATIC void GC_check_heap_proc (void);
431 : STATIC void GC_print_all_smashed_proc (void);
432 : #else
433 : STATIC void GC_do_nothing(void) {}
434 : #endif
435 :
436 0 : GC_INNER void GC_start_debugging(void)
437 : {
438 : # ifndef SHORT_DBG_HDRS
439 0 : GC_check_heap = GC_check_heap_proc;
440 0 : GC_print_all_smashed = GC_print_all_smashed_proc;
441 : # else
442 : GC_check_heap = GC_do_nothing;
443 : GC_print_all_smashed = GC_do_nothing;
444 : # endif
445 0 : GC_print_heap_obj = GC_debug_print_heap_obj_proc;
446 0 : GC_debugging_started = TRUE;
447 0 : GC_register_displacement((word)sizeof(oh));
448 0 : }
449 :
450 : size_t GC_debug_header_size = sizeof(oh);
451 :
452 0 : GC_API void GC_CALL GC_debug_register_displacement(size_t offset)
453 : {
454 0 : GC_register_displacement(offset);
455 0 : GC_register_displacement((word)sizeof(oh) + offset);
456 0 : }
457 :
458 0 : GC_API void * GC_CALL GC_debug_malloc(size_t lb, GC_EXTRA_PARAMS)
459 : {
460 : void * result;
461 : /* Note that according to malloc() specification, if size is 0 then */
462 : /* malloc() returns either NULL, or a unique pointer value that can */
463 : /* later be successfully passed to free(). We always do the latter. */
464 0 : result = GC_malloc(lb + DEBUG_BYTES);
465 :
466 0 : if (result == 0) {
467 0 : GC_err_printf("GC_debug_malloc(%lu) returning NULL (",
468 : (unsigned long) lb);
469 0 : GC_err_puts(s);
470 0 : GC_err_printf(":%ld)\n", (unsigned long)i);
471 0 : return(0);
472 : }
473 0 : if (!GC_debugging_started) {
474 0 : GC_start_debugging();
475 : }
476 : ADD_CALL_CHAIN(result, ra);
477 0 : return (GC_store_debug_info(result, (word)lb, s, i));
478 : }
479 :
480 0 : GC_API void * GC_CALL GC_debug_malloc_ignore_off_page(size_t lb,
481 : GC_EXTRA_PARAMS)
482 : {
483 0 : void * result = GC_malloc_ignore_off_page(lb + DEBUG_BYTES);
484 :
485 0 : if (result == 0) {
486 0 : GC_err_printf("GC_debug_malloc_ignore_off_page(%lu) returning NULL (",
487 : (unsigned long) lb);
488 0 : GC_err_puts(s);
489 0 : GC_err_printf(":%lu)\n", (unsigned long)i);
490 0 : return(0);
491 : }
492 0 : if (!GC_debugging_started) {
493 0 : GC_start_debugging();
494 : }
495 : ADD_CALL_CHAIN(result, ra);
496 0 : return (GC_store_debug_info(result, (word)lb, s, i));
497 : }
498 :
499 0 : GC_API void * GC_CALL GC_debug_malloc_atomic_ignore_off_page(size_t lb,
500 : GC_EXTRA_PARAMS)
501 : {
502 0 : void * result = GC_malloc_atomic_ignore_off_page(lb + DEBUG_BYTES);
503 :
504 0 : if (result == 0) {
505 0 : GC_err_printf("GC_debug_malloc_atomic_ignore_off_page(%lu)"
506 : " returning NULL (", (unsigned long)lb);
507 0 : GC_err_puts(s);
508 0 : GC_err_printf(":%lu)\n", (unsigned long)i);
509 0 : return(0);
510 : }
511 0 : if (!GC_debugging_started) {
512 0 : GC_start_debugging();
513 : }
514 : ADD_CALL_CHAIN(result, ra);
515 0 : return (GC_store_debug_info(result, (word)lb, s, i));
516 : }
517 :
518 : #ifdef DBG_HDRS_ALL
519 : /* An allocation function for internal use. Normally internally */
520 : /* allocated objects do not have debug information. But in this */
521 : /* case, we need to make sure that all objects have debug headers. */
522 : /* We assume debugging was started in collector initialization, and */
523 : /* we already hold the GC lock. */
524 : GC_INNER void * GC_debug_generic_malloc_inner(size_t lb, int k)
525 : {
526 : void * result = GC_generic_malloc_inner(lb + DEBUG_BYTES, k);
527 :
528 : if (result == 0) {
529 : GC_err_printf("GC internal allocation (%lu bytes) returning NULL\n",
530 : (unsigned long) lb);
531 : return(0);
532 : }
533 : ADD_CALL_CHAIN(result, GC_RETURN_ADDR);
534 : return (GC_store_debug_info_inner(result, (word)lb, "INTERNAL", 0));
535 : }
536 :
537 : GC_INNER void * GC_debug_generic_malloc_inner_ignore_off_page(size_t lb,
538 : int k)
539 : {
540 : void * result = GC_generic_malloc_inner_ignore_off_page(
541 : lb + DEBUG_BYTES, k);
542 :
543 : if (result == 0) {
544 : GC_err_printf("GC internal allocation (%lu bytes) returning NULL\n",
545 : (unsigned long) lb);
546 : return(0);
547 : }
548 : ADD_CALL_CHAIN(result, GC_RETURN_ADDR);
549 : return (GC_store_debug_info_inner(result, (word)lb, "INTERNAL", 0));
550 : }
551 : #endif /* DBG_HDRS_ALL */
552 :
553 : #ifdef STUBBORN_ALLOC
554 : GC_API void * GC_CALL GC_debug_malloc_stubborn(size_t lb, GC_EXTRA_PARAMS)
555 : {
556 : void * result = GC_malloc_stubborn(lb + DEBUG_BYTES);
557 :
558 : if (result == 0) {
559 : GC_err_printf("GC_debug_malloc(%lu) returning NULL (",
560 : (unsigned long) lb);
561 : GC_err_puts(s);
562 : GC_err_printf(":%lu)\n", (unsigned long)i);
563 : return(0);
564 : }
565 : if (!GC_debugging_started) {
566 : GC_start_debugging();
567 : }
568 : ADD_CALL_CHAIN(result, ra);
569 : return (GC_store_debug_info(result, (word)lb, s, i));
570 : }
571 :
572 : GC_API void GC_CALL GC_debug_change_stubborn(void *p)
573 : {
574 : void * q = GC_base(p);
575 : hdr * hhdr;
576 :
577 : if (q == 0) {
578 : GC_err_printf("Bad argument: %p to GC_debug_change_stubborn\n", p);
579 : ABORT("GC_debug_change_stubborn: bad arg");
580 : }
581 : hhdr = HDR(q);
582 : if (hhdr -> hb_obj_kind != STUBBORN) {
583 : GC_err_printf("GC_debug_change_stubborn arg not stubborn: %p\n", p);
584 : ABORT("GC_debug_change_stubborn: arg not stubborn");
585 : }
586 : GC_change_stubborn(q);
587 : }
588 :
589 : GC_API void GC_CALL GC_debug_end_stubborn_change(void *p)
590 : {
591 : void * q = GC_base(p);
592 : hdr * hhdr;
593 :
594 : if (q == 0) {
595 : GC_err_printf("Bad argument: %p to GC_debug_end_stubborn_change\n", p);
596 : ABORT("GC_debug_end_stubborn_change: bad arg");
597 : }
598 : hhdr = HDR(q);
599 : if (hhdr -> hb_obj_kind != STUBBORN) {
600 : GC_err_printf("debug_end_stubborn_change arg not stubborn: %p\n", p);
601 : ABORT("GC_debug_end_stubborn_change: arg not stubborn");
602 : }
603 : GC_end_stubborn_change(q);
604 : }
605 :
606 : #else /* !STUBBORN_ALLOC */
607 :
608 0 : GC_API void * GC_CALL GC_debug_malloc_stubborn(size_t lb, GC_EXTRA_PARAMS)
609 : {
610 0 : return GC_debug_malloc(lb, OPT_RA s, i);
611 : }
612 :
613 : /*ARGSUSED*/
614 0 : GC_API void GC_CALL GC_debug_change_stubborn(void *p) {}
615 :
616 : /*ARGSUSED*/
617 0 : GC_API void GC_CALL GC_debug_end_stubborn_change(void *p) {}
618 : #endif /* !STUBBORN_ALLOC */
619 :
620 0 : GC_API void * GC_CALL GC_debug_malloc_atomic(size_t lb, GC_EXTRA_PARAMS)
621 : {
622 0 : void * result = GC_malloc_atomic(lb + DEBUG_BYTES);
623 :
624 0 : if (result == 0) {
625 0 : GC_err_printf("GC_debug_malloc_atomic(%lu) returning NULL (",
626 : (unsigned long) lb);
627 0 : GC_err_puts(s);
628 0 : GC_err_printf(":%lu)\n", (unsigned long)i);
629 0 : return(0);
630 : }
631 0 : if (!GC_debugging_started) {
632 0 : GC_start_debugging();
633 : }
634 : ADD_CALL_CHAIN(result, ra);
635 0 : return (GC_store_debug_info(result, (word)lb, s, i));
636 : }
637 :
638 0 : GC_API char * GC_CALL GC_debug_strdup(const char *str, GC_EXTRA_PARAMS)
639 : {
640 : char *copy;
641 : size_t lb;
642 0 : if (str == NULL) {
643 0 : if (GC_find_leak)
644 0 : GC_err_printf("strdup(NULL) behavior is undefined\n");
645 0 : return NULL;
646 : }
647 :
648 0 : lb = strlen(str) + 1;
649 0 : copy = GC_debug_malloc_atomic(lb, OPT_RA s, i);
650 0 : if (copy == NULL) {
651 : # ifndef MSWINCE
652 0 : errno = ENOMEM;
653 : # endif
654 0 : return NULL;
655 : }
656 : # ifndef MSWINCE
657 0 : strcpy(copy, str);
658 : # else
659 : /* strcpy() is deprecated in WinCE */
660 : memcpy(copy, str, lb);
661 : # endif
662 0 : return copy;
663 : }
664 :
665 0 : GC_API char * GC_CALL GC_debug_strndup(const char *str, size_t size,
666 : GC_EXTRA_PARAMS)
667 : {
668 : char *copy;
669 0 : size_t len = strlen(str); /* str is expected to be non-NULL */
670 0 : if (len > size)
671 0 : len = size;
672 0 : copy = GC_debug_malloc_atomic(len + 1, OPT_RA s, i);
673 0 : if (copy == NULL) {
674 : # ifndef MSWINCE
675 0 : errno = ENOMEM;
676 : # endif
677 0 : return NULL;
678 : }
679 0 : BCOPY(str, copy, len);
680 0 : copy[len] = '\0';
681 0 : return copy;
682 : }
683 :
684 : #ifdef GC_REQUIRE_WCSDUP
685 : # include <wchar.h> /* for wcslen() */
686 :
687 : GC_API wchar_t * GC_CALL GC_debug_wcsdup(const wchar_t *str, GC_EXTRA_PARAMS)
688 : {
689 : size_t lb = (wcslen(str) + 1) * sizeof(wchar_t);
690 : wchar_t *copy = GC_debug_malloc_atomic(lb, OPT_RA s, i);
691 : if (copy == NULL) {
692 : # ifndef MSWINCE
693 : errno = ENOMEM;
694 : # endif
695 : return NULL;
696 : }
697 : BCOPY(str, copy, lb);
698 : return copy;
699 : }
700 : #endif /* GC_REQUIRE_WCSDUP */
701 :
702 0 : GC_API void * GC_CALL GC_debug_malloc_uncollectable(size_t lb,
703 : GC_EXTRA_PARAMS)
704 : {
705 0 : void * result = GC_malloc_uncollectable(lb + UNCOLLECTABLE_DEBUG_BYTES);
706 :
707 0 : if (result == 0) {
708 0 : GC_err_printf("GC_debug_malloc_uncollectable(%lu) returning NULL (",
709 : (unsigned long) lb);
710 0 : GC_err_puts(s);
711 0 : GC_err_printf(":%lu)\n", (unsigned long)i);
712 0 : return(0);
713 : }
714 0 : if (!GC_debugging_started) {
715 0 : GC_start_debugging();
716 : }
717 : ADD_CALL_CHAIN(result, ra);
718 0 : return (GC_store_debug_info(result, (word)lb, s, i));
719 : }
720 :
721 : #ifdef ATOMIC_UNCOLLECTABLE
722 0 : GC_API void * GC_CALL GC_debug_malloc_atomic_uncollectable(size_t lb,
723 : GC_EXTRA_PARAMS)
724 : {
725 : void * result =
726 0 : GC_malloc_atomic_uncollectable(lb + UNCOLLECTABLE_DEBUG_BYTES);
727 :
728 0 : if (result == 0) {
729 0 : GC_err_printf(
730 : "GC_debug_malloc_atomic_uncollectable(%lu) returning NULL (",
731 : (unsigned long) lb);
732 0 : GC_err_puts(s);
733 0 : GC_err_printf(":%lu)\n", (unsigned long)i);
734 0 : return(0);
735 : }
736 0 : if (!GC_debugging_started) {
737 0 : GC_start_debugging();
738 : }
739 : ADD_CALL_CHAIN(result, ra);
740 0 : return (GC_store_debug_info(result, (word)lb, s, i));
741 : }
742 : #endif /* ATOMIC_UNCOLLECTABLE */
743 :
744 : #ifndef GC_FREED_MEM_MARKER
745 : # if CPP_WORDSZ == 32
746 : # define GC_FREED_MEM_MARKER 0xdeadbeef
747 : # else
748 : # define GC_FREED_MEM_MARKER GC_WORD_C(0xEFBEADDEdeadbeef)
749 : # endif
750 : #endif
751 :
752 0 : GC_API void GC_CALL GC_debug_free(void * p)
753 : {
754 : ptr_t base;
755 0 : if (0 == p) return;
756 :
757 0 : base = GC_base(p);
758 0 : if (base == 0) {
759 0 : GC_err_printf("Attempt to free invalid pointer %p\n", p);
760 0 : ABORT("Invalid pointer passed to free()");
761 : }
762 0 : if ((ptr_t)p - (ptr_t)base != sizeof(oh)) {
763 0 : GC_err_printf(
764 : "GC_debug_free called on pointer %p w/o debugging info\n", p);
765 : } else {
766 : # ifndef SHORT_DBG_HDRS
767 0 : ptr_t clobbered = GC_check_annotated_obj((oh *)base);
768 0 : word sz = GC_size(base);
769 0 : if (clobbered != 0) {
770 0 : GC_have_errors = TRUE;
771 0 : if (((oh *)base) -> oh_sz == sz) {
772 0 : GC_print_smashed_obj(
773 : "GC_debug_free: found previously deallocated (?) object at",
774 : p, clobbered);
775 0 : return; /* ignore double free */
776 : } else {
777 0 : GC_print_smashed_obj("GC_debug_free: found smashed location at",
778 : p, clobbered);
779 : }
780 : }
781 : /* Invalidate size (mark the object as deallocated) */
782 0 : ((oh *)base) -> oh_sz = sz;
783 : # endif /* SHORT_DBG_HDRS */
784 : }
785 0 : if (GC_find_leak
786 : # ifndef SHORT_DBG_HDRS
787 0 : && ((ptr_t)p - (ptr_t)base != sizeof(oh) || !GC_findleak_delay_free)
788 : # endif
789 : ) {
790 0 : GC_free(base);
791 : } else {
792 0 : hdr * hhdr = HDR(p);
793 0 : if (hhdr -> hb_obj_kind == UNCOLLECTABLE
794 : # ifdef ATOMIC_UNCOLLECTABLE
795 0 : || hhdr -> hb_obj_kind == AUNCOLLECTABLE
796 : # endif
797 : ) {
798 0 : GC_free(base);
799 : } else {
800 : size_t i;
801 0 : size_t obj_sz = BYTES_TO_WORDS(hhdr -> hb_sz - sizeof(oh));
802 :
803 0 : for (i = 0; i < obj_sz; ++i)
804 0 : ((word *)p)[i] = GC_FREED_MEM_MARKER;
805 : GC_ASSERT((word *)p + i == (word *)(base + hhdr -> hb_sz));
806 : }
807 : } /* !GC_find_leak */
808 : }
809 :
810 : #if defined(THREADS) && defined(DBG_HDRS_ALL)
811 : /* Used internally; we assume it's called correctly. */
812 : GC_INNER void GC_debug_free_inner(void * p)
813 : {
814 : ptr_t base = GC_base(p);
815 : GC_ASSERT((ptr_t)p - (ptr_t)base == sizeof(oh));
816 : # ifdef LINT2
817 : if (!base) ABORT("Invalid GC_debug_free_inner argument");
818 : # endif
819 : # ifndef SHORT_DBG_HDRS
820 : /* Invalidate size */
821 : ((oh *)base) -> oh_sz = GC_size(base);
822 : # endif
823 : GC_free_inner(base);
824 : }
825 : #endif
826 :
827 0 : GC_API void * GC_CALL GC_debug_realloc(void * p, size_t lb, GC_EXTRA_PARAMS)
828 : {
829 : void * base;
830 : void * result;
831 : hdr * hhdr;
832 0 : if (p == 0)
833 0 : return(GC_debug_malloc(lb, OPT_RA s, i));
834 :
835 0 : base = GC_base(p);
836 0 : if (base == 0) {
837 0 : GC_err_printf("Attempt to reallocate invalid pointer %p\n", p);
838 0 : ABORT("Invalid pointer passed to realloc()");
839 : }
840 0 : if ((ptr_t)p - (ptr_t)base != sizeof(oh)) {
841 0 : GC_err_printf(
842 : "GC_debug_realloc called on pointer %p w/o debugging info\n", p);
843 0 : return(GC_realloc(p, lb));
844 : }
845 0 : hhdr = HDR(base);
846 0 : switch (hhdr -> hb_obj_kind) {
847 : # ifdef STUBBORN_ALLOC
848 : case STUBBORN:
849 : result = GC_debug_malloc_stubborn(lb, OPT_RA s, i);
850 : break;
851 : # endif
852 : case NORMAL:
853 0 : result = GC_debug_malloc(lb, OPT_RA s, i);
854 0 : break;
855 : case PTRFREE:
856 0 : result = GC_debug_malloc_atomic(lb, OPT_RA s, i);
857 0 : break;
858 : case UNCOLLECTABLE:
859 0 : result = GC_debug_malloc_uncollectable(lb, OPT_RA s, i);
860 0 : break;
861 : # ifdef ATOMIC_UNCOLLECTABLE
862 : case AUNCOLLECTABLE:
863 0 : result = GC_debug_malloc_atomic_uncollectable(lb, OPT_RA s, i);
864 0 : break;
865 : # endif
866 : default:
867 0 : result = NULL; /* initialized to prevent warning. */
868 0 : GC_err_printf("GC_debug_realloc: encountered bad kind\n");
869 0 : ABORT("Bad kind");
870 : }
871 :
872 0 : if (result != NULL) {
873 : size_t old_sz;
874 : # ifdef SHORT_DBG_HDRS
875 : old_sz = GC_size(base) - sizeof(oh);
876 : # else
877 0 : old_sz = ((oh *)base) -> oh_sz;
878 : # endif
879 0 : BCOPY(p, result, old_sz < lb ? old_sz : lb);
880 0 : GC_debug_free(p);
881 : }
882 0 : return(result);
883 : }
884 :
885 : #ifndef SHORT_DBG_HDRS
886 :
887 : /* List of smashed (clobbered) locations. We defer printing these, */
888 : /* since we can't always print them nicely with the allocation lock */
889 : /* held. We put them here instead of in GC_arrays, since it may be */
890 : /* useful to be able to look at them with the debugger. */
891 : #ifndef MAX_SMASHED
892 : # define MAX_SMASHED 20
893 : #endif
894 : STATIC ptr_t GC_smashed[MAX_SMASHED] = {0};
895 : STATIC unsigned GC_n_smashed = 0;
896 :
897 0 : STATIC void GC_add_smashed(ptr_t smashed)
898 : {
899 : GC_ASSERT(GC_is_marked(GC_base(smashed)));
900 : /* FIXME: Prevent adding an object while printing smashed list. */
901 0 : GC_smashed[GC_n_smashed] = smashed;
902 0 : if (GC_n_smashed < MAX_SMASHED - 1) ++GC_n_smashed;
903 : /* In case of overflow, we keep the first MAX_SMASHED-1 */
904 : /* entries plus the last one. */
905 0 : GC_have_errors = TRUE;
906 0 : }
907 :
908 : /* Print all objects on the list. Clear the list. */
909 0 : STATIC void GC_print_all_smashed_proc(void)
910 : {
911 : unsigned i;
912 :
913 : GC_ASSERT(I_DONT_HOLD_LOCK());
914 0 : if (GC_n_smashed == 0) return;
915 0 : GC_err_printf("GC_check_heap_block: found smashed heap objects:\n");
916 0 : for (i = 0; i < GC_n_smashed; ++i) {
917 0 : GC_print_smashed_obj("", (ptr_t)GC_base(GC_smashed[i]) + sizeof(oh),
918 : GC_smashed[i]);
919 0 : GC_smashed[i] = 0;
920 : }
921 0 : GC_n_smashed = 0;
922 0 : GC_err_printf("\n");
923 : }
924 :
925 : /* Check all marked objects in the given block for validity */
926 : /* Avoid GC_apply_to_each_object for performance reasons. */
927 : /*ARGSUSED*/
928 0 : STATIC void GC_check_heap_block(struct hblk *hbp, word dummy)
929 : {
930 0 : struct hblkhdr * hhdr = HDR(hbp);
931 0 : size_t sz = hhdr -> hb_sz;
932 : size_t bit_no;
933 : char *p, *plim;
934 :
935 0 : p = hbp->hb_body;
936 0 : if (sz > MAXOBJBYTES) {
937 0 : plim = p;
938 : } else {
939 0 : plim = hbp->hb_body + HBLKSIZE - sz;
940 : }
941 : /* go through all words in block */
942 0 : for (bit_no = 0; p <= plim; bit_no += MARK_BIT_OFFSET(sz), p += sz) {
943 0 : if (mark_bit_from_hdr(hhdr, bit_no) && GC_HAS_DEBUG_INFO((ptr_t)p)) {
944 0 : ptr_t clobbered = GC_check_annotated_obj((oh *)p);
945 0 : if (clobbered != 0)
946 0 : GC_add_smashed(clobbered);
947 : }
948 : }
949 0 : }
950 :
951 : /* This assumes that all accessible objects are marked, and that */
952 : /* I hold the allocation lock. Normally called by collector. */
953 0 : STATIC void GC_check_heap_proc(void)
954 : {
955 : GC_STATIC_ASSERT((sizeof(oh) & (GRANULE_BYTES - 1)) == 0);
956 : /* FIXME: Should we check for twice that alignment? */
957 0 : GC_apply_to_all_blocks(GC_check_heap_block, 0);
958 0 : }
959 :
960 0 : GC_INNER GC_bool GC_check_leaked(ptr_t base)
961 : {
962 : size_t i;
963 : size_t obj_sz;
964 : word *p;
965 :
966 0 : if (
967 : # if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH)
968 : (*(word *)base & 1) != 0 &&
969 : # endif
970 0 : GC_has_other_debug_info(base) >= 0)
971 0 : return TRUE; /* object has leaked */
972 :
973 : /* Validate freed object's content. */
974 0 : p = (word *)(base + sizeof(oh));
975 0 : obj_sz = BYTES_TO_WORDS(HDR(base)->hb_sz - sizeof(oh));
976 0 : for (i = 0; i < obj_sz; ++i)
977 0 : if (p[i] != GC_FREED_MEM_MARKER) {
978 0 : GC_set_mark_bit(base); /* do not reclaim it in this cycle */
979 0 : GC_add_smashed((ptr_t)(&p[i])); /* alter-after-free detected */
980 0 : break; /* don't report any other smashed locations in the object */
981 : }
982 :
983 0 : return FALSE; /* GC_debug_free() has been called */
984 : }
985 :
986 : #endif /* !SHORT_DBG_HDRS */
987 :
988 : struct closure {
989 : GC_finalization_proc cl_fn;
990 : void * cl_data;
991 : };
992 :
993 0 : STATIC void * GC_make_closure(GC_finalization_proc fn, void * data)
994 : {
995 : struct closure * result =
996 : # ifdef DBG_HDRS_ALL
997 : (struct closure *) GC_debug_malloc(sizeof (struct closure),
998 : GC_EXTRAS);
999 : # else
1000 0 : (struct closure *) GC_malloc(sizeof (struct closure));
1001 : # endif
1002 0 : if (result != 0) {
1003 0 : result -> cl_fn = fn;
1004 0 : result -> cl_data = data;
1005 : }
1006 0 : return((void *)result);
1007 : }
1008 :
1009 : /* An auxiliary fns to make finalization work correctly with displaced */
1010 : /* pointers introduced by the debugging allocators. */
1011 0 : STATIC void GC_CALLBACK GC_debug_invoke_finalizer(void * obj, void * data)
1012 : {
1013 0 : struct closure * cl = (struct closure *) data;
1014 0 : (*(cl -> cl_fn))((void *)((char *)obj + sizeof(oh)), cl -> cl_data);
1015 0 : }
1016 :
1017 : /* Special finalizer_proc value to detect GC_register_finalizer() failure. */
1018 : #define OFN_UNSET (GC_finalization_proc)(signed_word)-1
1019 :
1020 : /* Set ofn and ocd to reflect the values we got back. */
1021 0 : static void store_old(void *obj, GC_finalization_proc my_old_fn,
1022 : struct closure *my_old_cd, GC_finalization_proc *ofn,
1023 : void **ocd)
1024 : {
1025 0 : if (0 != my_old_fn) {
1026 0 : if (my_old_fn == OFN_UNSET) {
1027 : /* register_finalizer() failed; (*ofn) and (*ocd) are unchanged. */
1028 0 : return;
1029 : }
1030 0 : if (my_old_fn != GC_debug_invoke_finalizer) {
1031 0 : GC_err_printf("Debuggable object at %p had a non-debug finalizer\n",
1032 : obj);
1033 : /* This should probably be fatal. */
1034 : } else {
1035 0 : if (ofn) *ofn = my_old_cd -> cl_fn;
1036 0 : if (ocd) *ocd = my_old_cd -> cl_data;
1037 : }
1038 : } else {
1039 0 : if (ofn) *ofn = 0;
1040 0 : if (ocd) *ocd = 0;
1041 : }
1042 : }
1043 :
1044 0 : GC_API void GC_CALL GC_debug_register_finalizer(void * obj,
1045 : GC_finalization_proc fn,
1046 : void * cd, GC_finalization_proc *ofn,
1047 : void * *ocd)
1048 : {
1049 0 : GC_finalization_proc my_old_fn = OFN_UNSET;
1050 : void * my_old_cd;
1051 0 : ptr_t base = GC_base(obj);
1052 0 : if (0 == base) {
1053 : /* We won't collect it, hence finalizer wouldn't be run. */
1054 0 : if (ocd) *ocd = 0;
1055 0 : if (ofn) *ofn = 0;
1056 0 : return;
1057 : }
1058 0 : if ((ptr_t)obj - base != sizeof(oh)) {
1059 0 : GC_err_printf(
1060 : "GC_debug_register_finalizer called with non-base-pointer %p\n",
1061 : obj);
1062 : }
1063 0 : if (0 == fn) {
1064 0 : GC_register_finalizer(base, 0, 0, &my_old_fn, &my_old_cd);
1065 : } else {
1066 0 : cd = GC_make_closure(fn, cd);
1067 0 : if (cd == 0) return; /* out of memory */
1068 0 : GC_register_finalizer(base, GC_debug_invoke_finalizer,
1069 : cd, &my_old_fn, &my_old_cd);
1070 : }
1071 0 : store_old(obj, my_old_fn, (struct closure *)my_old_cd, ofn, ocd);
1072 : }
1073 :
1074 0 : GC_API void GC_CALL GC_debug_register_finalizer_no_order
1075 : (void * obj, GC_finalization_proc fn,
1076 : void * cd, GC_finalization_proc *ofn,
1077 : void * *ocd)
1078 : {
1079 0 : GC_finalization_proc my_old_fn = OFN_UNSET;
1080 : void * my_old_cd;
1081 0 : ptr_t base = GC_base(obj);
1082 0 : if (0 == base) {
1083 : /* We won't collect it, hence finalizer wouldn't be run. */
1084 0 : if (ocd) *ocd = 0;
1085 0 : if (ofn) *ofn = 0;
1086 0 : return;
1087 : }
1088 0 : if ((ptr_t)obj - base != sizeof(oh)) {
1089 0 : GC_err_printf(
1090 : "GC_debug_register_finalizer_no_order called with "
1091 : "non-base-pointer %p\n",
1092 : obj);
1093 : }
1094 0 : if (0 == fn) {
1095 0 : GC_register_finalizer_no_order(base, 0, 0, &my_old_fn, &my_old_cd);
1096 : } else {
1097 0 : cd = GC_make_closure(fn, cd);
1098 0 : if (cd == 0) return; /* out of memory */
1099 0 : GC_register_finalizer_no_order(base, GC_debug_invoke_finalizer,
1100 : cd, &my_old_fn, &my_old_cd);
1101 : }
1102 0 : store_old(obj, my_old_fn, (struct closure *)my_old_cd, ofn, ocd);
1103 : }
1104 :
1105 0 : GC_API void GC_CALL GC_debug_register_finalizer_unreachable
1106 : (void * obj, GC_finalization_proc fn,
1107 : void * cd, GC_finalization_proc *ofn,
1108 : void * *ocd)
1109 : {
1110 0 : GC_finalization_proc my_old_fn = OFN_UNSET;
1111 : void * my_old_cd;
1112 0 : ptr_t base = GC_base(obj);
1113 0 : if (0 == base) {
1114 : /* We won't collect it, hence finalizer wouldn't be run. */
1115 0 : if (ocd) *ocd = 0;
1116 0 : if (ofn) *ofn = 0;
1117 0 : return;
1118 : }
1119 0 : if ((ptr_t)obj - base != sizeof(oh)) {
1120 0 : GC_err_printf(
1121 : "GC_debug_register_finalizer_unreachable called with "
1122 : "non-base-pointer %p\n",
1123 : obj);
1124 : }
1125 0 : if (0 == fn) {
1126 0 : GC_register_finalizer_unreachable(base, 0, 0, &my_old_fn, &my_old_cd);
1127 : } else {
1128 0 : cd = GC_make_closure(fn, cd);
1129 0 : if (cd == 0) return; /* out of memory */
1130 0 : GC_register_finalizer_unreachable(base, GC_debug_invoke_finalizer,
1131 : cd, &my_old_fn, &my_old_cd);
1132 : }
1133 0 : store_old(obj, my_old_fn, (struct closure *)my_old_cd, ofn, ocd);
1134 : }
1135 :
1136 0 : GC_API void GC_CALL GC_debug_register_finalizer_ignore_self
1137 : (void * obj, GC_finalization_proc fn,
1138 : void * cd, GC_finalization_proc *ofn,
1139 : void * *ocd)
1140 : {
1141 0 : GC_finalization_proc my_old_fn = OFN_UNSET;
1142 : void * my_old_cd;
1143 0 : ptr_t base = GC_base(obj);
1144 0 : if (0 == base) {
1145 : /* We won't collect it, hence finalizer wouldn't be run. */
1146 0 : if (ocd) *ocd = 0;
1147 0 : if (ofn) *ofn = 0;
1148 0 : return;
1149 : }
1150 0 : if ((ptr_t)obj - base != sizeof(oh)) {
1151 0 : GC_err_printf(
1152 : "GC_debug_register_finalizer_ignore_self called with "
1153 : "non-base-pointer %p\n", obj);
1154 : }
1155 0 : if (0 == fn) {
1156 0 : GC_register_finalizer_ignore_self(base, 0, 0, &my_old_fn, &my_old_cd);
1157 : } else {
1158 0 : cd = GC_make_closure(fn, cd);
1159 0 : if (cd == 0) return; /* out of memory */
1160 0 : GC_register_finalizer_ignore_self(base, GC_debug_invoke_finalizer,
1161 : cd, &my_old_fn, &my_old_cd);
1162 : }
1163 0 : store_old(obj, my_old_fn, (struct closure *)my_old_cd, ofn, ocd);
1164 : }
1165 :
1166 0 : GC_API void * GC_CALL GC_debug_malloc_replacement(size_t lb)
1167 : {
1168 0 : return GC_debug_malloc(lb, GC_DBG_RA "unknown", 0);
1169 : }
1170 :
1171 0 : GC_API void * GC_CALL GC_debug_realloc_replacement(void *p, size_t lb)
1172 : {
1173 0 : return GC_debug_realloc(p, lb, GC_DBG_RA "unknown", 0);
1174 : }
|