Skip to content

Commit eef7bcd

Browse files
pks-tgitster
authored andcommitted
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 6593e14 commit eef7bcd

File tree

4 files changed

+33
-13
lines changed

4 files changed

+33
-13
lines changed

reftable/basics.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,14 +135,14 @@ size_t names_length(const char **names)
135135
return p - names;
136136
}
137137

138-
void parse_names(char *buf, int size, char ***namesp)
138+
char **parse_names(char *buf, int size)
139139
{
140140
char **names = NULL;
141141
size_t names_cap = 0;
142142
size_t names_len = 0;
143-
144143
char *p = buf;
145144
char *end = buf + size;
145+
146146
while (p < end) {
147147
char *next = strchr(p, '\n');
148148
if (next && next < end) {
@@ -152,14 +152,26 @@ void parse_names(char *buf, int size, char ***namesp)
152152
}
153153
if (p < next) {
154154
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;
156161
}
157162
p = next + 1;
158163
}
159164

160165
REFTABLE_REALLOC_ARRAY(names, names_len + 1);
161166
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;
163175
}
164176

165177
int names_equal(const char **a, const char **b)

reftable/basics.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,12 @@ size_t binsearch(size_t sz, int (*f)(size_t k, void *args), void *args);
3838
*/
3939
void free_names(char **a);
4040

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);
4447

4548
/* compares two NULL-terminated arrays of strings. */
4649
int names_equal(const char **a, const char **b);

reftable/stack.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,11 @@ static int fd_read_lines(int fd, char ***namesp)
108108
}
109109
buf[size] = 0;
110110

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+
}
112116

113117
done:
114118
reftable_free(buf);

t/unit-tests/t-reftable-basics.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,14 @@ int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
7272
if_test ("parse_names works for basic input") {
7373
char in1[] = "line\n";
7474
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);
7777
check_str(out[0], "line");
7878
check(!out[1]);
7979
free_names(out);
8080

81-
parse_names(in2, strlen(in2), &out);
81+
out = parse_names(in2, strlen(in2));
82+
check(out != NULL);
8283
check_str(out[0], "a");
8384
check_str(out[1], "b");
8485
check_str(out[2], "c");
@@ -88,8 +89,8 @@ int cmd_main(int argc UNUSED, const char *argv[] UNUSED)
8889

8990
if_test ("parse_names drops empty string") {
9091
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);
9394
check_str(out[0], "a");
9495
/* simply '\n' should be dropped as empty string */
9596
check_str(out[1], "b");

0 commit comments

Comments
 (0)