[glib] GList: be more robust
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib] GList: be more robust
- Date: Sun, 24 Feb 2013 21:56:48 +0000 (UTC)
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]