reftable/basics: handle allocation failures in `parse_names()`
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> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Patrick Steinhardt committed
Oct 2, 2024 at 12:55 UTC
eef7bcdafe0037f14a96c564ace899342b9ed0fb
4 files changed
+33
-13
reftable/basics.c
+16
-4
@@ -135,14 +135,14 @@ size_t names_length(const char **names)
135
return p - names;
136
}
137
138
-void parse_names(char *buf, int size, char ***namesp)
138
+char **parse_names(char *buf, int size)
139
{
140
char **names = NULL;
141
size_t names_cap = 0;
142
size_t names_len = 0;
143
-
143
char *p = buf;
144
char *end = buf + size;
145
+
146
while (p < end) {
147
char *next = strchr(p, '\n');
148
if (next && next < end) {
@@ -152,14 +152,26 @@ void parse_names(char *buf, int size, char ***namesp)
152
}
153
if (p < next) {
154
REFTABLE_ALLOC_GROW(names, names_len + 1, names_cap);
155
- names[names_len++] = xstrdup(p);
155
+ if (!names)
156
+ goto err;
157
+
158
+ names[names_len] = reftable_strdup(p);
159
+ if (!names[names_len++])
160
+ goto err;
161
}
162
p = next + 1;
163
}
164
165
REFTABLE_REALLOC_ARRAY(names, names_len + 1);
166
names[names_len] = NULL;
162
- *namesp = names;
167
+
168
+ return names;
169
+
170
+err:
171
+ for (size_t i = 0; i < names_len; i++)
172
+ reftable_free(names[i]);
173
+ reftable_free(names);
174
+ return NULL;
175
}
176
177
int names_equal(const char **a, const char **b)
reftable/basics.h
+6
-3
@@ -38,9 +38,12 @@ size_t binsearch(size_t sz, int (*f)(size_t k, void *args), void *args);
38
*/
39
void free_names(char **a);
40
41
-/* parse a newline separated list of names. `size` is the length of the buffer,
42
- * without terminating '\0'. Empty names are discarded. */
43
-void parse_names(char *buf, int size, char ***namesp);
41
+/*
42
+ * Parse a newline separated list of names. `size` is the length of the buffer,
43
+ * without terminating '\0'. Empty names are discarded. Returns a `NULL`
44
+ * pointer when allocations fail.
45
+ */
46
+char **parse_names(char *buf, int size);
47
48
/* compares two NULL-terminated arrays of strings. */
49
int names_equal(const char **a, const char **b);
reftable/stack.c
+5
-1
@@ -108,7 +108,11 @@ static int fd_read_lines(int fd, char ***namesp)
108
}
109
buf[size] = 0;
110
111
- parse_names(buf, size, namesp);
111
+ *namesp = parse_names(buf, size);
112
+ if (!*namesp) {
113
+ err = REFTABLE_OUT_OF_MEMORY_ERROR;
114
+ goto done;
115
+ }
116
117
done:
118
reftable_free(buf);
t/unit-tests/t-reftable-basics.c
+6
-5
@@ -72,13 +72,14 @@ int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
72
if_test ("parse_names works for basic input") {
73
char in1[] = "line\n";
74
char in2[] = "a\nb\nc";
75
- char **out = NULL;
76
- parse_names(in1, strlen(in1), &out);
75
+ char **out = parse_names(in1, strlen(in1));
76
+ check(out != NULL);
77
check_str(out[0], "line");
78
check(!out[1]);
79
free_names(out);
80
81
- parse_names(in2, strlen(in2), &out);
81
+ out = parse_names(in2, strlen(in2));
82
+ check(out != NULL);
83
check_str(out[0], "a");
84
check_str(out[1], "b");
85
check_str(out[2], "c");
@@ -88,8 +89,8 @@ int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
89
90
if_test ("parse_names drops empty string") {
91
char in[] = "a\n\nb\n";
91
- char **out = NULL;
92
- parse_names(in, strlen(in), &out);
92
+ char **out = parse_names(in, strlen(in));
93
+ check(out != NULL);
94
check_str(out[0], "a");
95
/* simply '\n' should be dropped as empty string */
96
check_str(out[1], "b");