#include <stddef.h>
#include <string.h>
#include <limits.h>
+#include <errno.h>
//#define TAL_DEBUG 1
/* 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) {
} 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. */
void tal_free(const tal_t *ctx)
{
struct tal_hdr *t;
+ int saved_errno = errno;
if (!ctx)
return;
t = debug_tal(to_tal_hdr(ctx));
remove_node(t);
del_tree(t);
+ errno = saved_errno;
}
void *tal_steal_(const tal_t *new_parent, const tal_t *ctx)
tal_t *tal_parent(const tal_t *ctx)
{
struct group *group;
- struct tal_hdr *t = debug_tal(to_tal_hdr(ctx));
+ struct tal_hdr *t;
+
+ if (!ctx)
+ return NULL;
+
+ t = debug_tal(to_tal_hdr(ctx));
while (!(group = find_property(t, GROUP)))
t = t->next;
return from_tal_hdr(group->parent_child->parent);
}
-void *tal_realloc_(tal_t *ctx, size_t size)
+bool tal_resize_(tal_t **ctxp, size_t size)
{
struct tal_hdr *old_t, *t, **prev;
struct group *group;
struct children *child;
- old_t = debug_tal(to_tal_hdr(ctx));
+ old_t = debug_tal(to_tal_hdr(*ctxp));
+
+ /* Don't hand silly sizes to realloc. */
+ if (size >> (CHAR_BIT*sizeof(size) - 1)) {
+ call_error("Reallocation size overflow");
+ return false;
+ }
t = resizefn(old_t, size + sizeof(struct tal_hdr));
if (!t) {
call_error("Reallocation failure");
- tal_free(old_t);
- return NULL;
+ return false;
}
+
+ /* If it didn't move, we're done! */
if (t == old_t)
- return ctx;
+ return true;
update_bounds(t);
/* Fix up linked list pointer. */
assert(child->parent == old_t);
child->parent = t;
}
-
- return from_tal_hdr(debug_tal(t));
+ *ctxp = from_tal_hdr(debug_tal(t));
+ return true;
}
char *tal_strdup(const tal_t *ctx, const char *p)
{
- return tal_memdup(ctx, p, strlen(p)+1);
+ return tal_dup(ctx, char, p, strlen(p)+1, 0);
}
char *tal_strndup(const tal_t *ctx, const char *p, size_t n)
if (strlen(p) < n)
n = strlen(p);
- ret = tal_memdup(ctx, p, n+1);
+ ret = tal_dup(ctx, char, p, n, 1);
if (ret)
ret[n] = '\0';
return ret;
}
-void *tal_memdup(const tal_t *ctx, const void *p, size_t n)
+void *tal_dup_(const tal_t *ctx, const void *p, size_t n, size_t extra,
+ const char *label)
{
void *ret;
- if (ctx == TAL_TAKE)
- return (void *)p;
+ /* Beware overflow! */
+ if (n + extra < n || n + extra + sizeof(struct tal_hdr) < n) {
+ call_error("dup size overflow");
+ if (ctx == TAL_TAKE)
+ tal_free(p);
+ return NULL;
+ }
- ret = tal_arr(ctx, char, n);
+ if (ctx == TAL_TAKE) {
+ if (unlikely(!p))
+ return NULL;
+ if (!tal_resize_((void **)&p, n + extra)) {
+ tal_free(p);
+ return NULL;
+ }
+ return (void *)p;
+ }
+ ret = tal_alloc_(ctx, n + extra, false, label);
if (ret)
memcpy(ret, p, n);
return ret;
if (ret < max)
break;
- buf = tal_resize(buf, max *= 2);
+ if (!tal_resize(&buf, max *= 2)) {
+ tal_free(buf);
+ buf = NULL;
+ }
}
if (ctx == TAL_TAKE)
tal_free(fmt);