@@ -130,14 +130,14 @@ size_t names_length(const char **names)
return p - names;
}
-void parse_names(char *buf, int size, char ***namesp)
+char **parse_names(char *buf, int size)
{
char **names = NULL;
size_t names_cap = 0;
size_t names_len = 0;
-
char *p = buf;
char *end = buf + size;
+
while (p < end) {
char *next = strchr(p, '\n');
if (next && next < end) {
@@ -147,14 +147,26 @@ void parse_names(char *buf, int size, char ***namesp)
}
if (p < next) {
REFTABLE_ALLOC_GROW(names, names_len + 1, names_cap);
- names[names_len++] = xstrdup(p);
+ if (!names)
+ goto err;
+
+ names[names_len] = strdup(p);
+ if (!names[names_len++])
+ goto err;
}
p = next + 1;
}
REFTABLE_REALLOC_ARRAY(names, names_len + 1);
names[names_len] = NULL;
- *namesp = names;
+
+ return names;
+
+err:
+ for (size_t i = 0; i < names_len; i++)
+ free(names[i]);
+ free(names);
+ return NULL;
}
int names_equal(const char **a, const char **b)
@@ -38,9 +38,12 @@ size_t binsearch(size_t sz, int (*f)(size_t k, void *args), void *args);
*/
void free_names(char **a);
-/* parse a newline separated list of names. `size` is the length of the buffer,
- * without terminating '\0'. Empty names are discarded. */
-void parse_names(char *buf, int size, char ***namesp);
+/*
+ * Parse a newline separated list of names. `size` is the length of the buffer,
+ * without terminating '\0'. Empty names are discarded. Returns a `NULL`
+ * pointer when allocations fail.
+ */
+char **parse_names(char *buf, int size);
/* compares two NULL-terminated arrays of strings. */
int names_equal(const char **a, const char **b);
@@ -108,7 +108,11 @@ static int fd_read_lines(int fd, char ***namesp)
}
buf[size] = 0;
- parse_names(buf, size, namesp);
+ *namesp = parse_names(buf, size);
+ if (!*namesp) {
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
+ goto done;
+ }
done:
reftable_free(buf);
@@ -72,13 +72,14 @@ int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
if_test ("parse_names works for basic input") {
char in1[] = "line\n";
char in2[] = "a\nb\nc";
- char **out = NULL;
- parse_names(in1, strlen(in1), &out);
+ char **out = parse_names(in1, strlen(in1));
+ check(out != NULL);
check_str(out[0], "line");
check(!out[1]);
free_names(out);
- parse_names(in2, strlen(in2), &out);
+ out = parse_names(in2, strlen(in2));
+ check(out != NULL);
check_str(out[0], "a");
check_str(out[1], "b");
check_str(out[2], "c");
@@ -88,8 +89,8 @@ int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
if_test ("parse_names drops empty string") {
char in[] = "a\n\nb\n";
- char **out = NULL;
- parse_names(in, strlen(in), &out);
+ char **out = parse_names(in, strlen(in));
+ check(out != NULL);
check_str(out[0], "a");
/* simply '\n' should be dropped as empty string */
check_str(out[1], "b");
Handle allocation failures in `parse_names()` by returning `NULL` in case any allocation fails. While at it, refactor the function to return the array directly instead of assigning it to an out-pointer. Signed-off-by: Patrick Steinhardt <ps@pks.im> --- reftable/basics.c | 20 ++++++++++++++++---- reftable/basics.h | 9 ++++++--- reftable/stack.c | 6 +++++- t/unit-tests/t-reftable-basics.c | 11 ++++++----- 4 files changed, 33 insertions(+), 13 deletions(-)