tal: add tal_expand().
authorRusty Russell <rusty@rustcorp.com.au>
Mon, 3 Dec 2012 08:59:39 +0000 (19:29 +1030)
committerRusty Russell <rusty@rustcorp.com.au>
Mon, 3 Dec 2012 08:59:39 +0000 (19:29 +1030)
Helper to reallocate and append to an array.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ccan/tal/tal.c
ccan/tal/tal.h
ccan/tal/test/run-expand.c [new file with mode: 0644]
ccan/tal/test/run-overflow.c

index 4f7d56784dd9f2ffb46131f98b7f6288981d1c62..5c0aec07990dcbafc44b5e7bf075ac8c68ba5641 100644 (file)
@@ -712,6 +712,37 @@ bool tal_resize_(tal_t **ctxp, size_t size, size_t count)
        return true;
 }
 
+bool tal_expand_(tal_t **ctxp, const void *src, size_t size, size_t count)
+{
+       struct length *l;
+       bool ret = false;
+
+       l = find_property(debug_tal(to_tal_hdr(*ctxp)), LENGTH);
+
+       /* Check for additive overflow */
+       if (l->count + count < count) {
+               call_error("dup size overflow");
+               goto out;
+       }
+
+       /* Don't point src inside thing we're expanding! */
+       assert(src < *ctxp
+              || (char *)src >= (char *)(*ctxp) + (size * l->count));
+
+       /* Note: updates l->count. */
+       if (!tal_resize_(ctxp, size, l->count + count))
+               goto out;
+
+       memcpy((char *)*ctxp + size * (l->count - count),
+              src, count * size);
+       ret = true;
+
+out:
+       if (taken(src))
+               tal_free(src);
+       return ret;
+}
+
 void *tal_dup_(const tal_t *ctx, const void *p, size_t size,
               size_t n, size_t extra, bool add_count,
               const char *label)
index 091eb034c1fbfb979f30f9021266c7c93278e695..28be3f2034c133b276bc1a9e7f803df6fa033469 100644 (file)
@@ -305,6 +305,28 @@ void tal_set_backend(void *(*alloc_fn)(size_t size),
                     void (*free_fn)(void *),
                     void (*error_fn)(const char *msg));
 
+/**
+ * tal_expand - expand a tal array with contents.
+ * @a1p: a pointer to the tal array to expand.
+ * @a2: the second array (can be take()).
+ * @num2: the number of elements in the second array.
+ *
+ * Note that *@a1 and @a2 should be the same type.  tal_count(@a1) will
+ * be increased by @num2.
+ *
+ * Example:
+ *     int *arr1 = tal_arrz(NULL, int, 2);
+ *     int arr2[2] = { 1, 3 };
+ *
+ *     tal_expand(&arr1, arr2, 2);
+ *     assert(tal_count(arr1) == 4);
+ *     assert(arr1[2] == 1);
+ *     assert(arr1[3] == 3);
+ */
+#define tal_expand(a1p, a2, num2)                              \
+       tal_expand_((void **)(a1p), (a2), sizeof**(a1p),        \
+                   (num2) + 0*sizeof(*(a1p) == (a2)))
+
 
 /**
  * tal_check - set the allocation or error functions to use
@@ -374,6 +396,7 @@ void *tal_dup_(const tal_t *ctx, const void *p, size_t size,
 tal_t *tal_steal_(const tal_t *new_parent, const tal_t *t);
 
 bool tal_resize_(tal_t **ctxp, size_t size, size_t count);
+bool tal_expand_(tal_t **ctxp, const void *src, size_t size, size_t count);
 
 bool tal_add_destructor_(const tal_t *ctx, void (*destroy)(void *me));
 bool tal_del_destructor_(const tal_t *ctx, void (*destroy)(void *me));
diff --git a/ccan/tal/test/run-expand.c b/ccan/tal/test/run-expand.c
new file mode 100644 (file)
index 0000000..2edb31f
--- /dev/null
@@ -0,0 +1,32 @@
+#include <ccan/tal/tal.h>
+#include <ccan/tal/tal.c>
+#include <ccan/tap/tap.h>
+
+int main(void)
+{
+       int *a;
+       const int arr[] = { 1, 2 };
+
+       plan_tests(13);
+
+       a = tal_arrz(NULL, int, 1);
+       ok1(a);
+
+       ok1(tal_expand(&a, arr, 2));
+       ok1(tal_count(a) == 3);
+       ok1(a[0] == 0);
+       ok1(a[1] == 1);
+       ok1(a[2] == 2);
+
+       ok1(tal_expand(&a, take(tal_arrz(NULL, int, 1)), 1));
+       ok1(tal_count(a) == 4);
+       ok1(a[0] == 0);
+       ok1(a[1] == 1);
+       ok1(a[2] == 2);
+       ok1(a[3] == 0);
+       ok1(tal_first(NULL) == a && !tal_next(NULL, a));
+
+       tal_free(a);
+
+       return exit_status();
+}
index 989fcd2aba2eee5e9339e06abdd3be4eb7549644..c5daf97d2794b99966dd59e959cdab7d649be87f 100644 (file)
@@ -13,8 +13,9 @@ int main(void)
 {
        void *p;
        int *pi, *origpi;
+       char *cp;
 
-       plan_tests(26);
+       plan_tests(30);
 
        tal_set_backend(NULL, NULL, NULL, my_error);
 
@@ -81,5 +82,17 @@ int main(void)
        ok1(error_count == 1);
        ok1(!tal_first(NULL));
 
+       /* Overflow on expand addition. */
+       cp = tal_arr(p, char, 100);
+       ok1(!tal_expand(&cp, NULL, (size_t)-99UL));
+       ok1(error_count == 2);
+       tal_free(cp);
+
+       /* Overflow when multiplied by size */
+       origpi = tal_arr(NULL, int, 100);
+       ok1(!tal_expand(&origpi, NULL, (size_t)-1UL / sizeof(int)));
+       ok1(error_count == 3);
+       tal_free(origpi);
+
        return exit_status();
 }