tal: use notifier infrastructure for destructors.
[ccan] / ccan / tal / tal.c
1 /* Licensed under BSD-MIT - see LICENSE file for details */
2 #include <ccan/tal/tal.h>
3 #include <ccan/compiler/compiler.h>
4 #include <ccan/list/list.h>
5 #include <ccan/take/take.h>
6 #include <assert.h>
7 #include <stdio.h>
8 #include <stdarg.h>
9 #include <stddef.h>
10 #include <string.h>
11 #include <limits.h>
12 #include <errno.h>
13
14 //#define TAL_DEBUG 1
15
16 #define NOTIFY_IS_DESTRUCTOR 512
17
18 /* 32-bit type field, first byte 0 in either endianness. */
19 enum prop_type {
20         CHILDREN = 0x00c1d500,
21         NAME = 0x00111100,
22         NOTIFIER = 0x00071f00
23 };
24
25 struct tal_hdr {
26         struct list_node list;
27         struct prop_hdr *prop;
28         struct children *parent_child;
29 };
30
31 struct prop_hdr {
32         enum prop_type type;
33         struct prop_hdr *next;
34 };
35
36 struct children {
37         struct prop_hdr hdr; /* CHILDREN */
38         struct tal_hdr *parent;
39         struct list_head children; /* Head of siblings. */
40 };
41
42 struct name {
43         struct prop_hdr hdr; /* NAME */
44         char name[];
45 };
46
47 struct notifier {
48         struct prop_hdr hdr; /* NOTIFIER */
49         enum tal_notify_type types;
50         union {
51                 void (*notifyfn)(tal_t *, enum tal_notify_type, void *);
52                 void (*destroy)(tal_t *); /* If NOTIFY_IS_DESTRUCTOR set */
53         } u;
54 };
55
56 static struct {
57         struct tal_hdr hdr;
58         struct children c;
59 } null_parent = { { { &null_parent.hdr.list, &null_parent.hdr.list },
60                     &null_parent.c.hdr, NULL },
61                   { { CHILDREN, NULL },
62                     &null_parent.hdr,
63                     { { &null_parent.c.children.n,
64                         &null_parent.c.children.n } }
65                   }
66 };
67
68
69 static void *(*allocfn)(size_t size) = malloc;
70 static void *(*resizefn)(void *, size_t size) = realloc;
71 static void (*freefn)(void *) = free;
72 static void (*errorfn)(const char *msg) = (void *)abort;
73
74 static inline void COLD call_error(const char *msg)
75 {
76         errorfn(msg);
77 }
78
79 static bool get_destroying_bit(struct children *parent_child)
80 {
81         return (size_t)parent_child & 1;
82 }
83
84 static void set_destroying_bit(struct children **parent_child)
85 {
86         *parent_child = (void *)((size_t)*parent_child | 1);
87 }
88
89 static struct children *ignore_destroying_bit(struct children *parent_child)
90 {
91         return (void *)((size_t)parent_child & ~(size_t)1);
92 }
93
94 static bool initialized = false;
95
96 /* This means valgrind can see leaks. */
97 static void tal_cleanup(void)
98 {
99         struct tal_hdr *i;
100
101         while ((i = list_top(&null_parent.c.children, struct tal_hdr, list)))
102                 list_del(&i->list);
103
104         /* Cleanup any taken pointers. */
105         take_cleanup();
106 }
107
108 /* For allocation failures inside ccan/take */
109 static void take_alloc_failed(const void *p)
110 {
111         tal_free(p);
112 }
113
114 /* We carefully start all real properties with a zero byte. */
115 static bool is_literal(const struct prop_hdr *prop)
116 {
117         return ((char *)prop)[0] != 0;
118 }
119
120 #ifndef NDEBUG
121 static const void *bounds_start, *bounds_end;
122
123 static void update_bounds(const void *new, size_t size)
124 {
125         if (unlikely(!bounds_start)) {
126                 bounds_start = new;
127                 bounds_end = (char *)new + size;
128         } else if (new < bounds_start)
129                 bounds_start = new;
130         else if ((char *)new + size > (char *)bounds_end)
131                 bounds_end = (char *)new + size;
132 }
133
134 static bool in_bounds(const void *p)
135 {
136         return !p
137                 || (p >= (void *)&null_parent && p <= (void *)(&null_parent + 1))
138                 || (p >= bounds_start && p <= bounds_end);
139 }
140 #else
141 static void update_bounds(const void *new, size_t size)
142 {
143 }
144
145 static bool in_bounds(const void *p)
146 {
147         return true;
148 }
149 #endif
150
151 static void check_bounds(const void *p)
152 {
153         if (!in_bounds(p))
154                 call_error("Not a valid header");
155 }
156
157 static struct tal_hdr *to_tal_hdr(const void *ctx)
158 {
159         struct tal_hdr *t;
160
161         t = (struct tal_hdr *)((char *)ctx - sizeof(struct tal_hdr));
162         check_bounds(t);
163         check_bounds(ignore_destroying_bit(t->parent_child));
164         check_bounds(t->list.next);
165         check_bounds(t->list.prev);
166         if (t->prop && !is_literal(t->prop))
167                 check_bounds(t->prop);
168         return t;
169 }
170
171 static struct tal_hdr *to_tal_hdr_or_null(const void *ctx)
172 {
173         if (!ctx)
174                 return &null_parent.hdr;
175         return to_tal_hdr(ctx);
176 }
177
178 static void *from_tal_hdr(const struct tal_hdr *hdr)
179 {
180         return (void *)(hdr + 1);
181 }
182
183 #ifdef TAL_DEBUG
184 static void *from_tal_hdr_or_null(struct tal_hdr *hdr)
185 {
186         if (hdr == &null_parent.hdr)
187                 return NULL;
188         return from_tal_hdr(hdr);
189 }
190
191 static struct tal_hdr *debug_tal(struct tal_hdr *tal)
192 {
193         tal_check(from_tal_hdr_or_null(tal), "TAL_DEBUG ");
194         return tal;
195 }
196 #else
197 static struct tal_hdr *debug_tal(struct tal_hdr *tal)
198 {
199         return tal;
200 }
201 #endif
202
203 static void notify(const struct tal_hdr *ctx,
204                    enum tal_notify_type type, const void *info)
205 {
206         const struct prop_hdr *p;
207
208         for (p = ctx->prop; p; p = p->next) {
209                 struct notifier *n;
210
211                 if (is_literal(p))
212                         break;
213                 if (p->type != NOTIFIER)
214                         continue;
215                 n = (struct notifier *)p;
216                 if (n->types & type) {
217                         if (n->types & NOTIFY_IS_DESTRUCTOR)
218                                 n->u.destroy(from_tal_hdr(ctx));
219                         else
220                                 n->u.notifyfn(from_tal_hdr(ctx), type,
221                                               (void *)info);
222                 }
223         }
224 }
225
226 static void *allocate(size_t size)
227 {
228         void *ret;
229
230         /* Don't hand silly sizes to malloc. */
231         if (size >> (CHAR_BIT*sizeof(size) - 1)) {
232                 call_error("allocation size overflow");
233                 return NULL;
234         }
235
236         ret = allocfn(size);
237         if (!ret)
238                 call_error("allocation failed");
239         else
240                 update_bounds(ret, size);
241         return ret;
242 }
243
244 static struct prop_hdr **find_property_ptr(const struct tal_hdr *t,
245                                            enum prop_type type)
246 {
247         struct prop_hdr **p;
248
249         for (p = (struct prop_hdr **)&t->prop; *p; p = &(*p)->next) {
250                 if (is_literal(*p)) {
251                         if (type == NAME)
252                                 return p;
253                         break;
254                 }
255                 if ((*p)->type == type)
256                         return p;
257         }
258         return NULL;
259 }
260
261 static void *find_property(const struct tal_hdr *parent, enum prop_type type)
262 {
263         struct prop_hdr **p = find_property_ptr(parent, type);
264
265         if (p)
266                 return *p;
267         return NULL;
268 }
269
270 static void init_property(struct prop_hdr *hdr,
271                           struct tal_hdr *parent,
272                           enum prop_type type)
273 {
274         hdr->type = type;
275         hdr->next = parent->prop;
276         parent->prop = hdr;
277 }
278
279 static struct notifier *add_notifier_property(struct tal_hdr *t,
280                                               enum tal_notify_type types,
281                                               void (*fn)(void *,
282                                                          enum tal_notify_type,
283                                                          void *))
284 {
285         struct notifier *prop = allocate(sizeof(*prop));
286         if (prop) {
287                 init_property(&prop->hdr, t, NOTIFIER);
288                 prop->types = types;
289                 prop->u.notifyfn = fn;
290         }
291         return prop;
292 }
293
294 static bool del_notifier_property(struct tal_hdr *t,
295                                   void (*fn)(tal_t *,
296                                              enum tal_notify_type, void *))
297 {
298         struct prop_hdr **p;
299
300         for (p = (struct prop_hdr **)&t->prop; *p; p = &(*p)->next) {
301                 struct notifier *n;
302
303                 if (is_literal(*p))
304                         break;
305                 if ((*p)->type != NOTIFIER)
306                         continue;
307                 n = (struct notifier *)*p;
308                 if (n->u.notifyfn == fn) {
309                         *p = (*p)->next;
310                         freefn(n);
311                         return true;
312                 }
313         }
314         return false;
315 }
316
317 static struct name *add_name_property(struct tal_hdr *t, const char *name)
318 {
319         struct name *prop;
320
321         prop = allocate(sizeof(*prop) + strlen(name) + 1);
322         if (prop) {
323                 init_property(&prop->hdr, t, NAME);
324                 strcpy(prop->name, name);
325         }
326         return prop;
327 }
328
329 static struct children *add_child_property(struct tal_hdr *parent,
330                                            struct tal_hdr *child)
331 {
332         struct children *prop = allocate(sizeof(*prop));
333         if (prop) {
334                 init_property(&prop->hdr, parent, CHILDREN);
335                 prop->parent = parent;
336                 list_head_init(&prop->children);
337         }
338         return prop;
339 }
340
341 static bool add_child(struct tal_hdr *parent, struct tal_hdr *child)
342 {
343         struct children *children = find_property(parent, CHILDREN);
344
345         if (!children) {
346                 if (unlikely(!initialized)) {
347                         atexit(tal_cleanup);
348                         take_allocfail(take_alloc_failed);
349                         initialized = true;
350                 }
351                 children = add_child_property(parent, child);
352                 if (!children)
353                         return false;
354         }
355         list_add(&children->children, &child->list);
356         child->parent_child = children;
357         return true;
358 }
359
360 static void del_tree(struct tal_hdr *t, const tal_t *orig)
361 {
362         struct prop_hdr **prop, *p, *next;
363
364         /* Already being destroyed?  Don't loop. */
365         if (unlikely(get_destroying_bit(t->parent_child)))
366                 return;
367
368         set_destroying_bit(&t->parent_child);
369
370         /* Call free notifiers. */
371         notify(t, TAL_NOTIFY_FREE, (tal_t *)orig);
372
373         /* Now free children and groups. */
374         prop = find_property_ptr(t, CHILDREN);
375         if (prop) {
376                 struct tal_hdr *i;
377                 struct children *c = (struct children *)*prop;
378
379                 while ((i = list_top(&c->children, struct tal_hdr, list))) {
380                         list_del(&i->list);
381                         del_tree(i, orig);
382                 }
383         }
384
385         /* Finally free our properties. */
386         for (p = t->prop; p && !is_literal(p); p = next) {
387                 next = p->next;
388                 freefn(p);
389         }
390         freefn(t);
391 }
392
393 void *tal_alloc_(const tal_t *ctx, size_t size, bool clear, const char *label)
394 {
395         struct tal_hdr *child, *parent = debug_tal(to_tal_hdr_or_null(ctx));
396
397         child = allocate(sizeof(struct tal_hdr) + size);
398         if (!child)
399                 return NULL;
400         if (clear)
401                 memset(from_tal_hdr(child), 0, size);
402         child->prop = (void *)label;
403         if (!add_child(parent, child)) {
404                 freefn(child);
405                 return NULL;
406         }
407         debug_tal(parent);
408         notify(parent, TAL_NOTIFY_ADD_CHILD, from_tal_hdr(debug_tal(child)));
409         return from_tal_hdr(debug_tal(child));
410 }
411
412 void *tal_free(const tal_t *ctx)
413 {
414         if (ctx) {
415                 struct tal_hdr *t;
416                 int saved_errno = errno;
417                 t = debug_tal(to_tal_hdr(ctx));
418                 notify(ignore_destroying_bit(t->parent_child)->parent,
419                        TAL_NOTIFY_DEL_CHILD, ctx);
420                 list_del(&t->list);
421                 del_tree(t, ctx);
422                 errno = saved_errno;
423         }
424         return NULL;
425 }
426
427 void *tal_steal_(const tal_t *new_parent, const tal_t *ctx)
428 {
429         if (ctx) {
430                 struct tal_hdr *newpar, *t, *old_parent;
431
432                 newpar = debug_tal(to_tal_hdr_or_null(new_parent));
433                 t = debug_tal(to_tal_hdr(ctx));
434
435                 /* Unlink it from old parent. */
436                 list_del(&t->list);
437                 old_parent = ignore_destroying_bit(t->parent_child)->parent;
438
439                 if (unlikely(!add_child(newpar, t))) {
440                         /* We can always add to old parent, becuase it has a
441                          * children property already. */
442                         if (!add_child(old_parent, t))
443                                 abort();
444                         return NULL;
445                 }
446                 debug_tal(newpar);
447                 notify(t, TAL_NOTIFY_STEAL, new_parent);
448         }
449         return (void *)ctx;
450 }
451
452 bool tal_add_destructor_(tal_t *ctx, void (*destroy)(void *me))
453 {
454         tal_t *t = debug_tal(to_tal_hdr(ctx));
455         return add_notifier_property(t, TAL_NOTIFY_FREE|NOTIFY_IS_DESTRUCTOR,
456                                      (void *)destroy);
457 }
458
459 bool tal_add_notifier_(tal_t *ctx, enum tal_notify_type types,
460                        void (*callback)(tal_t *, enum tal_notify_type, void *))
461 {
462         tal_t *t = debug_tal(to_tal_hdr(ctx));
463         struct notifier *n;
464
465         assert(types);
466         assert((types & ~(TAL_NOTIFY_FREE | TAL_NOTIFY_STEAL | TAL_NOTIFY_MOVE
467                           | TAL_NOTIFY_RESIZE | TAL_NOTIFY_RENAME
468                           | TAL_NOTIFY_ADD_CHILD | TAL_NOTIFY_DEL_CHILD
469                           | TAL_NOTIFY_ADD_NOTIFIER
470                           | TAL_NOTIFY_DEL_NOTIFIER)) == 0);
471
472         /* Don't call notifier about itself: set types after! */
473         n = add_notifier_property(t, 0, callback);
474         if (unlikely(!n))
475                 return false;
476
477         notify(t, TAL_NOTIFY_ADD_NOTIFIER, callback);
478         n->types = types;
479         return true;
480 }
481
482 bool tal_del_notifier_(tal_t *ctx,
483                        void (*callback)(tal_t *, enum tal_notify_type, void *))
484 {
485         struct tal_hdr *t = debug_tal(to_tal_hdr(ctx));
486         bool ret;
487
488         ret = del_notifier_property(t, callback);
489         if (ret)
490                 notify(t, TAL_NOTIFY_DEL_NOTIFIER, callback);
491         return ret;
492 }
493
494 bool tal_del_destructor_(tal_t *ctx, void (*destroy)(void *me))
495 {
496         return tal_del_notifier_(ctx, (void *)destroy);
497 }
498
499 bool tal_set_name_(tal_t *ctx, const char *name, bool literal)
500 {
501         struct tal_hdr *t = debug_tal(to_tal_hdr(ctx));
502         struct prop_hdr **prop = find_property_ptr(t, NAME);
503
504         /* Get rid of any old name */
505         if (prop) {
506                 struct name *name = (struct name *)*prop;
507                 if (is_literal(&name->hdr))
508                         *prop = NULL;
509                 else {
510                         *prop = name->hdr.next;
511                         freefn(name);
512                 }
513         }
514
515         if (literal && name[0]) {
516                 struct prop_hdr **p;
517
518                 /* Append literal. */
519                 for (p = &t->prop; *p && !is_literal(*p); p = &(*p)->next);
520                 *p = (struct prop_hdr *)name;
521         } else if (!add_name_property(t, name))
522                 return false;
523
524         debug_tal(t);
525         notify(t, TAL_NOTIFY_RENAME, name);
526         return true;
527 }
528
529 const char *tal_name(const tal_t *t)
530 {
531         struct name *n;
532
533         n = find_property(debug_tal(to_tal_hdr(t)), NAME);
534         if (!n)
535                 return NULL;
536
537         if (is_literal(&n->hdr))
538                 return (const char *)n;
539         return n->name;
540 }
541
542 /* Start one past first child: make stopping natural in circ. list. */
543 static struct tal_hdr *first_child(struct tal_hdr *parent)
544 {
545         struct children *child;
546
547         child = find_property(parent, CHILDREN);
548         if (!child)
549                 return NULL;
550
551         return list_top(&child->children, struct tal_hdr, list);
552 }
553
554 tal_t *tal_first(const tal_t *root)
555 {
556         struct tal_hdr *c, *t = debug_tal(to_tal_hdr_or_null(root));
557
558         c = first_child(t);
559         if (!c)
560                 return NULL;
561         return from_tal_hdr(c);
562 }
563
564 tal_t *tal_next(const tal_t *root, const tal_t *prev)
565 {
566         struct tal_hdr *c, *t = debug_tal(to_tal_hdr(prev)), *top;
567
568         /* Children? */
569         c = first_child(t);
570         if (c)
571                 return from_tal_hdr(c);
572
573         top = to_tal_hdr_or_null(root);
574         do {
575                 struct tal_hdr *next;
576                 struct list_node *end;
577
578                 end = &ignore_destroying_bit(t->parent_child)->children.n;
579
580                 next = list_entry(t->list.next, struct tal_hdr, list);
581                 if (&next->list != end)
582                         return from_tal_hdr(next);
583
584                 /* OK, go back to parent. */
585                 t = ignore_destroying_bit(t->parent_child)->parent;
586         } while (t != top);
587
588         return NULL;
589 }
590
591 tal_t *tal_parent(const tal_t *ctx)
592 {
593         struct tal_hdr *t;
594
595         if (!ctx)
596                 return NULL;
597
598         t = debug_tal(to_tal_hdr(ctx));
599         if (ignore_destroying_bit(t->parent_child)->parent == &null_parent.hdr)
600                 return NULL;
601         return from_tal_hdr(ignore_destroying_bit(t->parent_child)->parent);
602 }
603
604 bool tal_resize_(tal_t **ctxp, size_t size)
605 {
606         struct tal_hdr *old_t, *t;
607         struct children *child;
608
609         old_t = debug_tal(to_tal_hdr(*ctxp));
610
611         /* Don't hand silly sizes to realloc. */
612         if (size >> (CHAR_BIT*sizeof(size) - 1)) {
613                 call_error("Reallocation size overflow");
614                 return false;
615         }
616
617         t = resizefn(old_t, size + sizeof(struct tal_hdr));
618         if (!t) {
619                 call_error("Reallocation failure");
620                 return false;
621         }
622
623         /* If it didn't move, we're done! */
624         if (t != old_t) {
625                 update_bounds(t, size + sizeof(struct tal_hdr));
626
627                 /* Fix up linked list pointers. */
628                 if (list_entry(t->list.next, struct tal_hdr, list) != old_t)
629                         t->list.next->prev = t->list.prev->next = &t->list;
630
631                 /* Fix up child property's parent pointer. */
632                 child = find_property(t, CHILDREN);
633                 if (child) {
634                         assert(child->parent == old_t);
635                         child->parent = t;
636                 }
637                 *ctxp = from_tal_hdr(debug_tal(t));
638                 notify(t, TAL_NOTIFY_MOVE, from_tal_hdr(old_t));
639         }
640         notify(t, TAL_NOTIFY_RESIZE, (void *)size);
641
642         return true;
643 }
644
645 char *tal_strdup(const tal_t *ctx, const char *p)
646 {
647         /* We have to let through NULL for take(). */
648         return tal_dup(ctx, char, p, p ? strlen(p) + 1: 1, 0);
649 }
650
651 char *tal_strndup(const tal_t *ctx, const char *p, size_t n)
652 {
653         size_t len;
654         char *ret;
655
656         /* We have to let through NULL for take(). */
657         if (likely(p)) {
658                 len = strlen(p);
659                 if (len > n)
660                         len = n;
661         } else
662                 len = n;
663
664         ret = tal_dup(ctx, char, p, len, 1);
665         if (ret)
666                 ret[len] = '\0';
667         return ret;
668 }
669
670 void *tal_dup_(const tal_t *ctx, const void *p, size_t n, size_t extra,
671                const char *label)
672 {
673         void *ret;
674
675         /* Beware overflow! */
676         if (n + extra < n || n + extra + sizeof(struct tal_hdr) < n) {
677                 call_error("dup size overflow");
678                 if (taken(p))
679                         tal_free(p);
680                 return NULL;
681         }
682
683         if (taken(p)) {
684                 if (unlikely(!p))
685                         return NULL;
686                 if (unlikely(!tal_resize_((void **)&p, n + extra)))
687                         return tal_free(p);
688                 if (unlikely(!tal_steal(ctx, p)))
689                         return tal_free(p);
690                 return (void *)p;
691         }
692         ret = tal_alloc_(ctx, n + extra, false, label);
693         if (ret)
694                 memcpy(ret, p, n);
695         return ret;
696 }
697
698 char *tal_asprintf(const tal_t *ctx, const char *fmt, ...)
699 {
700         va_list ap;
701         char *ret;
702
703         va_start(ap, fmt);
704         ret = tal_vasprintf(ctx, fmt, ap);
705         va_end(ap);
706
707         return ret;
708 }
709
710 char *tal_vasprintf(const tal_t *ctx, const char *fmt, va_list ap)
711 {
712         size_t max;
713         char *buf;
714         int ret;
715
716         if (!fmt && taken(fmt))
717                 return NULL;
718
719         /* A decent guess to start. */
720         max = strlen(fmt) * 2;
721         buf = tal_arr(ctx, char, max);
722         while (buf) {
723                 va_list ap2;
724
725                 va_copy(ap2, ap);
726                 ret = vsnprintf(buf, max, fmt, ap2);
727                 va_end(ap2);
728
729                 if (ret < max)
730                         break;
731                 if (!tal_resize(&buf, max *= 2))
732                         buf = tal_free(buf);
733         }
734         if (taken(fmt))
735                 tal_free(fmt);
736         return buf;
737 }
738
739 void tal_set_backend(void *(*alloc_fn)(size_t size),
740                      void *(*resize_fn)(void *, size_t size),
741                      void (*free_fn)(void *),
742                      void (*error_fn)(const char *msg))
743 {
744         if (alloc_fn)
745                 allocfn = alloc_fn;
746         if (resize_fn)
747                 resizefn = resize_fn;
748         if (free_fn)
749                 freefn = free_fn;
750         if (error_fn)
751                 errorfn = error_fn;
752 }
753
754 #ifdef CCAN_TAL_DEBUG
755 static void dump_node(unsigned int indent, const struct tal_hdr *t)
756 {
757         unsigned int i;
758         const struct prop_hdr *p;
759
760         for (i = 0; i < indent; i++)
761                 printf("  ");
762         printf("%p", t);
763         for (p = t->prop; p; p = p->next) {
764                 struct children *c;
765                 struct name *n;
766                 struct notifier *no;
767                 if (is_literal(p)) {
768                         printf(" \"%s\"", (const char *)p);
769                         break;
770                 }
771                 switch (p->type) {
772                 case CHILDREN:
773                         c = (struct children *)p;
774                         printf(" CHILDREN(%p):parent=%p,children={%p,%p}\n",
775                                p, c->parent,
776                                c->children.n.prev, c->children.n.next);
777                         break;
778                 case NAME:
779                         n = (struct name *)p;
780                         printf(" NAME(%p):%s", p, n->name);
781                         break;
782                 case NOTIFIER:
783                         no = (struct notifier *)p;
784                         printf(" NOTIFIER(%p):fn=%p", p, no->u.notifyfn);
785                         break;
786                 default:
787                         printf(" **UNKNOWN(%p):%i**", p, p->type);
788                 }
789         }
790         printf("\n");
791 }
792
793 static void tal_dump_(unsigned int level, const struct tal_hdr *t)
794 {
795         struct children *children;
796
797         dump_node(level, t);
798
799         children = find_property(t, CHILDREN);
800         if (children) {
801                 struct tal_hdr *i;
802
803                 list_for_each(&children->children, i, list)
804                         tal_dump_(level + 1, i);
805         }
806 }
807
808 void tal_dump(void)
809 {
810         tal_dump_(0, &null_parent.hdr);
811 }
812 #endif /* CCAN_TAL_DEBUG */
813
814 #ifndef NDEBUG
815 static bool check_err(struct tal_hdr *t, const char *errorstr,
816                       const char *errmsg)
817 {
818         if (errorstr) {
819                 /* Try not to malloc: it may be corrupted. */
820                 char msg[strlen(errorstr) + 20 + strlen(errmsg) + 1];
821                 sprintf(msg, "%s:%p %s", errorstr, from_tal_hdr(t), errmsg);
822                 call_error(msg);
823         }
824         return false;
825 }
826
827 static bool check_node(struct children *parent_child,
828                        struct tal_hdr *t, const char *errorstr)
829 {
830         struct prop_hdr *p;
831         struct name *name = NULL;
832         struct children *children = NULL;
833
834         if (!in_bounds(t))
835                 return check_err(t, errorstr, "invalid pointer");
836
837         if (ignore_destroying_bit(t->parent_child) != parent_child)
838                 return check_err(t, errorstr, "incorrect parent");
839
840         for (p = t->prop; p; p = p->next) {
841                 if (is_literal(p)) {
842                         if (name)
843                                 return check_err(t, errorstr,
844                                                  "has extra literal");
845                         name = (struct name *)p;
846                         break;
847                 }
848                 if (!in_bounds(p))
849                         return check_err(t, errorstr,
850                                          "has bad property pointer");
851
852                 switch (p->type) {
853                 case CHILDREN:
854                         if (children)
855                                 return check_err(t, errorstr,
856                                                  "has two child nodes");
857                         children = (struct children *)p;
858                         break;
859                 case NOTIFIER:
860                         break;
861                 case NAME:
862                         if (name)
863                                 return check_err(t, errorstr,
864                                                  "has two names");
865                         name = (struct name *)p;
866                         break;
867                 default:
868                         return check_err(t, errorstr, "has unknown property");
869                 }
870         }
871         if (children) {
872                 struct tal_hdr *i;
873
874                 if (!list_check(&children->children, errorstr))
875                         return false;
876                 list_for_each(&children->children, i, list) {
877                         if (!check_node(children, i, errorstr))
878                                 return false;
879                 }
880         }
881         return true;
882 }
883
884 bool tal_check(const tal_t *ctx, const char *errorstr)
885 {
886         struct tal_hdr *t = to_tal_hdr_or_null(ctx);
887
888         return check_node(ignore_destroying_bit(t->parent_child), t, errorstr);
889 }
890 #else /* NDEBUG */
891 bool tal_check(const tal_t *ctx, const char *errorstr)
892 {
893         return true;
894 }
895 #endif