Fix a crash in ptrie if you iterate over the map in the deleted notifier.

Signed-off-by: Angus Salkeld <asalkeld@redhat.com>
This commit is contained in:
Angus Salkeld 2012-09-12 10:39:17 +10:00
parent aedcb97690
commit bcba4a2983
2 changed files with 61 additions and 3 deletions

View File

@ -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--;

View File

@ -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