Browse Source

tal: tal_steal() fix.

We call remove_node() in tal_steal, then re-use the node.  So it's important
that we always unlink the group property from the node for that case.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Rusty Russell 13 years ago
parent
commit
f243444490
2 changed files with 42 additions and 1 deletions
  1. 2 1
      ccan/tal/tal.c
  2. 40 0
      ccan/tal/test/run-steal.c

+ 2 - 1
ccan/tal/tal.c

@@ -455,6 +455,7 @@ static struct tal_hdr *remove_node(struct tal_hdr *t)
 
 		/* Are we the only one? */
 		if (prev == t) {
+			struct prop_hdr *next = (*prop)->next;
 			struct children *c = group->parent_child;
 			/* Is this the group embedded in the child property? */
 			if (group == &c->group) {
@@ -462,9 +463,9 @@ static struct tal_hdr *remove_node(struct tal_hdr *t)
 			} else {
 				/* Empty group, so free it. */
 				list_del_from(&c->group.list, &group->list.n);
-				*prop = group->hdr.next;
 				freefn(group);
 			}
+			*prop = next;
 			return c->parent;
 		} else {
 			/* Move property to next node. */

+ 40 - 0
ccan/tal/test/run-steal.c

@@ -0,0 +1,40 @@
+#include <ccan/tal/tal.h>
+#include <ccan/tal/tal.c>
+#include <ccan/tap/tap.h>
+
+int main(void)
+{
+	char *p[5];
+	unsigned int i;
+
+	plan_tests(9);
+
+	p[0] = NULL;
+	for (i = 1; i < 5; i++)
+		p[i] = tal(p[i-1], char);
+
+	tal_check(NULL, "check");
+	/* Steal node with no children. */
+	ok1(tal_steal(p[0], p[4]) == p[4]);
+	tal_check(NULL, "check");
+	/* Noop steal. */
+	ok1(tal_steal(p[0], p[4]) == p[4]);
+	tal_check(NULL, "check");
+	/* Steal with children. */
+	ok1(tal_steal(p[0], p[1]) == p[1]);
+	tal_check(NULL, "check");
+	/* Noop steal. */
+	ok1(tal_steal(p[0], p[1]) == p[1]);
+	tal_check(NULL, "check");
+	/* Steal from direct child. */
+	ok1(tal_steal(p[0], p[2]) == p[2]);
+	tal_check(NULL, "check");
+
+	ok1(tal_parent(p[1]) == p[0]);
+	ok1(tal_parent(p[2]) == p[0]);
+	ok1(tal_parent(p[3]) == p[2]);
+	ok1(tal_parent(p[4]) == p[0]);
+	tal_free(p[0]);
+
+	return exit_status();
+}