#include <ccan/compiler/compiler.h>
#include <ccan/hash/hash.h>
#include <ccan/list/list.h>
+#include <ccan/take/take.h>
#include <assert.h>
#include <stdio.h>
#include <stdarg.h>
return list_entry(group->list.n.next, struct group, list.n);
}
-static bool atexit_set = false;
+static bool initialized = false;
+
/* This means valgrind can see leaks. */
-static void unlink_null(void)
+static void tal_cleanup(void)
{
struct group *i, *next;
+ /* Unlink null_parent. */
for (i = next_group(&null_parent.c.group);
i != &null_parent.c.group;
i = next) {
freefn(i);
}
null_parent.c.group.first_child = NULL;
+
+ /* Cleanup any taken pointers. */
+ take_cleanup();
+}
+
+/* For allocation failures inside ccan/take */
+static void take_alloc_failed(const void *p)
+{
+ tal_free(p);
}
#ifndef NDEBUG
if (unlikely(!group->first_child)) {
assert(group == &children->group);
/* This hits on first child appended to null parent. */
- if (unlikely(!atexit_set)) {
- atexit(unlink_null);
- atexit_set = true;
+ if (unlikely(!initialized)) {
+ atexit(tal_cleanup);
+ take_allocfail(take_alloc_failed);
+ initialized = true;
}
/* Link group into this child, make it the first one. */
group->hdr.next = child->prop;
char *tal_strdup(const tal_t *ctx, const char *p)
{
- return tal_dup(ctx, char, p, strlen(p)+1, 0);
+ /* We have to let through NULL for take(). */
+ return tal_dup(ctx, char, p, p ? strlen(p) + 1: 1, 0);
}
char *tal_strndup(const tal_t *ctx, const char *p, size_t n)
{
+ size_t len;
char *ret;
- if (strlen(p) < n)
- n = strlen(p);
- ret = tal_dup(ctx, char, p, n, 1);
+ /* We have to let through NULL for take(). */
+ if (likely(p)) {
+ len = strlen(p);
+ if (len > n)
+ len = n;
+ } else
+ len = n;
+
+ ret = tal_dup(ctx, char, p, len, 1);
if (ret)
- ret[n] = '\0';
+ ret[len] = '\0';
return ret;
}
/* Beware overflow! */
if (n + extra < n || n + extra + sizeof(struct tal_hdr) < n) {
call_error("dup size overflow");
- if (ctx == TAL_TAKE)
+ if (taken(p))
tal_free(p);
return NULL;
}
- if (ctx == TAL_TAKE) {
+ if (taken(p)) {
if (unlikely(!p))
return NULL;
- if (!tal_resize_((void **)&p, n + extra)) {
+ if (unlikely(!tal_resize_((void **)&p, n + extra))) {
+ tal_free(p);
+ return NULL;
+ }
+ if (unlikely(!tal_steal(ctx, p))) {
tal_free(p);
return NULL;
}
char *tal_vasprintf(const tal_t *ctx, const char *fmt, va_list ap)
{
- size_t max = strlen(fmt) * 2;
+ size_t max;
char *buf;
int ret;
- if (ctx == TAL_TAKE)
- buf = tal_arr(tal_parent(fmt), char, max);
- else
- buf = tal_arr(ctx, char, max);
+ if (!fmt && taken(fmt))
+ return NULL;
+ /* A decent guess to start. */
+ max = strlen(fmt) * 2;
+ buf = tal_arr(ctx, char, max);
while (buf) {
va_list ap2;
buf = NULL;
}
}
- if (ctx == TAL_TAKE)
+ if (taken(fmt))
tal_free(fmt);
return buf;
}