GC_API void GC_CALL GC_debug_change_stubborn(const void *p) { const void * q = GC_base_C(p); hdr * hhdr; if (q == 0) { ABORT_ARG1("GC_debug_change_stubborn: bad arg", ": %p", p); } hhdr = HDR(q); if (hhdr -> hb_obj_kind != STUBBORN) { ABORT_ARG1("GC_debug_change_stubborn: arg not stubborn", ": %p", p); } GC_change_stubborn(q); }
GC_API void GC_CALL GC_debug_end_stubborn_change(const void *p) { const void * q = GC_base_C(p); if (NULL == q) { ABORT_ARG1("GC_debug_end_stubborn_change: bad arg", ": %p", p); } GC_end_stubborn_change(q); }
GC_API void GC_CALL GC_debug_free(void * p) { ptr_t base; if (0 == p) return; base = GC_base(p); if (base == 0) { ABORT_ARG1("Invalid pointer passed to free()", ": %p", p); } if ((ptr_t)p - (ptr_t)base != sizeof(oh)) { GC_err_printf( "GC_debug_free called on pointer %p w/o debugging info\n", p); } else { # ifndef SHORT_DBG_HDRS ptr_t clobbered = GC_check_annotated_obj((oh *)base); word sz = GC_size(base); if (clobbered != 0) { GC_have_errors = TRUE; if (((oh *)base) -> oh_sz == sz) { GC_print_smashed_obj( "GC_debug_free: found previously deallocated (?) object at", p, clobbered); return; /* ignore double free */ } else { GC_print_smashed_obj("GC_debug_free: found smashed location at", p, clobbered); } } /* Invalidate size (mark the object as deallocated) */ ((oh *)base) -> oh_sz = sz; # endif /* SHORT_DBG_HDRS */ } if (GC_find_leak # ifndef SHORT_DBG_HDRS && ((ptr_t)p - (ptr_t)base != sizeof(oh) || !GC_findleak_delay_free) # endif ) { GC_free(base); } else { hdr * hhdr = HDR(p); if (hhdr -> hb_obj_kind == UNCOLLECTABLE # ifdef ATOMIC_UNCOLLECTABLE || hhdr -> hb_obj_kind == AUNCOLLECTABLE # endif ) { GC_free(base); } else { size_t i; size_t obj_sz = BYTES_TO_WORDS(hhdr -> hb_sz - sizeof(oh)); for (i = 0; i < obj_sz; ++i) ((word *)p)[i] = GC_FREED_MEM_MARKER; GC_ASSERT((word *)p + i == (word *)(base + hhdr -> hb_sz)); } } /* !GC_find_leak */ }
STATIC void GC_CALLBACK GC_default_is_visible_print_proc(void * p) { ABORT_ARG1("GC_is_visible test failed", ": %p not GC-visible", p); }
STATIC void GC_CALLBACK GC_default_is_valid_displacement_print_proc (void *p) { ABORT_ARG1("GC_is_valid_displacement test failed", ": %p not valid", p); }
GC_API void * GC_CALL GC_debug_realloc(void * p, size_t lb, GC_EXTRA_PARAMS) { void * base; void * result; hdr * hhdr; if (p == 0) { return GC_debug_malloc(lb, OPT_RA s, i); } if (0 == lb) /* and p != NULL */ { GC_debug_free(p); return NULL; } # ifdef GC_ADD_CALLER if (s == NULL) { GC_caller_func_offset(ra, &s, &i); } # endif base = GC_base(p); if (base == 0) { ABORT_ARG1("Invalid pointer passed to realloc()", ": %p", p); } if ((ptr_t)p - (ptr_t)base != sizeof(oh)) { GC_err_printf( "GC_debug_realloc called on pointer %p w/o debugging info\n", p); return(GC_realloc(p, lb)); } hhdr = HDR(base); switch (hhdr -> hb_obj_kind) { case NORMAL: result = GC_debug_malloc(lb, OPT_RA s, i); break; case PTRFREE: result = GC_debug_malloc_atomic(lb, OPT_RA s, i); break; case UNCOLLECTABLE: result = GC_debug_malloc_uncollectable(lb, OPT_RA s, i); break; # ifdef GC_ATOMIC_UNCOLLECTABLE case AUNCOLLECTABLE: result = GC_debug_malloc_atomic_uncollectable(lb, OPT_RA s, i); break; # endif default: result = NULL; /* initialized to prevent warning. */ ABORT_RET("GC_debug_realloc: encountered bad kind"); } if (result != NULL) { size_t old_sz; # ifdef SHORT_DBG_HDRS old_sz = GC_size(base) - sizeof(oh); # else old_sz = ((oh *)base) -> oh_sz; # endif if (old_sz > 0) BCOPY(p, result, old_sz < lb ? old_sz : lb); GC_debug_free(p); } return(result); }
GC_API void GC_CALL GC_debug_free(void * p) { ptr_t base; if (0 == p) return; base = (ptr_t)GC_base(p); if (NULL == base) { # if defined(REDIRECT_MALLOC) \ && ((defined(NEED_CALLINFO) && defined(GC_HAVE_BUILTIN_BACKTRACE)) \ || defined(GC_LINUX_THREADS) || defined(GC_SOLARIS_THREADS) \ || defined(MSWIN32)) /* In some cases, we should ignore objects that do not belong */ /* to the GC heap. See the comment in GC_free. */ if (!GC_is_heap_ptr(p)) return; # endif ABORT_ARG1("Invalid pointer passed to free()", ": %p", p); } if ((ptr_t)p - (ptr_t)base != sizeof(oh)) { # if defined(REDIRECT_FREE) && defined(USE_PROC_FOR_LIBRARIES) /* TODO: Suppress the warning if free() caller is in libpthread */ /* or libdl. */ # endif GC_err_printf( "GC_debug_free called on pointer %p w/o debugging info\n", p); } else { # ifndef SHORT_DBG_HDRS ptr_t clobbered = GC_check_annotated_obj((oh *)base); word sz = GC_size(base); if (clobbered != 0) { GC_have_errors = TRUE; if (((oh *)base) -> oh_sz == sz) { GC_print_smashed_obj( "GC_debug_free: found previously deallocated (?) object at", p, clobbered); return; /* ignore double free */ } else { GC_print_smashed_obj("GC_debug_free: found smashed location at", p, clobbered); } } /* Invalidate size (mark the object as deallocated) */ ((oh *)base) -> oh_sz = sz; # endif /* SHORT_DBG_HDRS */ } if (GC_find_leak # ifndef SHORT_DBG_HDRS && ((ptr_t)p - (ptr_t)base != sizeof(oh) || !GC_findleak_delay_free) # endif ) { GC_free(base); } else { hdr * hhdr = HDR(p); if (hhdr -> hb_obj_kind == UNCOLLECTABLE # ifdef GC_ATOMIC_UNCOLLECTABLE || hhdr -> hb_obj_kind == AUNCOLLECTABLE # endif ) { GC_free(base); } else { word i; word sz = hhdr -> hb_sz; word obj_sz = BYTES_TO_WORDS(sz - sizeof(oh)); for (i = 0; i < obj_sz; ++i) ((word *)p)[i] = GC_FREED_MEM_MARKER; GC_ASSERT((word *)p + i == (word *)(base + sz)); /* Update the counter even though the real deallocation */ /* is deferred. */ LOCK(); GC_bytes_freed += sz; UNLOCK(); } } /* !GC_find_leak */ }