Commit 7ca46909 authored by Rusty Russell's avatar Rusty Russell

tal: Make tal_resize() easier to use.

Instead of trying to force people to use the return value, pass a pointer.
This makes it easier if you want to handle failure: no overwriting the old
pointer!
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent 34c2962d
...@@ -657,22 +657,23 @@ tal_t *tal_parent(const tal_t *ctx) ...@@ -657,22 +657,23 @@ tal_t *tal_parent(const tal_t *ctx)
return from_tal_hdr(group->parent_child->parent); 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 tal_hdr *old_t, *t, **prev;
struct group *group; struct group *group;
struct children *child; struct children *child;
old_t = debug_tal(to_tal_hdr(ctx)); old_t = debug_tal(to_tal_hdr(*ctxp));
t = resizefn(old_t, size + sizeof(struct tal_hdr)); t = resizefn(old_t, size + sizeof(struct tal_hdr));
if (!t) { if (!t) {
call_error("Reallocation failure"); call_error("Reallocation failure");
tal_free(old_t); return false;
return NULL;
} }
/* If it didn't move, we're done! */
if (t == old_t) if (t == old_t)
return ctx; return true;
update_bounds(t); update_bounds(t);
/* Fix up linked list pointer. */ /* Fix up linked list pointer. */
...@@ -692,8 +693,8 @@ void *tal_realloc_(tal_t *ctx, size_t size) ...@@ -692,8 +693,8 @@ void *tal_realloc_(tal_t *ctx, size_t size)
assert(child->parent == old_t); assert(child->parent == old_t);
child->parent = t; child->parent = t;
} }
*ctxp = from_tal_hdr(debug_tal(t));
return from_tal_hdr(debug_tal(t)); return true;
} }
char *tal_strdup(const tal_t *ctx, const char *p) char *tal_strdup(const tal_t *ctx, const char *p)
...@@ -758,7 +759,10 @@ char *tal_vasprintf(const tal_t *ctx, const char *fmt, va_list ap) ...@@ -758,7 +759,10 @@ char *tal_vasprintf(const tal_t *ctx, const char *fmt, va_list ap)
if (ret < max) if (ret < max)
break; break;
buf = tal_resize(buf, max *= 2); if (!tal_resize(&buf, max *= 2)) {
tal_free(buf);
buf = NULL;
}
} }
if (ctx == TAL_TAKE) if (ctx == TAL_TAKE)
tal_free(fmt); tal_free(fmt);
......
...@@ -38,6 +38,10 @@ typedef void tal_t; ...@@ -38,6 +38,10 @@ typedef void tal_t;
* Allocates a specific type, with a given parent context. The name * Allocates a specific type, with a given parent context. The name
* of the object is a string of the type, but if CCAN_TAL_DEBUG is * of the object is a string of the type, but if CCAN_TAL_DEBUG is
* defined it also contains the file and line which allocated it. * defined it also contains the file and line which allocated it.
*
* Example:
* int *p = tal(NULL, int);
* *p = 1;
*/ */
#define tal(ctx, type) \ #define tal(ctx, type) \
((type *)tal_alloc_((ctx), sizeof(type), false, TAL_LABEL(type, ""))) ((type *)tal_alloc_((ctx), sizeof(type), false, TAL_LABEL(type, "")))
...@@ -48,6 +52,10 @@ typedef void tal_t; ...@@ -48,6 +52,10 @@ typedef void tal_t;
* @type: the type to allocate. * @type: the type to allocate.
* *
* Equivalent to tal() followed by memset() to zero. * Equivalent to tal() followed by memset() to zero.
*
* Example:
* p = talz(NULL, int);
* assert(*p == 0);
*/ */
#define talz(ctx, type) \ #define talz(ctx, type) \
((type *)tal_alloc_((ctx), sizeof(type), true, TAL_LABEL(type, ""))) ((type *)tal_alloc_((ctx), sizeof(type), true, TAL_LABEL(type, "")))
...@@ -60,6 +68,9 @@ typedef void tal_t; ...@@ -60,6 +68,9 @@ typedef void tal_t;
* children (recursively) before finally freeing the memory. * children (recursively) before finally freeing the memory.
* *
* Note: errno is preserved by this call. * Note: errno is preserved by this call.
*
* Example:
* tal_free(p);
*/ */
void tal_free(const tal_t *p); void tal_free(const tal_t *p);
...@@ -68,6 +79,11 @@ void tal_free(const tal_t *p); ...@@ -68,6 +79,11 @@ void tal_free(const tal_t *p);
* @ctx: NULL, or tal allocated object to be parent. * @ctx: NULL, or tal allocated object to be parent.
* @type: the type to allocate. * @type: the type to allocate.
* @count: the number to allocate. * @count: the number to allocate.
*
* Example:
* p = tal_arr(NULL, int, 2);
* p[0] = 0;
* p[1] = 1;
*/ */
#define tal_arr(ctx, type, count) \ #define tal_arr(ctx, type, count) \
((type *)tal_alloc_((ctx), tal_sizeof_(sizeof(type), (count)), false, \ ((type *)tal_alloc_((ctx), tal_sizeof_(sizeof(type), (count)), false, \
...@@ -78,21 +94,27 @@ void tal_free(const tal_t *p); ...@@ -78,21 +94,27 @@ void tal_free(const tal_t *p);
* @ctx: NULL, or tal allocated object to be parent. * @ctx: NULL, or tal allocated object to be parent.
* @type: the type to allocate. * @type: the type to allocate.
* @count: the number to allocate. * @count: the number to allocate.
*
* Example:
* p = tal_arrz(NULL, int, 2);
* assert(p[0] == 0 && p[1] == 0);
*/ */
#define tal_arrz(ctx, type, count) \ #define tal_arrz(ctx, type, count) \
((type *)tal_alloc_((ctx), tal_sizeof_(sizeof(type), (count)), true, \ ((type *)tal_alloc_((ctx), tal_sizeof_(sizeof(type), (count)), true, \
TAL_LABEL(type, "[]"))) TAL_LABEL(type, "[]")))
/** /**
* tal_resize - enlarge or reduce a tal_arr(z). * tal_resize - enlarge or reduce a tal_arr[z].
* @p: The tal allocated array to resize. * @p: A pointer to the tal allocated array to resize.
* @count: the number to allocate. * @count: the number to allocate.
* *
* This returns the new pointer, or NULL (and destroys the old one) * This returns true on success (and may move *@p), or false on failure.
* on failure. *
* Example:
* tal_resize(&p, 100);
*/ */
#define tal_resize(p, count) \ #define tal_resize(p, count) \
((tal_typeof(p) tal_realloc_((p), tal_sizeof_(sizeof(*p), (count))))) tal_resize_((void **)(p), tal_sizeof_(sizeof**(p), (count)))
/** /**
* tal_steal - change the parent of a tal-allocated pointer. * tal_steal - change the parent of a tal-allocated pointer.
...@@ -102,7 +124,7 @@ void tal_free(const tal_t *p); ...@@ -102,7 +124,7 @@ void tal_free(const tal_t *p);
* This may need to perform an allocation, in which case it may fail; thus * This may need to perform an allocation, in which case it may fail; thus
* it can return NULL, otherwise returns @ptr. * it can return NULL, otherwise returns @ptr.
* *
* Weird macro avoids gcc's 'warning: value computed is not used'. * Note: weird macro avoids gcc's 'warning: value computed is not used'.
*/ */
#if HAVE_STATEMENT_EXPR #if HAVE_STATEMENT_EXPR
#define tal_steal(ctx, ptr) \ #define tal_steal(ctx, ptr) \
...@@ -301,7 +323,7 @@ void *tal_alloc_(const tal_t *ctx, size_t bytes, bool clear, const char *label); ...@@ -301,7 +323,7 @@ void *tal_alloc_(const tal_t *ctx, size_t bytes, bool clear, const char *label);
tal_t *tal_steal_(const tal_t *new_parent, const tal_t *t); tal_t *tal_steal_(const tal_t *new_parent, const tal_t *t);
void *tal_realloc_(tal_t *ctx, size_t size); bool tal_resize_(tal_t **ctxp, size_t size);
bool tal_add_destructor_(tal_t *ctx, void (*destroy)(void *me)); bool tal_add_destructor_(tal_t *ctx, void (*destroy)(void *me));
......
...@@ -15,6 +15,15 @@ static void *failing_alloc(size_t len) ...@@ -15,6 +15,15 @@ static void *failing_alloc(size_t len)
return malloc(len); return malloc(len);
} }
static void *failing_realloc(void *p, size_t len)
{
if (alloc_count++ == when_to_fail)
return NULL;
return realloc(p, len);
}
static void nofail_on_error(const char *msg) static void nofail_on_error(const char *msg)
{ {
diag("ERROR: %s", msg); diag("ERROR: %s", msg);
...@@ -27,12 +36,12 @@ static void destroy_p(void *p) ...@@ -27,12 +36,12 @@ static void destroy_p(void *p)
int main(void) int main(void)
{ {
void *p, *c1, *c2; char *p, *c1, *c2;
bool success; bool success;
plan_tests(21); plan_tests(25);
tal_set_backend(failing_alloc, NULL, NULL, nofail_on_error); tal_set_backend(failing_alloc, failing_realloc, NULL, nofail_on_error);
/* Fail at each possible point in an allocation. */ /* Fail at each possible point in an allocation. */
when_to_fail = err_count = 0; when_to_fail = err_count = 0;
...@@ -56,6 +65,23 @@ int main(void) ...@@ -56,6 +65,23 @@ int main(void)
ok1(when_to_fail > 1); ok1(when_to_fail > 1);
ok1(err_count == when_to_fail - 1); ok1(err_count == when_to_fail - 1);
/* Now during resize. */
c2 = c1;
when_to_fail = err_count = 0;
for (;;) {
alloc_count = 0;
if (tal_resize(&c1, 100))
break;
/* Failing alloc will not change pointer. */
ok1(c1 == c2);
when_to_fail++;
};
ok1(alloc_count == 1);
ok1(when_to_fail == 1);
ok1(err_count == 1);
/* Make sure it's really resized. */
memset(c1, 1, 100);
/* Now for second child. */ /* Now for second child. */
when_to_fail = err_count = 0; when_to_fail = err_count = 0;
do { do {
......
...@@ -7,7 +7,7 @@ int main(void) ...@@ -7,7 +7,7 @@ int main(void)
char *parent, *c[4]; char *parent, *c[4];
int i; int i;
plan_tests(9); plan_tests(11);
parent = tal(NULL, char); parent = tal(NULL, char);
ok1(parent); ok1(parent);
...@@ -33,6 +33,14 @@ int main(void) ...@@ -33,6 +33,14 @@ int main(void)
strcpy(c[i], "abc"); strcpy(c[i], "abc");
tal_free(c[i]); tal_free(c[i]);
} }
/* Resizing. */
c[0] = tal_arrz(parent, char, 4);
ok1(tal_resize(&c[0], 6));
strcpy(c[0], "hello");
tal_free(c[0]);
ok1(tal_first(parent) == NULL);
tal_free(parent); tal_free(parent);
return exit_status(); return exit_status();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment