]> git.ozlabs.org Git - ccan/commitdiff
tal/str: always create strings which have tal_count() == strlen() + 1.
authorRusty Russell <rusty@rustcorp.com.au>
Fri, 27 Jul 2018 06:25:50 +0000 (15:55 +0930)
committerRusty Russell <rusty@rustcorp.com.au>
Fri, 27 Jul 2018 06:25:50 +0000 (15:55 +0930)
This is least-surprise, but also means callers can sometimes do faster
string handling by avoiding strstr().

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ccan/tal/str/_info
ccan/tal/str/str.c
ccan/tal/str/str.h
ccan/tal/str/test/run-fmt-terminate.c
ccan/tal/str/test/run-string.c
ccan/tal/str/test/run-strndup.c
ccan/tal/str/test/run-strreg.c
ccan/tal/str/test/run.c

index 3037cfde2fba99fcf1e817c0117ed8b89909fee3..9b9c70b6be7f1198e684e23dc0bf892f41fbb04f 100644 (file)
@@ -7,7 +7,9 @@
  *
  * This is a grab bag of functions for string operations, designed to enhance
  * the standard string.h; these are separated from the non-tal-needing
  *
  * This is a grab bag of functions for string operations, designed to enhance
  * the standard string.h; these are separated from the non-tal-needing
- * string utilities in "str.h".
+ * string utilities in "str.h".  Each string created by this library
+ * will have tal_count() equal to strlen() + 1 (assuming you didn't create
+ * a string containing a NUL, such as using tal_fmt("%c", 0)).
  *
  * Example:
  *     #include <ccan/tal/str/str.h>
  *
  * Example:
  *     #include <ccan/tal/str/str.h>
index b00775ab70fc4d652e8739027dc99d813a28d2c9..cec31c752bbe104b3a457ec25f62da7df4d172ef 100644 (file)
@@ -68,6 +68,8 @@ static bool do_vfmt(char **buf, size_t off, const char *fmt, va_list ap)
 
                if (ret < max) {
                        ok = true;
 
                if (ret < max) {
                        ok = true;
+                       /* Make sure tal_count() is correct! */
+                       tal_resize(buf, off + ret + 1);
                        break;
                }
                max *= 2;
                        break;
                }
                max *= 2;
@@ -222,6 +224,8 @@ char *tal_strjoin_(const tal_t *ctx,
                totlen += dlen;
        }
        ret[totlen] = '\0';
                totlen += dlen;
        }
        ret[totlen] = '\0';
+       /* Make sure tal_count() is correct! */
+       tal_resize(&ret, totlen+1);
 out:
        if (taken(strings))
                tal_free(strings);
 out:
        if (taken(strings))
                tal_free(strings);
index bdcb27ea3f8e18b398e81ba2f876154d6118b092..f939484400f57609302eade19c6d4d8599c9e649 100644 (file)
@@ -13,6 +13,8 @@
  * tal_strdup - duplicate a string
  * @ctx: NULL, or tal allocated object to be parent.
  * @p: the string to copy (can be take()).
  * tal_strdup - duplicate a string
  * @ctx: NULL, or tal allocated object to be parent.
  * @p: the string to copy (can be take()).
+ *
+ * The returned string will have tal_count() == strlen() + 1.
  */
 #define tal_strdup(ctx, p) tal_strdup_(ctx, p, TAL_LABEL(char, "[]"))
 char *tal_strdup_(const tal_t *ctx, const char *p TAKES, const char *label);
  */
 #define tal_strdup(ctx, p) tal_strdup_(ctx, p, TAL_LABEL(char, "[]"))
 char *tal_strdup_(const tal_t *ctx, const char *p TAKES, const char *label);
@@ -24,6 +26,7 @@ char *tal_strdup_(const tal_t *ctx, const char *p TAKES, const char *label);
  * @n: the maximum length to copy.
  *
  * Always gives a nul-terminated string, with strlen() <= @n.
  * @n: the maximum length to copy.
  *
  * Always gives a nul-terminated string, with strlen() <= @n.
