From d743b2fbeab01f9a9904712a5b751afd0519696d Mon Sep 17 00:00:00 2001 From: Kristian Rietveld Date: Thu, 30 Jul 2009 21:23:47 +0200 Subject: [PATCH] =?UTF-8?q?Bug=20586374=20=E2=80=93=20code=20does=20not=20?= =?UTF-8?q?follow=20documentation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Properly invalidate iterators in iter_next, iter_children, iter_nth_child and iter_parent when FALSE is returned. ListStore was actually already mostly in order as the GSequence pointers are very strictly checked, but to be a little stricter we've added stamp = 0 lines. TreeStore did not invalidate its iterators, so stamp = 0 lines were added where appropriate. Unit tests have been added to check this. Fixes bug 586374, reported by Mike Gemunde. --- gtk/gtkliststore.c | 21 ++++++++++-- gtk/gtktreestore.c | 20 ++++++++--- gtk/tests/liststore.c | 80 +++++++++++++++++++++++++++++++++++++++++++ gtk/tests/treestore.c | 80 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 194 insertions(+), 7 deletions(-) diff --git a/gtk/gtkliststore.c b/gtk/gtkliststore.c index 470c9f82b1..dd286298fe 100644 --- a/gtk/gtkliststore.c +++ b/gtk/gtkliststore.c @@ -494,10 +494,16 @@ static gboolean gtk_list_store_iter_next (GtkTreeModel *tree_model, GtkTreeIter *iter) { + gboolean retval; + g_return_val_if_fail (GTK_LIST_STORE (tree_model)->stamp == iter->stamp, FALSE); iter->user_data = g_sequence_iter_next (iter->user_data); - return !g_sequence_iter_is_end (iter->user_data); + retval = g_sequence_iter_is_end (iter->user_data); + if (retval) + iter->stamp = 0; + + return !retval; } static gboolean @@ -509,7 +515,10 @@ gtk_list_store_iter_children (GtkTreeModel *tree_model, /* this is a list, nodes have no children */ if (parent) - return FALSE; + { + iter->stamp = 0; + return FALSE; + } if (g_sequence_get_length (list_store->seq) > 0) { @@ -518,7 +527,10 @@ gtk_list_store_iter_children (GtkTreeModel *tree_model, return TRUE; } else - return FALSE; + { + iter->stamp = 0; + return FALSE; + } } static gboolean @@ -551,6 +563,8 @@ gtk_list_store_iter_nth_child (GtkTreeModel *tree_model, GtkListStore *list_store = (GtkListStore *) tree_model; GSequenceIter *child; + iter->stamp = 0; + if (parent) return FALSE; @@ -570,6 +584,7 @@ gtk_list_store_iter_parent (GtkTreeModel *tree_model, GtkTreeIter *iter, GtkTreeIter *child) { + iter->stamp = 0; return FALSE; } diff --git a/gtk/gtktreestore.c b/gtk/gtktreestore.c index 1fb178d375..97084084fb 100644 --- a/gtk/gtktreestore.c +++ b/gtk/gtktreestore.c @@ -620,7 +620,10 @@ gtk_tree_store_iter_next (GtkTreeModel *tree_model, return TRUE; } else - return FALSE; + { + iter->stamp = 0; + return FALSE; + } } static gboolean @@ -646,7 +649,10 @@ gtk_tree_store_iter_children (GtkTreeModel *tree_model, return TRUE; } else - return FALSE; + { + iter->stamp = 0; + return FALSE; + } } static gboolean @@ -708,7 +714,10 @@ gtk_tree_store_iter_nth_child (GtkTreeModel *tree_model, return TRUE; } else - return FALSE; + { + iter->stamp = 0; + return FALSE; + } } static gboolean @@ -733,7 +742,10 @@ gtk_tree_store_iter_parent (GtkTreeModel *tree_model, return TRUE; } else - return FALSE; + { + iter->stamp = 0; + return FALSE; + } } diff --git a/gtk/tests/liststore.c b/gtk/tests/liststore.c index 588f725f3d..6452fc2903 100644 --- a/gtk/tests/liststore.c +++ b/gtk/tests/liststore.c @@ -850,6 +850,72 @@ list_store_test_move_before_single (void) g_object_unref (store); } + +/* iter invalidation */ + +static void +list_store_test_iter_next_invalid (ListStore *fixture, + gconstpointer user_data) +{ + GtkTreePath *path; + GtkTreeIter iter; + + path = gtk_tree_path_new_from_indices (4, -1); + gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store), &iter, path); + gtk_tree_path_free (path); + + g_assert (gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), + &iter) == FALSE); + g_assert (gtk_list_store_iter_is_valid (fixture->store, &iter) == FALSE); + g_assert (iter.stamp == 0); +} + +static void +list_store_test_iter_children_invalid (ListStore *fixture, + gconstpointer user_data) +{ + GtkTreeIter iter, child; + + gtk_tree_model_get_iter_first (GTK_TREE_MODEL (fixture->store), &iter); + g_assert (gtk_list_store_iter_is_valid (fixture->store, &iter) == TRUE); + + g_assert (gtk_tree_model_iter_children (GTK_TREE_MODEL (fixture->store), + &child, &iter) == FALSE); + g_assert (gtk_list_store_iter_is_valid (fixture->store, &child) == FALSE); + g_assert (child.stamp == 0); +} + +static void +list_store_test_iter_nth_child_invalid (ListStore *fixture, + gconstpointer user_data) +{ + GtkTreeIter iter, child; + + gtk_tree_model_get_iter_first (GTK_TREE_MODEL (fixture->store), &iter); + g_assert (gtk_list_store_iter_is_valid (fixture->store, &iter) == TRUE); + + g_assert (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (fixture->store), + &child, &iter, 0) == FALSE); + g_assert (gtk_list_store_iter_is_valid (fixture->store, &child) == FALSE); + g_assert (child.stamp == 0); +} + +static void +list_store_test_iter_parent_invalid (ListStore *fixture, + gconstpointer user_data) +{ + GtkTreeIter iter, child; + + gtk_tree_model_get_iter_first (GTK_TREE_MODEL (fixture->store), &child); + g_assert (gtk_list_store_iter_is_valid (fixture->store, &child) == TRUE); + + g_assert (gtk_tree_model_iter_parent (GTK_TREE_MODEL (fixture->store), + &iter, &child) == FALSE); + g_assert (gtk_list_store_iter_is_valid (fixture->store, &iter) == FALSE); + g_assert (iter.stamp == 0); +} + + /* main */ int @@ -958,5 +1024,19 @@ main (int argc, g_test_add_func ("/list-store/move-before-single", list_store_test_move_before_single); + /* iter invalidation */ + g_test_add ("/list-store/iter-next-invalid", ListStore, NULL, + list_store_setup, list_store_test_iter_next_invalid, + list_store_teardown); + g_test_add ("/list-store/iter-children-invalid", ListStore, NULL, + list_store_setup, list_store_test_iter_children_invalid, + list_store_teardown); + g_test_add ("/list-store/iter-nth-child-invalid", ListStore, NULL, + list_store_setup, list_store_test_iter_nth_child_invalid, + list_store_teardown); + g_test_add ("/list-store/iter-parent-invalid", ListStore, NULL, + list_store_setup, list_store_test_iter_parent_invalid, + list_store_teardown); + return g_test_run (); } diff --git a/gtk/tests/treestore.c b/gtk/tests/treestore.c index e3a85c92fe..c9dbcffba8 100644 --- a/gtk/tests/treestore.c +++ b/gtk/tests/treestore.c @@ -853,6 +853,72 @@ tree_store_test_move_before_single (void) g_object_unref (store); } + +/* iter invalidation */ + +static void +tree_store_test_iter_next_invalid (TreeStore *fixture, + gconstpointer user_data) +{ + GtkTreePath *path; + GtkTreeIter iter; + + path = gtk_tree_path_new_from_indices (4, -1); + gtk_tree_model_get_iter (GTK_TREE_MODEL (fixture->store), &iter, path); + gtk_tree_path_free (path); + + g_assert (gtk_tree_model_iter_next (GTK_TREE_MODEL (fixture->store), + &iter) == FALSE); + g_assert (gtk_tree_store_iter_is_valid (fixture->store, &iter) == FALSE); + g_assert (iter.stamp == 0); +} + +static void +tree_store_test_iter_children_invalid (TreeStore *fixture, + gconstpointer user_data) +{ + GtkTreeIter iter, child; + + gtk_tree_model_get_iter_first (GTK_TREE_MODEL (fixture->store), &iter); + g_assert (gtk_tree_store_iter_is_valid (fixture->store, &iter) == TRUE); + + g_assert (gtk_tree_model_iter_children (GTK_TREE_MODEL (fixture->store), + &child, &iter) == FALSE); + g_assert (gtk_tree_store_iter_is_valid (fixture->store, &child) == FALSE); + g_assert (child.stamp == 0); +} + +static void +tree_store_test_iter_nth_child_invalid (TreeStore *fixture, + gconstpointer user_data) +{ + GtkTreeIter iter, child; + + gtk_tree_model_get_iter_first (GTK_TREE_MODEL (fixture->store), &iter); + g_assert (gtk_tree_store_iter_is_valid (fixture->store, &iter) == TRUE); + + g_assert (gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (fixture->store), + &child, &iter, 0) == FALSE); + g_assert (gtk_tree_store_iter_is_valid (fixture->store, &child) == FALSE); + g_assert (child.stamp == 0); +} + +static void +tree_store_test_iter_parent_invalid (TreeStore *fixture, + gconstpointer user_data) +{ + GtkTreeIter iter, child; + + gtk_tree_model_get_iter_first (GTK_TREE_MODEL (fixture->store), &child); + g_assert (gtk_tree_store_iter_is_valid (fixture->store, &child) == TRUE); + + g_assert (gtk_tree_model_iter_parent (GTK_TREE_MODEL (fixture->store), + &iter, &child) == FALSE); + g_assert (gtk_tree_store_iter_is_valid (fixture->store, &iter) == FALSE); + g_assert (iter.stamp == 0); +} + + /* main */ int @@ -961,5 +1027,19 @@ main (int argc, g_test_add_func ("/tree-store/move-before-single", tree_store_test_move_before_single); + /* iter invalidation */ + g_test_add ("/tree-store/iter-next-invalid", TreeStore, NULL, + tree_store_setup, tree_store_test_iter_next_invalid, + tree_store_teardown); + g_test_add ("/tree-store/iter-children-invalid", TreeStore, NULL, + tree_store_setup, tree_store_test_iter_children_invalid, + tree_store_teardown); + g_test_add ("/tree-store/iter-nth-child-invalid", TreeStore, NULL, + tree_store_setup, tree_store_test_iter_nth_child_invalid, + tree_store_teardown); + g_test_add ("/tree-store/iter-parent-invalid", TreeStore, NULL, + tree_store_setup, tree_store_test_iter_parent_invalid, + tree_store_teardown); + return g_test_run (); }