From 55d814230f7fb628bb5303cd53498209c7928040 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 27 Jul 2018 15:55:50 +0930 Subject: [PATCH] tal/str: always create strings which have tal_count() == strlen() + 1. This is least-surprise, but also means callers can sometimes do faster string handling by avoiding strstr(). Signed-off-by: Rusty Russell --- ccan/tal/str/_info | 4 +++- ccan/tal/str/str.c | 4 ++++ ccan/tal/str/str.h | 14 ++++++++++++++ ccan/tal/str/test/run-fmt-terminate.c | 3 ++- ccan/tal/str/test/run-string.c | 13 ++++++++++++- ccan/tal/str/test/run-strndup.c | 3 ++- ccan/tal/str/test/run-strreg.c | 15 ++++++++++++++- ccan/tal/str/test/run.c | 11 ++++++++++- 8 files changed, 61 insertions(+), 6 deletions(-) diff --git a/ccan/tal/str/_info b/ccan/tal/str/_info index 3037cfde..9b9c70b6 100644 --- a/ccan/tal/str/_info +++ b/ccan/tal/str/_info @@ -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 - * 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 diff --git a/ccan/tal/str/str.c b/ccan/tal/str/str.c index b00775ab..cec31c75 100644 --- a/ccan/tal/str/str.c +++ b/ccan/tal/str/str.c @@ -68,6 +68,8 @@ static bool do_vfmt(char **buf, size_t off, const char *fmt, va_list ap) if (ret < max) { ok = true; + /* Make sure tal_count() is correct! */ + tal_resize(buf, off + ret + 1); break; } max *= 2; @@ -222,6 +224,8 @@ char *tal_strjoin_(const tal_t *ctx, totlen += dlen; } ret[totlen] = '\0'; + /* Make sure tal_count() is correct! */ + tal_resize(&ret, totlen+1); out: if (taken(strings)) tal_free(strings); diff --git a/ccan/tal/str/str.h b/ccan/tal/str/str.h index bdcb27ea..f9394844 100644 --- a/ccan/tal/str/str.h +++ b/ccan/tal/str/str.h @@ -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()). + * + * 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); @@ -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. + * 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, @@ -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()). + * + * The returned string will have tal_count() == strlen() + 1. */ #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. + * + * The returned string will have tal_count() == strlen() + 1. */ #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. + * Otherwise tal_count(*@baseptr) == strlen(*@baseptr) + 1. */ 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. + * Otherwise tal_count(*@baseptr) == strlen(*@baseptr) + 1. */ 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()). + * + * 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, @@ -144,6 +155,8 @@ enum strjoin { * 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) @@ -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. + * The allocated strings will have tal_count() == strlen() + 1. * * See Also: * regcomp(3), regex(3). diff --git a/ccan/tal/str/test/run-fmt-terminate.c b/ccan/tal/str/test/run-fmt-terminate.c index 374ca03a..3474cdfa 100644 --- a/ccan/tal/str/test/run-fmt-terminate.c +++ b/ccan/tal/str/test/run-fmt-terminate.c @@ -11,11 +11,12 @@ int main(void) 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, "")); + ok1(tal_count(str) == strlen(str) + 1); tal_free(str); return exit_status(); diff --git a/ccan/tal/str/test/run-string.c b/ccan/tal/str/test/run-string.c index 533ad012..03d4eb51 100644 --- a/ccan/tal/str/test/run-string.c +++ b/ccan/tal/str/test/run-string.c @@ -7,7 +7,7 @@ int main(void) { char *parent, *c; - plan_tests(32); + plan_tests(43); 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); + 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); + ok1(tal_count(c) == strlen(c) + 1); 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); + ok1(tal_count(c) == 6); 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); + 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_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_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_count(c) == strlen(c) + 1); 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)); @@ -77,12 +85,15 @@ int main(void) /* 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_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_count(c) == strlen(c) + 1); tal_free(parent); diff --git a/ccan/tal/str/test/run-strndup.c b/ccan/tal/str/test/run-strndup.c index 55e35fd4..94689d8c 100644 --- a/ccan/tal/str/test/run-strndup.c +++ b/ccan/tal/str/test/run-strndup.c @@ -9,12 +9,13 @@ int main(void) { 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")); + ok1(tal_count(copy) == strlen(copy) + 1); tal_free(copy); free(str); diff --git a/ccan/tal/str/test/run-strreg.c b/ccan/tal/str/test/run-strreg.c index 93b8602a..55e244c6 100644 --- a/ccan/tal/str/test/run-strreg.c +++ b/ccan/tal/str/test/run-strreg.c @@ -21,7 +21,7 @@ int main(void) /* 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); @@ -36,12 +36,15 @@ int main(void) 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")); + 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); @@ -52,6 +55,8 @@ int main(void) &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); @@ -60,6 +65,8 @@ int main(void) &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); @@ -68,6 +75,8 @@ int main(void) &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); @@ -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_count(a) == strlen(a) + 1); 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")); + ok1(tal_count(b) == strlen(b) + 1); 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")); + ok1(tal_count(b) == strlen(b) + 1); 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_count(b) == strlen(b) + 1); ok1(tal_parent(b) == ctx); tal_free(b); ok1(no_children(ctx)); diff --git a/ccan/tal/str/test/run.c b/ccan/tal/str/test/run.c index a59d9400..626434c3 100644 --- a/ccan/tal/str/test/run.c +++ b/ccan/tal/str/test/run.c @@ -15,7 +15,7 @@ int main(void) 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], "")); @@ -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, ")); + ok1(tal_count(str) == strlen(str) + 1); 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_count(str) == strlen(str) + 1); 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"); @@ -77,6 +81,7 @@ int main(void) 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")); @@ -90,6 +95,7 @@ int main(void) /* 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")); @@ -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")); + ok1(tal_count(str) == strlen(str) + 1); 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); + ok1(tal_count(str) == strlen(str) + 1); 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")); + 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)); -- 2.39.2