/*ARGSUSED*/ void GC_check_heap_block(struct hblk *hbp, word dummy) { struct hblkhdr * hhdr = HDR(hbp); size_t sz = hhdr -> hb_sz; size_t bit_no; char *p, *plim; p = hbp->hb_body; bit_no = 0; if (sz > MAXOBJBYTES) { plim = p; } else { plim = hbp->hb_body + HBLKSIZE - sz; } /* go through all words in block */ while( p <= plim ) { if( mark_bit_from_hdr(hhdr, bit_no) && GC_HAS_DEBUG_INFO((ptr_t)p)) { ptr_t clobbered = GC_check_annotated_obj((oh *)p); if (clobbered != 0) GC_add_smashed(clobbered); } bit_no += MARK_BIT_OFFSET(sz); p += sz; } }
void * GC_debug_realloc(void * p, size_t lb, GC_EXTRA_PARAMS) { void * base = GC_base(p); ptr_t clobbered; void * result; size_t copy_sz = lb; size_t old_sz; hdr * hhdr; if (p == 0) return(GC_debug_malloc(lb, OPT_RA s, i)); if (base == 0) { GC_err_printf("Attempt to reallocate invalid pointer %p\n", p); ABORT("realloc(invalid pointer)"); } if ((ptr_t)p - (ptr_t)base != sizeof(oh)) { GC_err_printf( "GC_debug_realloc called on pointer %p wo debugging info\n", p); return(GC_realloc(p, lb)); } hhdr = HDR(base); switch (hhdr -> hb_obj_kind) { # ifdef STUBBORN_ALLOC case STUBBORN: result = GC_debug_malloc_stubborn(lb, OPT_RA s, i); break; # endif 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 ATOMIC_UNCOLLECTABLE case AUNCOLLECTABLE: result = GC_debug_malloc_atomic_uncollectable(lb, OPT_RA s, i); break; # endif default: GC_err_printf("GC_debug_realloc: encountered bad kind\n"); ABORT("bad kind"); } # ifdef SHORT_DBG_HDRS old_sz = GC_size(base) - sizeof(oh); # else clobbered = GC_check_annotated_obj((oh *)base); if (clobbered != 0) { GC_err_printf("GC_debug_realloc: found smashed location at "); GC_print_smashed_obj(p, clobbered); } old_sz = ((oh *)base) -> oh_sz; # endif if (old_sz < copy_sz) copy_sz = old_sz; if (result == 0) return(0); BCOPY(p, result, copy_sz); GC_debug_free(p); return(result); }
GC_API void GC_CALL GC_debug_free(void * p) { ptr_t base; if (0 == p) return; base = GC_base(p); if (base == 0) { GC_err_printf("Attempt to free invalid pointer %p\n", p); ABORT("Invalid pointer passed to free()"); } 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 */ }
void GC_debug_free(void * p) { ptr_t base; ptr_t clobbered; if (0 == p) return; base = GC_base(p); if (base == 0) { GC_err_printf("Attempt to free invalid pointer %p\n", p); ABORT("free(invalid pointer)"); } if ((ptr_t)p - (ptr_t)base != sizeof(oh)) { GC_err_printf( "GC_debug_free called on pointer %p wo debugging info\n", p); } else { # ifndef SHORT_DBG_HDRS clobbered = GC_check_annotated_obj((oh *)base); if (clobbered != 0) { if (((oh *)base) -> oh_sz == GC_size(base)) { GC_err_printf( "GC_debug_free: found previously deallocated (?) object at "); } else { GC_err_printf("GC_debug_free: found smashed location at "); } GC_print_smashed_obj(p, clobbered); } /* Invalidate size */ ((oh *)base) -> oh_sz = GC_size(base); # endif /* SHORT_DBG_HDRS */ } if (GC_find_leak) { GC_free(base); } else { hdr * hhdr = HDR(p); GC_bool uncollectable = FALSE; if (hhdr -> hb_obj_kind == UNCOLLECTABLE) { uncollectable = TRUE; } # ifdef ATOMIC_UNCOLLECTABLE if (hhdr -> hb_obj_kind == AUNCOLLECTABLE) { uncollectable = TRUE; } # endif if (uncollectable) { 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] = 0xdeadbeef; GC_ASSERT((word *)p + i == (word *)(base + hhdr -> hb_sz)); } } /* !GC_find_leak */ }
/* Avoid GC_apply_to_each_object for performance reasons. */ STATIC void GC_check_heap_block(struct hblk *hbp, word dummy GC_ATTR_UNUSED) { struct hblkhdr * hhdr = HDR(hbp); word sz = hhdr -> hb_sz; word bit_no; char *p, *plim; p = hbp->hb_body; if (sz > MAXOBJBYTES) { plim = p; } else { plim = hbp->hb_body + HBLKSIZE - sz; } /* go through all words in block */ for (bit_no = 0; (word)p <= (word)plim; bit_no += MARK_BIT_OFFSET(sz), p += sz) { if (mark_bit_from_hdr(hhdr, bit_no) && GC_HAS_DEBUG_INFO((ptr_t)p)) { ptr_t clobbered = GC_check_annotated_obj((oh *)p); if (clobbered != 0) GC_add_smashed(clobbered); } } }
#include <M2/gc-include.h> #include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <M2/config.h> #include <stdint.h> #include "debug.h" #include <gmp.h> #include <mpfr.h> #include <string.h> void *trapaddr = (void *)1; int trapcount = 0; int trapset = 0; void trap(void) {} /* I used to be concerned that this function would get optimized away, but it isn't static ... */ void *pointers[10]; /* during debugging we can put pointers here, visible to the garbage collector */ void trapchk(void *p) { trapcount++; if (trapcount == trapset || p == trapaddr || p == (void *)~(intptr_t)trapaddr) trap(); } #define STDERR 2 int badBlock() { char buf[120]; sprintf(buf,"%s:%d: internal error: smashed block in memory block allocator\n",__FILE__,__LINE__); if (write(STDERR,buf,strlen(buf))) abort(); abort(); } #if GC_DEBUG extern unsigned int GC_debug_header_size; extern void *GC_check_annotated_obj(void *); /* returns NULL or pointer to clobbered debug header location */ void GC_check(void *p) { void *q = (char *)p - GC_debug_header_size; if (NULL != GC_check_annotated_obj(q)) trap(); }
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 */ }