>>>>> "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

Reply via email to