summaryrefslogtreecommitdiff
path: root/src/basic/nulstr-util.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2022-11-11 23:17:12 +0100
committerYu Watanabe <watanabe.yu+github@gmail.com>2022-11-13 17:40:59 +0900
commit76078ad850990fdcd42f82b7add35f73156e35bc (patch)
treea21cc4d97d8ee8ef18cf7951a994b80fb3f01e08 /src/basic/nulstr-util.c
parentdb645f936f2b686e05524e198df00112acaff3c6 (diff)
downloadsystemd-76078ad850990fdcd42f82b7add35f73156e35bc.tar.gz
nulstr-util: fix corner cases of strv_make_nulstr()
Let's change the return semantics of strv_make_nulstr() so that we can properly distuingish the case where we have a no entries in the nulstr from the case where we have a single empty string in a nulstr. Previously we couldn't distuingish those, we'd in both cases return a size of zero, and a buffer with two NUL bytes. With this change, we'll still return a buffer with two NULL bytes, but for the case where no entries are defined we'll return a size of zero, and where we have two a size of one. This is a good idea, as it makes sure we can properly handle all corner cases. Nowadays the function is used by one place only: ask-password-api.c. The corner case never mattered there, since it was used to serialize passwords, and it was known that there was exactly one password, not less. But let's clean this up. This means the subtraction of the final NUL byte now happens in ask-password-api.c instead.
Diffstat (limited to 'src/basic/nulstr-util.c')
-rw-r--r--src/basic/nulstr-util.c22
1 files changed, 14 insertions, 8 deletions
diff --git a/src/basic/nulstr-util.c b/src/basic/nulstr-util.c
index 67226d208c..44b88ca753 100644
--- a/src/basic/nulstr-util.c
+++ b/src/basic/nulstr-util.c
@@ -70,10 +70,15 @@ char** strv_split_nulstr(const char *s) {
}
int strv_make_nulstr(char * const *l, char **ret, size_t *ret_size) {
- /* A valid nulstr with two NULs at the end will be created, but q will be the length without the two
- * trailing NULs. Thus the output string is a valid nulstr and can be iterated over using
- * NULSTR_FOREACH(), and can also be parsed by strv_parse_nulstr() as long as the length is provided
- * separately. */
+ /* Builds a nulstr and returns it together with the size. An extra NUL byte will be appended (⚠️ but
+ * not included in the size! ⚠️). This is done so that the nulstr can be used both in
+ * strv_parse_nulstr() and in NULSTR_FOREACH()/strv_split_nulstr() contexts, i.e. with and without a
+ * size parameter. In the former case we can include empty strings, in the latter case we cannot (as
+ * that is the end marker).
+ *
+ * When NULSTR_FOREACH()/strv_split_nulstr() is used it is often assumed that the nulstr ends in two
+ * NUL bytes (which it will, if not empty). To ensure that this assumption *always* holds, we'll
+ * return a buffer with two NUL bytes in that case, but return a size of zero. */
_cleanup_free_ char *m = NULL;
size_t n = 0;
@@ -94,17 +99,18 @@ int strv_make_nulstr(char * const *l, char **ret, size_t *ret_size) {
}
if (!m) {
+ /* return a buffer with an extra NUL, so that the assumption that we always have two trailing NULs holds */
m = new0(char, 2);
if (!m)
return -ENOMEM;
- n = 1;
+
+ n = 0;
} else
- /* make sure there is a second extra NUL at the end of resulting nulstr */
+ /* Make sure there is a second extra NUL at the end of resulting nulstr (not counted in return size) */
m[n] = '\0';
- assert(n > 0);
*ret = TAKE_PTR(m);
- *ret_size = n - 1;
+ *ret_size = n;
return 0;
}