summaryrefslogtreecommitdiff
path: root/dbg_mlc.c
diff options
context:
space:
mode:
authorivmai <ivmai>2011-05-06 06:43:49 +0200
committerIvan Maidanski <ivmai@mail.ru>2011-07-26 19:06:58 +0200
commit9d99463219d3125e87c7a07cf6aba5624e16aae6 (patch)
tree5202a4816a9a04ac8fa7b8ed64dbebf238b90cfa /dbg_mlc.c
parentb898fa85675826496de2c476276ff8ca4af756bf (diff)
2011-05-06 Ivan Maidanski <ivmai@mail.ru>
* dbg_mlc.c (GC_has_other_debug_info): Change return type to int; return -1 if the object has (or had) debugging info but was marked deallocated. * include/private/dbg_mlc.h (GC_has_other_debug_info): Ditto. * dbg_mlc.c (GC_has_other_debug_info): Update documentation; remove "ohdr" local variable. * dbg_mlc.c (GC_debug_free): Don't call GC_free if the object has probably been deallocated. * dbg_mlc.c (GC_debug_free): Don't actually free the object even in the leak-finding mode if GC_findleak_delay_free. * dbg_mlc.c (GC_print_all_smashed_proc): Print a trailing blank line. * dbg_mlc.c (GC_check_leaked): New function (only unless SHORT_DBG_HDRS). * doc/README.environment (GC_FINDLEAK_DELAY_FREE): Document. * doc/README.macros (GC_FINDLEAK_DELAY_FREE): Ditto. * include/private/dbg_mlc.h (START_FLAG, END_FLAG): Use GC_WORD_C on 64-bit architectures. * include/private/dbg_mlc.h (NOT_MARKED): Remove redundant parentheses. * include/private/dbg_mlc.h (GC_HAS_DEBUG_INFO): Update (due to GC_has_other_debug_info change). * include/private/gc_priv.h (GC_findleak_delay_free): New global variable declaration (unless SHORT_DBG_HDRS). * misc.c (GC_findleak_delay_free): New global variable; recognize GC_FINDLEAK_DELAY_FREE. * misc.c (GC_init): Recognize GC_FINDLEAK_DELAY_FREE environment variable (unless SHORT_DBG_HDRS). * reclaim.c (GC_check_leaked): Declare (unless SHORT_DBG_HDRS). * reclaim.c (GC_add_leaked): Don't add the object to leaked list if marked as deallocated.
Diffstat (limited to 'dbg_mlc.c')
-rw-r--r--dbg_mlc.c78
1 files changed, 57 insertions, 21 deletions
diff --git a/dbg_mlc.c b/dbg_mlc.c
index b2671c1..c3d9e77 100644
--- a/dbg_mlc.c
+++ b/dbg_mlc.c
@@ -32,27 +32,27 @@ GC_INNER void GC_default_print_heap_obj_proc(ptr_t p);
/* odd, which is added by the GC_HAS_DEBUG_INFO macro. */
/* Note that if DBG_HDRS_ALL is set, uncollectable objects */
/* on free lists may not have debug information set. Thus it's */
- /* not always safe to return TRUE, even if the client does */
- /* its part. */
- GC_INNER GC_bool GC_has_other_debug_info(ptr_t p)
+ /* not always safe to return TRUE (1), even if the client does */
+ /* its part. Return -1 if the object with debug info has been */
+ /* marked as deallocated. */
+ GC_INNER int GC_has_other_debug_info(ptr_t p)
{
- oh * ohdr = (oh *)p;
- ptr_t body = (ptr_t)(ohdr + 1);
- word sz = GC_size((ptr_t) ohdr);
+ ptr_t body = (ptr_t)((oh *)p + 1);
+ word sz = GC_size(p);
- if (HBLKPTR((ptr_t)ohdr) != HBLKPTR((ptr_t)body)
+ if (HBLKPTR(p) != HBLKPTR((ptr_t)body)
|| sz < DEBUG_BYTES + EXTRA_BYTES) {
- return(FALSE);
+ return 0;
}
- if (ohdr -> oh_sz == sz) {
- /* Object may have had debug info, but has been deallocated */
- return(FALSE);
+ if (((oh *)p) -> oh_sf != (START_FLAG ^ (word)body)
+ && ((word *)p)[BYTES_TO_WORDS(sz)-1] != (END_FLAG ^ (word)body)) {
+ return 0;
}
- if (ohdr -> oh_sf == (START_FLAG ^ (word)body)) return(TRUE);
- if (((word *)ohdr)[BYTES_TO_WORDS(sz)-1] == (END_FLAG ^ (word)body)) {
- return(TRUE);
+ if (((oh *)p)->oh_sz == sz) {
+ /* Object may have had debug info, but has been deallocated */
+ return -1;
}
- return(FALSE);
+ return 1;
}
#endif /* !SHORT_DBG_HDRS */
@@ -771,17 +771,26 @@ GC_API void GC_CALL GC_debug_free(void * p)
ptr_t clobbered = GC_check_annotated_obj((oh *)base);
word sz = GC_size(base);
if (clobbered != 0) {
- GC_print_smashed_obj(((oh *)base) -> oh_sz == sz ?
- "GC_debug_free: found previously deallocated (?) object at" :
- "GC_debug_free: found smashed location at",
- p, clobbered);
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 */
+ /* Invalidate size (mark the object as deallocated) */
((oh *)base) -> oh_sz = sz;
# endif /* SHORT_DBG_HDRS */
}
- if (GC_find_leak) {
+ 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);
@@ -914,6 +923,7 @@ STATIC void GC_print_all_smashed_proc(void)
GC_smashed[i] = 0;
}
GC_n_smashed = 0;
+ GC_err_printf("\n");
}
/* Check all marked objects in the given block for validity */
@@ -951,6 +961,32 @@ STATIC void GC_check_heap_proc(void)
GC_apply_to_all_blocks(GC_check_heap_block, 0);
}
+GC_INNER GC_bool GC_check_leaked(ptr_t base)
+{
+ size_t i;
+ size_t obj_sz;
+ word *p;
+
+ if (
+# if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH)
+ (*(word *)base & 1) != 0 &&
+# endif
+ GC_has_other_debug_info(base) >= 0)
+ return TRUE; /* object has leaked */
+
+ /* Validate freed object's content. */
+ p = (word *)(base + sizeof(oh));
+ obj_sz = BYTES_TO_WORDS(HDR(base)->hb_sz - sizeof(oh));
+ for (i = 0; i < obj_sz; ++i)
+ if (p[i] != GC_FREED_MEM_MARKER) {
+ GC_set_mark_bit(base); /* do not reclaim it in this cycle */
+ GC_add_smashed((ptr_t)(&p[i])); /* alter-after-free detected */
+ break; /* don't report any other smashed locations in the object */
+ }
+
+ return FALSE; /* GC_debug_free() has been called */
+}
+
#endif /* !SHORT_DBG_HDRS */
struct closure {