From bcba4a298372735787b8f1da58a5d397e6e4e21e Mon Sep 17 00:00:00 2001 From: Angus Salkeld Date: Wed, 12 Sep 2012 10:39:17 +1000 Subject: [PATCH] Fix a crash in ptrie if you iterate over the map in the deleted notifier. Signed-off-by: Angus Salkeld --- lib/trie.c | 17 ++++++++++++++--- tests/check_map.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/lib/trie.c b/lib/trie.c index 7a05c68..4dda823 100644 --- a/lib/trie.c +++ b/lib/trie.c @@ -66,6 +66,17 @@ static struct trie_node *trie_new_node(struct trie *t, struct trie_node *parent) #define TRIE_CHAR2INDEX(ch) (126 - ch) #define TRIE_INDEX2CHAR(idx) (126 - idx) + +static int32_t +trie_node_alive(struct trie_node *node) +{ + if (node->value == NULL || + node->refcount <= 0) { + return QB_FALSE; + } + return QB_TRUE; +} + static struct trie_node * trie_node_next(struct trie_node *node, struct trie_node *root, int all) { @@ -86,7 +97,7 @@ keep_going: } } if (n) { - if (all || n->value) { + if (all || trie_node_alive(n)) { return n; } else { c = n; @@ -112,7 +123,7 @@ keep_going: } while (n == NULL && p != root); if (n) { - if (all || n->value) { + if (all || trie_node_alive(n)) { return n; } if (n == root) { @@ -421,7 +432,7 @@ trie_node_ref(struct trie *t, struct trie_node *node) static void trie_node_deref(struct trie *t, struct trie_node *node) { - if (node->value == NULL) { + if (!trie_node_alive(node)) { return; } node->refcount--; diff --git a/tests/check_map.c b/tests/check_map.c index df3008f..0f064ac 100644 --- a/tests/check_map.c +++ b/tests/check_map.c @@ -45,6 +45,51 @@ static void *notified_new_value = NULL; static void *notified_user_data = NULL; static int32_t notified_event = 0; static int32_t notified_event_prev = 0; +static int32_t notified_events = 0; + +static void +my_map_notification_iter(uint32_t event, + char* key, void* old_value, + void* value, void* user_data) +{ + const char *p; + void *data; + qb_map_t *m = (qb_map_t *)user_data; + qb_map_iter_t *it = qb_map_iter_create(m); + + notified_events++; + + for (p = qb_map_iter_next(it, &data); p; p = qb_map_iter_next(it, &data)) { + printf("%s > %s\n", p, (char*) data); + } + qb_map_iter_free(it); +} + +/* + * create some entries + * add a notifier + * delete an entry + * in the notifier iterate over the map. + */ +static void +test_map_notifications_iter(qb_map_t *m) +{ + int i; + + qb_map_put(m, "k1", "one"); + qb_map_put(m, "k12", "two"); + qb_map_put(m, "k34", "three"); + ck_assert_int_eq(qb_map_count_get(m), 3); + + notified_events = 0; + i = qb_map_notify_add(m, NULL, my_map_notification_iter, + (QB_MAP_NOTIFY_DELETED | + QB_MAP_NOTIFY_RECURSIVE), m); + ck_assert_int_eq(i, 0); + qb_map_rm(m, "k12"); + ck_assert_int_eq(notified_events, 1); + ck_assert_int_eq(qb_map_count_get(m), 2); +} static void test_map_simple(qb_map_t *m, const char *name) @@ -729,6 +774,8 @@ START_TEST(test_trie_notifications) test_map_notifications_prefix(m); m = qb_trie_create(); test_map_notifications_free(m); + m = qb_trie_create(); + test_map_notifications_iter(m); } END_TEST -- 1.7.11.4