>>>>> "Basile" == Basile Starynkevitch <bas...@starynkevitch.net> writes:
Basile> So I need to understand who is writing the 0x101 in that field. valgrind can sometimes catch this, assuming that the write is an invalid one. Basile> An obvious strategy is to use the hardware watchpoint feature of GDB. Basile> However, one cannot nicely put a watchpoint on an address which is not Basile> mmap-ed yet. I think a new-enough gdb should handle this ok. rth> I typically find the location at which the object containing the address rth> is allocated. E.g. in alloc_block on the return statement. Make this rth> bp conditional on the object you're looking for. I do this, too. One thing to watch out for is that the memory can be recycled. I've been very confused whenever I've forgotten this. I have a hack for the GC (appended -- ancient enough that it probably won't apply) that makes it easy to notice when an object you are interested in is collected. IIRC I apply this before the first run, call ggc_watch_object for the thing I am interested in, and then see in what GC cycle the real one is allocated. Tom Index: ggc-page.c =================================================================== --- ggc-page.c (revision 127650) +++ ggc-page.c (working copy) @@ -430,6 +430,13 @@ } *free_object_list; #endif + /* Watched objects. */ + struct watched_object + { + void *object; + struct watched_object *next; + } *watched_object_list; + #ifdef GATHER_STATISTICS struct { @@ -481,7 +488,7 @@ /* Initial guess as to how many page table entries we might need. */ #define INITIAL_PTE_COUNT 128 -static int ggc_allocated_p (const void *); +int ggc_allocated_p (const void *); static page_entry *lookup_page_table_entry (const void *); static void set_page_table_entry (void *, page_entry *); #ifdef USING_MMAP @@ -549,7 +556,7 @@ /* Returns nonzero if P was allocated in GC'able memory. */ -static inline int +int ggc_allocated_p (const void *p) { page_entry ***base; @@ -1264,9 +1271,36 @@ (unsigned long) size, (unsigned long) object_size, result, (void *) entry); + { + struct watched_object *w; + for (w = G.watched_object_list; w; w = w->next) + { + if (result == w->object) + { + fprintf (stderr, "re-returning watched object %p\n", w->object); + break; + } + } + } + return result; } +int +ggc_check_watch (void *p, char *what) +{ + struct watched_object *w; + for (w = G.watched_object_list; w; w = w->next) + { + if (p == w->object) + { + fprintf (stderr, "got it: %s\n", what); + return 1; + } + } + return 0; +} + /* If P is not marked, marks it and return false. Otherwise return true. P must have been allocated by the GC allocator; it mustn't point to static objects, stack variables, or memory allocated with malloc. */ @@ -1293,6 +1327,19 @@ if (entry->in_use_p[word] & mask) return 1; + { + struct watched_object *w; + for (w = G.watched_object_list; w; w = w->next) + { + if (p == w->object) + { + fprintf (stderr, "marking object %p; was %d\n", p, + (int) (entry->in_use_p[word] & mask)); + break; + } + } + } + /* Otherwise set it, and decrement the free object count. */ entry->in_use_p[word] |= mask; entry->num_free_objects -= 1; @@ -1337,6 +1384,15 @@ return OBJECT_SIZE (pe->order); } +void +ggc_watch_object (void *p) +{ + struct watched_object *w = XNEW (struct watched_object); + w->object = p; + w->next = G.watched_object_list; + G.watched_object_list = w; +} + /* Release the memory for object P. */ void @@ -1345,11 +1401,21 @@ page_entry *pe = lookup_page_table_entry (p); size_t order = pe->order; size_t size = OBJECT_SIZE (order); + struct watched_object *w; #ifdef GATHER_STATISTICS ggc_free_overhead (p); #endif + for (w = G.watched_object_list; w; w = w->next) + { + if (w->object == p) + { + fprintf (stderr, "freeing watched object %p\n", p); + break; + } + } + if (GGC_DEBUG_LEVEL >= 3) fprintf (G.debug_file, "Freeing object, actual size=%lu, at %p on %p\n", @@ -1868,6 +1934,10 @@ #define validate_free_objects() #endif +int ggc_nc = 0; + + + /* Top level mark-and-sweep routine. */ void @@ -1903,6 +1973,21 @@ clear_marks (); ggc_mark_roots (); + + if (G.watched_object_list) + { + struct watched_object *w; + fprintf (stderr, "== starting collection %d\n", ggc_nc); + ++ggc_nc; + for (w = G.watched_object_list; w; w = w->next) + { + if (!ggc_marked_p (w->object)) + { + fprintf (stderr, "object %p is free\n", w->object); + } + } + } + #ifdef GATHER_STATISTICS ggc_prune_overhead_list (); #endif