[glib] GList: be more robust



commit 921593b022491ce3dbd61739cc9808a715f25b9f
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Feb 24 22:54:09 2013 +0100

    GList: be more robust
    
    We can detect list corruption in some cases. The new test case
    demonstrates a case where we can warn instead of silently corrupt
    the list. This was pointed out by Steve Grubb.
    
    Also, use the same auxiliary routine in all places where we unlink
    a list element.

 glib/glist.c      |   69 +++++++++++++++++++++++++++--------------------------
 glib/tests/list.c |   27 ++++++++++++++++++++
 2 files changed, 62 insertions(+), 34 deletions(-)
---
diff --git a/glib/glist.c b/glib/glist.c
index f4905f3..620b58d 100644
--- a/glib/glist.c
+++ b/glib/glist.c
@@ -32,6 +32,7 @@
 
 #include "glist.h"
 #include "gslice.h"
+#include "gmessages.h"
 
 #include "gtestutils.h"
 
@@ -420,6 +421,34 @@ g_list_concat (GList *list1, GList *list2)
   return list1;
 }
 
+static inline GList*
+_g_list_remove_link (GList *list,
+                    GList *link)
+{
+  if (link->prev)
+    {
+      if (link->prev->next == link)
+        link->prev->next = link->next;
+      else
+        g_warning ("corrupted double-linked list detected");
+    }
+  if (link->next)
+    {
+      if (link->next->prev == link)
+        link->next->prev = link->prev;
+      else
+        g_warning ("corrupted double-linked list detected");
+    }
+
+  if (link == list)
+    list = list->next;
+
+  link->next = NULL;
+  link->prev = NULL;
+
+  return list;
+}
+
 /**
  * g_list_remove:
  * @list: a #GList
@@ -436,7 +465,7 @@ g_list_remove (GList             *list,
               gconstpointer  data)
 {
   GList *tmp;
-  
+
   tmp = list;
   while (tmp)
     {
@@ -444,16 +473,9 @@ g_list_remove (GList            *list,
        tmp = tmp->next;
       else
        {
-         if (tmp->prev)
-           tmp->prev->next = tmp->next;
-         if (tmp->next)
-           tmp->next->prev = tmp->prev;
-         
-         if (list == tmp)
-           list = list->next;
-         
+          list = _g_list_remove_link (list, tmp);
          _g_list_free1 (tmp);
-         
+
          break;
        }
     }
@@ -465,9 +487,9 @@ g_list_remove (GList             *list,
  * @list: a #GList
  * @data: data to remove
  *
- * Removes all list nodes with data equal to @data. 
- * Returns the new head of the list. Contrast with 
- * g_list_remove() which removes only the first node 
+ * Removes all list nodes with data equal to @data.
+ * Returns the new head of the list. Contrast with
+ * g_list_remove() which removes only the first node
  * matching the given data.
  *
  * Returns: new head of @list
@@ -500,27 +522,6 @@ g_list_remove_all (GList   *list,
   return list;
 }
 
-static inline GList*
-_g_list_remove_link (GList *list,
-                    GList *link)
-{
-  if (link)
-    {
-      if (link->prev)
-       link->prev->next = link->next;
-      if (link->next)
-       link->next->prev = link->prev;
-      
-      if (link == list)
-       list = list->next;
-      
-      link->next = NULL;
-      link->prev = NULL;
-    }
-  
-  return list;
-}
-
 /**
  * g_list_remove_link:
  * @list: a #GList
diff --git a/glib/tests/list.c b/glib/tests/list.c
index 7241784..10d5236 100644
--- a/glib/tests/list.c
+++ b/glib/tests/list.c
@@ -1,4 +1,5 @@
 #include <glib.h>
+#include <stdlib.h>
 
 #define SIZE       50
 #define NUMBER_MIN 0000
@@ -488,6 +489,31 @@ test_position (void)
   g_list_free (ll);
 }
 
+static void
+test_double_free (void)
+{
+  if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
+    {
+      GList *list, *link;
+      GList  intruder = { NULL, (gpointer)0xDEADBEEF, (gpointer)0xDEADBEEF };
+
+      list = NULL;
+      list = g_list_append (list, "a");
+      link = list = g_list_append (list, "b");
+      list = g_list_append (list, "c");
+
+      list = g_list_remove_link (list, link);
+      link->prev = list;
+      link->next = &intruder;
+      list = g_list_remove_link (list, link);
+
+      g_list_free (list);
+      exit (0);
+    }
+  g_test_trap_assert_failed ();
+  g_test_trap_assert_stderr ("*corrupted double-linked list detected*");
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -516,6 +542,7 @@ main (int argc, char *argv[])
   g_test_add_func ("/list/delete-link", test_delete_link);
   g_test_add_func ("/list/prepend", test_prepend);
   g_test_add_func ("/list/position", test_position);
+  g_test_add_func ("/list/double-free", test_double_free);
 
   return g_test_run ();
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]