This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: hints on debugging memory corruption...


>>>>> "Basile" == Basile Starynkevitch <basile@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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]