+ * The returned string will have tal_count() == strlen() + 1.
  */
 #define tal_strndup(ctx, p, n) tal_strndup_(ctx, p, n, TAL_LABEL(char, "[]"))
 char *tal_strndup_(const tal_t *ctx, const char *p TAKES, size_t n,
  */
 #define tal_strndup(ctx, p, n) tal_strndup_(ctx, p, n, TAL_LABEL(char, "[]"))
 char *tal_strndup_(const tal_t *ctx, const char *p TAKES, size_t n,
@@ -33,6 +36,8 @@ char *tal_strndup_(const tal_t *ctx, const char *p TAKES, size_t n,
  * tal_fmt - allocate a formatted string
  * @ctx: NULL, or tal allocated object to be parent.
  * @fmt: the printf-style format (can be take()).
  * tal_fmt - allocate a formatted string
  * @ctx: NULL, or tal allocated object to be parent.
  * @fmt: the printf-style format (can be take()).
+ *
+ * The returned string will have tal_count() == strlen() + 1.
  */
 #define tal_fmt(ctx, ...)                               \
        tal_fmt_(ctx, TAL_LABEL(char, "[]"), __VA_ARGS__)
  */
 #define tal_fmt(ctx, ...)                               \
        tal_fmt_(ctx, TAL_LABEL(char, "[]"), __VA_ARGS__)
@@ -44,6 +49,8 @@ char *tal_fmt_(const tal_t *ctx, const char *label, const char *fmt TAKES,
  * @ctx: NULL, or tal allocated object to be parent.
  * @fmt: the printf-style format (can be take()).
  * @va: the va_list containing the format args.
  * @ctx: NULL, or tal allocated object to be parent.
  * @fmt: the printf-style format (can be take()).
  * @va: the va_list containing the format args.
+ *
+ * The returned string will have tal_count() == strlen() + 1.
  */
 #define tal_vfmt(ctx, fmt, va)                         \
        tal_vfmt_(ctx, fmt, va, TAL_LABEL(char, "[]"))
  */
 #define tal_vfmt(ctx, fmt, va)                         \
        tal_vfmt_(ctx, fmt, va, TAL_LABEL(char, "[]"))
@@ -57,6 +64,7 @@ char *tal_vfmt_(const tal_t *ctx, const char *fmt TAKES, va_list ap,
  * @fmt: the printf-style format (can be take()).
  *
  * Returns false on allocation failure.
  * @fmt: the printf-style format (can be take()).
  *
  * Returns false on allocation failure.
+ * Otherwise tal_count(*@baseptr) == strlen(*@baseptr) + 1.
  */
 bool tal_append_fmt(char **baseptr, const char *fmt TAKES, ...) PRINTF_FMT(2,3);
 
  */
 bool tal_append_fmt(char **baseptr, const char *fmt TAKES, ...) PRINTF_FMT(2,3);
 
@@ -67,6 +75,7 @@ bool tal_append_fmt(char **baseptr, const char *fmt TAKES, ...) PRINTF_FMT(2,3);
  * @va: the va_list containing the format args.
  *
  * Returns false on allocation failure.
  * @va: the va_list containing the format args.
  *
  * Returns false on allocation failure.
+ * Otherwise tal_count(*@baseptr) == strlen(*@baseptr) + 1.
  */
 bool tal_append_vfmt(char **baseptr, const char *fmt TAKES, va_list ap);
 
  */
 bool tal_append_vfmt(char **baseptr, const char *fmt TAKES, va_list ap);
 
@@ -75,6 +84,8 @@ bool tal_append_vfmt(char **baseptr, const char *fmt TAKES, va_list ap);
  * @ctx: NULL, or tal allocated object to be parent.
  * @s1: the first string (can be take()).
  * @s2: the second string (can be take()).
  * @ctx: NULL, or tal allocated object to be parent.
  * @s1: the first string (can be take()).
  * @s2: the second string (can be take()).
+ *
+ * The returned string will have tal_count() == strlen() + 1.
  */
 #define tal_strcat(ctx, s1, s2) tal_strcat_(ctx, s1, s2, TAL_LABEL(char, "[]"))
 char *tal_strcat_(const tal_t *ctx, const char *s1 TAKES, const char *s2 TAKES,
  */
 #define tal_strcat(ctx, s1, s2) tal_strcat_(ctx, s1, s2, TAL_LABEL(char, "[]"))
 char *tal_strcat_(const tal_t *ctx, const char *s1 TAKES, const char *s2 TAKES,
@@ -144,6 +155,8 @@ enum strjoin {
  * return value is allocated using tal.  Each string in @strings is
  * followed by a copy of @delim.
  *
  * return value is allocated using tal.  Each string in @strings is
  * followed by a copy of @delim.
  *
+ * The returned string will have tal_count() == strlen() + 1.
+ *
  * Example:
  *     // Append the string "--EOL" to each line.
  *     static char *append_to_all_lines(const char *string)
  * Example:
  *     // Append the string "--EOL" to each line.
  *     static char *append_to_all_lines(const char *string)
@@ -180,6 +193,7 @@ char *tal_strjoin_(const void *ctx,
  * non-existent matches (eg "([a-z]*)?") the pointer is set to NULL.
  *
  * Allocation failures or malformed regular expressions return false.
  * non-existent matches (eg "([a-z]*)?") the pointer is set to NULL.
  *
  * Allocation failures or malformed regular expressions return false.
+ * The allocated strings will have tal_count() == strlen() + 1.
  *
  * See Also:
  *     regcomp(3), regex(3).
  *
  * See Also:
  *     regcomp(3), regex(3).
index 374ca03a1fed893f017cc89c632c13d41a2507ed..3474cdfa180a46c48ae0e70ed3fc0a59974e94b1 100644 (file)
@@ -11,11 +11,12 @@ int main(void)
        char *str;
        const char *fmt = "";
 
        char *str;
        const char *fmt = "";
 
-       plan_tests(1);
+       plan_tests(2);
        /* GCC complains about empty format string, complains about non-literal
         * with no args... */
        str = tal_fmt(NULL, fmt, "");
        ok1(!strcmp(str, ""));
        /* GCC complains about empty format string, complains about non-literal
         * with no args... */
        str = tal_fmt(NULL, fmt, "");
        ok1(!strcmp(str, ""));
+       ok1(tal_count(str) == strlen(str) + 1);
        tal_free(str);
 
        return exit_status();
        tal_free(str);
 
        return exit_status();
index 533ad01280ed593ee2594514c3bf07e566c9eb48..03d4eb51b9c061283a3a822977b909bacdacd0bf 100644 (file)
@@ -7,7 +7,7 @@ int main(void)
 {
        char *parent, *c;
 
 {
        char *parent, *c;
 
-       plan_tests(32);
+       plan_tests(43);
 
        parent = tal(NULL, char);
        ok1(parent);
 
        parent = tal(NULL, char);
        ok1(parent);
@@ -15,11 +15,13 @@ int main(void)
        c = tal_strdup(parent, "hello");
        ok1(strcmp(c, "hello") == 0);
        ok1(tal_parent(c) == parent);
        c = tal_strdup(parent, "hello");
        ok1(strcmp(c, "hello") == 0);
        ok1(tal_parent(c) == parent);
+       ok1(tal_count(c) == strlen(c) + 1);
        tal_free(c);
 
        c = tal_strndup(parent, "hello", 3);
        ok1(strcmp(c, "hel") == 0);
        ok1(tal_parent(c) == parent);
        tal_free(c);
 
        c = tal_strndup(parent, "hello", 3);
        ok1(strcmp(c, "hel") == 0);
        ok1(tal_parent(c) == parent);
+       ok1(tal_count(c) == strlen(c) + 1);
        tal_free(c);
 
 #ifdef TAL_USE_TALLOC
        tal_free(c);
 
 #ifdef TAL_USE_TALLOC
@@ -30,6 +32,7 @@ int main(void)
        c = tal_dup_arr(parent, char, "hello", 6, 0);
        ok1(strcmp(c, "hello") == 0);
        ok1(strcmp(tal_name(c), "char[]") == 0);
        c = tal_dup_arr(parent, char, "hello", 6, 0);
        ok1(strcmp(c, "hello") == 0);
        ok1(strcmp(tal_name(c), "char[]") == 0);
+       ok1(tal_count(c) == 6);
        ok1(tal_parent(c) == parent);
        tal_free(c);
 
        ok1(tal_parent(c) == parent);
        tal_free(c);
 
@@ -37,26 +40,31 @@ int main(void)
        c = tal_dup_arr(parent, char, "hello", 6, 1);
        ok1(strcmp(c, "hello") == 0);
        ok1(strcmp(tal_name(c), "char[]") == 0);
        c = tal_dup_arr(parent, char, "hello", 6, 1);
        ok1(strcmp(c, "hello") == 0);
        ok1(strcmp(tal_name(c), "char[]") == 0);
+       ok1(tal_count(c) == 7);
        ok1(tal_parent(c) == parent);
        strcat(c, "x");
        tal_free(c);
 
        c = tal_fmt(parent, "hello %s", "there");
        ok1(strcmp(c, "hello there") == 0);
        ok1(tal_parent(c) == parent);
        strcat(c, "x");
        tal_free(c);
 
        c = tal_fmt(parent, "hello %s", "there");
        ok1(strcmp(c, "hello there") == 0);
+       ok1(tal_count(c) == strlen(c) + 1);
        ok1(tal_parent(c) == parent);
        tal_free(c);
 
        c = tal_strcat(parent, "hello ", "there");
        ok1(strcmp(c, "hello there") == 0);
        ok1(tal_parent(c) == parent);
        tal_free(c);
 
        c = tal_strcat(parent, "hello ", "there");
        ok1(strcmp(c, "hello there") == 0);
+       ok1(tal_count(c) == strlen(c) + 1);
        ok1(tal_parent(c) == parent);
 
        /* Make sure take works correctly. */
        c = tal_strcat(parent, take(c), " again");
        ok1(strcmp(c, "hello there again") == 0);
        ok1(tal_parent(c) == parent);
 
        /* Make sure take works correctly. */
        c = tal_strcat(parent, take(c), " again");
        ok1(strcmp(c, "hello there again") == 0);
+       ok1(tal_count(c) == strlen(c) + 1);
        ok1(tal_parent(c) == parent);
        ok1(single_child(parent, c));
 
        c = tal_strcat(parent, "And ", take(c));
        ok1(tal_parent(c) == parent);
        ok1(single_child(parent, c));
 
        c = tal_strcat(parent, "And ", take(c));
+       ok1(tal_count(c) == strlen(c) + 1);
        ok1(strcmp(c, "And hello there again") == 0);
        ok1(tal_parent(c) == parent);
        ok1(single_child(parent, c));
        ok1(strcmp(c, "And hello there again") == 0);
        ok1(tal_parent(c) == parent);
        ok1(single_child(parent, c));
@@ -77,12 +85,15 @@ int main(void)
 
        /* Appending formatted strings. */
        c = tal_strdup(parent, "hi");
 
        /* Appending formatted strings. */
        c = tal_strdup(parent, "hi");
+       ok1(tal_count(c) == strlen(c) + 1);
        ok1(tal_append_fmt(&c, "%s %s", "there", "world"));
        ok1(strcmp(c, "hithere world") == 0);
        ok1(tal_append_fmt(&c, "%s %s", "there", "world"));
        ok1(strcmp(c, "hithere world") == 0);
+       ok1(tal_count(c) == strlen(c) + 1);
        ok1(tal_parent(c) == parent);
 
        ok1(!tal_append_fmt(&c, take(NULL), "there", "world"));
        ok1(strcmp(c, "hithere world") == 0);
        ok1(tal_parent(c) == parent);
 
        ok1(!tal_append_fmt(&c, take(NULL), "there", "world"));
        ok1(strcmp(c, "hithere world") == 0);
+       ok1(tal_count(c) == strlen(c) + 1);
 
        tal_free(parent);
 
 
        tal_free(parent);
 
index 55e35fd4be8c6fb1a8033a311d1ff4d8c17ff001..94689d8c6d7aa6fd52496a192a217a2a32d593c1 100644 (file)
@@ -9,12 +9,13 @@ int main(void)
 {
        char *str, *copy;
 
 {
        char *str, *copy;
 
-       plan_tests(1);
+       plan_tests(2);
        str = malloc(5);
        memcpy(str, "hello", 5);
        /* We should be fine to strndup src without nul terminator. */
        copy = tal_strndup(NULL, str, 5);
        ok1(!strcmp(copy, "hello"));
        str = malloc(5);
        memcpy(str, "hello", 5);
        /* We should be fine to strndup src without nul terminator. */
        copy = tal_strndup(NULL, str, 5);
        ok1(!strcmp(copy, "hello"));
+       ok1(tal_count(copy) == strlen(copy) + 1);
        tal_free(copy);
        free(str);
 
        tal_free(copy);
        free(str);
 
index 93b8602a3c1f8ab067c4406ece439db949ae6b5b..55e244c61e7bba769326a331dee91622bcdca478 100644 (file)
@@ -21,7 +21,7 @@ int main(void)
        /* If it accesses this, it will crash. */
        char **invalid = (char **)1L;
 
        /* If it accesses this, it will crash. */
        char **invalid = (char **)1L;
 
-       plan_tests(41);
+       plan_tests(54);
        /* Simple matching. */
        ok1(tal_strreg(ctx, "hello world!", "hello") == true);
        ok1(tal_strreg(ctx, "hello world!", "hi") == false);
        /* Simple matching. */
        ok1(tal_strreg(ctx, "hello world!", "hello") == true);
        ok1(tal_strreg(ctx, "hello world!", "hi") == false);
@@ -36,12 +36,15 @@ int main(void)
        ok1(streq(a, "hello"));
        /* Allocated off ctx */
        ok1(find_parent(a, ctx));
        ok1(streq(a, "hello"));
        /* Allocated off ctx */
        ok1(find_parent(a, ctx));
+       ok1(tal_count(a) == strlen(a) + 1);
        tal_free(a);
 
        ok1(tal_strreg(ctx, "hello world!", "([a-z]*) ([a-z]+)",
                       &a, &b, invalid) == true);
        ok1(streq(a, "hello"));
        ok1(streq(b, "world"));
        tal_free(a);
 
        ok1(tal_strreg(ctx, "hello world!", "([a-z]*) ([a-z]+)",
                       &a, &b, invalid) == true);
        ok1(streq(a, "hello"));
        ok1(streq(b, "world"));
+       ok1(tal_count(a) == strlen(a) + 1);
+       ok1(tal_count(b) == strlen(b) + 1);
        ok1(find_parent(a, ctx));
        ok1(find_parent(b, ctx));
        tal_free(a);
        ok1(find_parent(a, ctx));
        ok1(find_parent(b, ctx));
        tal_free(a);
@@ -52,6 +55,8 @@ int main(void)
                       &a, &b, invalid) == true);
        ok1(streq(a, "o"));
        ok1(streq(b, "world"));
                       &a, &b, invalid) == true);
        ok1(streq(a, "o"));
        ok1(streq(b, "world"));
+       ok1(tal_count(a) == strlen(a) + 1);
+       ok1(tal_count(b) == strlen(b) + 1);
        tal_free(a);
        tal_free(b);
 
        tal_free(a);
        tal_free(b);
 
@@ -60,6 +65,8 @@ int main(void)
                       &a, &b, invalid) == true);
        ok1(streq(a, "hello world"));
        ok1(streq(b, "hello"));
                       &a, &b, invalid) == true);
        ok1(streq(a, "hello world"));
        ok1(streq(b, "hello"));
+       ok1(tal_count(a) == strlen(a) + 1);
+       ok1(tal_count(b) == strlen(b) + 1);
        tal_free(a);
        tal_free(b);
 
        tal_free(a);
        tal_free(b);
 
@@ -68,6 +75,8 @@ int main(void)
                       &a, &b, invalid) == true);
        ok1(streq(a, "hello world"));
        ok1(streq(b, "hello"));
                       &a, &b, invalid) == true);
        ok1(streq(a, "hello world"));
        ok1(streq(b, "hello"));
+       ok1(tal_count(a) == strlen(a) + 1);
+       ok1(tal_count(b) == strlen(b) + 1);
        tal_free(a);
        tal_free(b);
 
        tal_free(a);
        tal_free(b);
 
@@ -75,6 +84,7 @@ int main(void)
        ok1(tal_strreg(ctx, "hello world!", "((hello|goodbye) world)",
                       &a, NULL, invalid) == true);
        ok1(streq(a, "hello world"));
        ok1(tal_strreg(ctx, "hello world!", "((hello|goodbye) world)",
                       &a, NULL, invalid) == true);
        ok1(streq(a, "hello world"));
+       ok1(tal_count(a) == strlen(a) + 1);
        tal_free(a);
 
        /* No leaks! */
        tal_free(a);
 
        /* No leaks! */
@@ -88,6 +98,7 @@ int main(void)
        a = tal_strdup(ctx, "hello world!");
        ok1(tal_strreg(ctx, take(a), "([a-z]+)", &b, invalid) == true);
        ok1(streq(b, "hello"));
        a = tal_strdup(ctx, "hello world!");
        ok1(tal_strreg(ctx, take(a), "([a-z]+)", &b, invalid) == true);
        ok1(streq(b, "hello"));
+       ok1(tal_count(b) == strlen(b) + 1);
        ok1(tal_parent(b) == ctx);
        tal_free(b);
        ok1(no_children(ctx));
        ok1(tal_parent(b) == ctx);
        tal_free(b);
        ok1(no_children(ctx));
@@ -96,6 +107,7 @@ int main(void)
        a = tal_strdup(ctx, "([a-z]+)");
        ok1(tal_strreg(ctx, "hello world!", take(a), &b, invalid) == true);
        ok1(streq(b, "hello"));
        a = tal_strdup(ctx, "([a-z]+)");
        ok1(tal_strreg(ctx, "hello world!", take(a), &b, invalid) == true);
        ok1(streq(b, "hello"));
+       ok1(tal_count(b) == strlen(b) + 1);
        ok1(tal_parent(b) == ctx);
        tal_free(b);
        ok1(no_children(ctx));
        ok1(tal_parent(b) == ctx);
        tal_free(b);
        ok1(no_children(ctx));
@@ -105,6 +117,7 @@ int main(void)
        ok1(tal_strreg(ctx, take(tal_strdup(ctx, "hello world!")),
                       take(a), &b, invalid) == true);
        ok1(streq(b, "hello"));
        ok1(tal_strreg(ctx, take(tal_strdup(ctx, "hello world!")),
                       take(a), &b, invalid) == true);
        ok1(streq(b, "hello"));
+       ok1(tal_count(b) == strlen(b) + 1);
        ok1(tal_parent(b) == ctx);
        tal_free(b);
        ok1(no_children(ctx));
        ok1(tal_parent(b) == ctx);
        tal_free(b);
        ok1(no_children(ctx));
index a59d940087cfc81e5a39566a51cfb8790934cb03..626434c31043382d63cb683dd0397c98f0426b08 100644 (file)
@@ -15,7 +15,7 @@ int main(void)
        char **split, *str;
        void *ctx;
 
        char **split, *str;
        void *ctx;
 
-       plan_tests(69);
+       plan_tests(78);
        split = tal_strsplit(NULL, "hello  world", " ", STR_EMPTY_OK);
        ok1(!strcmp(split[0], "hello"));
        ok1(!strcmp(split[1], ""));
        split = tal_strsplit(NULL, "hello  world", " ", STR_EMPTY_OK);
        ok1(!strcmp(split[0], "hello"));
        ok1(!strcmp(split[1], ""));
@@ -54,16 +54,20 @@ int main(void)
 
        str = tal_strjoin(NULL, (char **)substrings, ", ", STR_TRAIL);
        ok1(!strcmp(str, "far, bar, baz, b, ba, z, ar, "));
 
        str = tal_strjoin(NULL, (char **)substrings, ", ", STR_TRAIL);
        ok1(!strcmp(str, "far, bar, baz, b, ba, z, ar, "));
+       ok1(tal_count(str) == strlen(str) + 1);
        ctx = str;
        str = tal_strjoin(ctx, (char **)substrings, "", STR_TRAIL);
        ok1(!strcmp(str, "farbarbazbbazar"));
        ctx = str;
        str = tal_strjoin(ctx, (char **)substrings, "", STR_TRAIL);
        ok1(!strcmp(str, "farbarbazbbazar"));
+       ok1(tal_count(str) == strlen(str) + 1);
        ok1(tal_parent(str) == ctx);
        str = tal_strjoin(ctx, (char **)substrings, ", ", STR_NO_TRAIL);
        ok1(tal_parent(str) == ctx);
        ok1(!strcmp(str, "far, bar, baz, b, ba, z, ar"));
        ok1(tal_parent(str) == ctx);
        str = tal_strjoin(ctx, (char **)substrings, ", ", STR_NO_TRAIL);
        ok1(tal_parent(str) == ctx);
        ok1(!strcmp(str, "far, bar, baz, b, ba, z, ar"));
+       ok1(tal_count(str) == strlen(str) + 1);
        str = tal_strjoin(ctx, (char **)substrings, "", STR_NO_TRAIL);
        ok1(!strcmp(str, "farbarbazbbazar"));
        ok1(tal_parent(str) == ctx);
        str = tal_strjoin(ctx, (char **)substrings, "", STR_NO_TRAIL);
        ok1(!strcmp(str, "farbarbazbbazar"));
        ok1(tal_parent(str) == ctx);
+       ok1(tal_count(str) == strlen(str) + 1);
        tal_free(ctx);
 
        ctx = tal_strdup(NULL, "context");
        tal_free(ctx);
 
        ctx = tal_strdup(NULL, "context");
@@ -77,6 +81,7 @@ int main(void)
        str = tal_strdup(ctx, "hello world");
        ok1(tal_check(ctx, NULL));
        ok1(tal_check(str, NULL));
        str = tal_strdup(ctx, "hello world");
        ok1(tal_check(ctx, NULL));
        ok1(tal_check(str, NULL));
+       ok1(tal_count(str) == strlen(str) + 1);
        split = tal_strsplit(ctx, take(str), " ", STR_EMPTY_OK);
        ok1(tal_parent(split) == ctx);
        ok1(!strcmp(split[0], "hello"));
        split = tal_strsplit(ctx, take(str), " ", STR_EMPTY_OK);
        ok1(tal_parent(split) == ctx);
        ok1(!strcmp(split[0], "hello"));
@@ -90,6 +95,7 @@ int main(void)
 
        /* tal_strsplit take delims */
        str = tal_strdup(ctx, " ");
 
        /* tal_strsplit take delims */
        str = tal_strdup(ctx, " ");
+       ok1(tal_count(str) == strlen(str) + 1);
        split = tal_strsplit(ctx, "hello world", take(str), STR_EMPTY_OK);
        ok1(tal_parent(split) == ctx);
        ok1(!strcmp(split[0], "hello"));
        split = tal_strsplit(ctx, "hello world", take(str), STR_EMPTY_OK);
        ok1(tal_parent(split) == ctx);
        ok1(!strcmp(split[0], "hello"));
@@ -124,6 +130,7 @@ int main(void)
        split = tal_strsplit(ctx, "hello world", " ", STR_EMPTY_OK);
        str = tal_strjoin(ctx, take(split), " there ", STR_NO_TRAIL);
        ok1(!strcmp(str, "hello there world"));
        split = tal_strsplit(ctx, "hello world", " ", STR_EMPTY_OK);
        str = tal_strjoin(ctx, take(split), " there ", STR_NO_TRAIL);
        ok1(!strcmp(str, "hello there world"));
+       ok1(tal_count(str) == strlen(str) + 1);
        ok1(tal_parent(str) == ctx);
        /* split is gone... */
        ok1(single_child(ctx, str));
        ok1(tal_parent(str) == ctx);
        /* split is gone... */
        ok1(single_child(ctx, str));
@@ -136,6 +143,7 @@ int main(void)
                          STR_NO_TRAIL);
        ok1(!strcmp(str, "hello there world"));
        ok1(tal_parent(str) == ctx);
                          STR_NO_TRAIL);
        ok1(!strcmp(str, "hello there world"));
        ok1(tal_parent(str) == ctx);
+       ok1(tal_count(str) == strlen(str) + 1);
        tal_free(split);
        /* tmp alloc is gone, str is only remainder. */
        ok1(single_child(ctx, str));
        tal_free(split);
        /* tmp alloc is gone, str is only remainder. */
        ok1(single_child(ctx, str));
@@ -147,6 +155,7 @@ int main(void)
                                                 STR_EMPTY_OK)),
                          take(tal_strdup(ctx, " there ")), STR_NO_TRAIL);
        ok1(!strcmp(str, "hello there world"));
                                                 STR_EMPTY_OK)),
                          take(tal_strdup(ctx, " there ")), STR_NO_TRAIL);
        ok1(!strcmp(str, "hello there world"));
+       ok1(tal_count(str) == strlen(str) + 1);
        ok1(tal_parent(str) == ctx);
        /* tmp allocs are gone, str is only remainder. */
        ok1(single_child(ctx, str));
        ok1(tal_parent(str) == ctx);
        /* tmp allocs are gone, str is only remainder. */
        ok1(single_child(ctx, str));