Skip to content

Commit f644206

Browse files
KarthikNayakgitster
authored andcommitted
reftable: check for trailing newline in 'tables.list'
In the reftable format, the 'tables.list' file contains a newline separated list of tables. While we parse this file, we do not check or care about the last newline. Tighten the parser in `parse_names()` to return an appropriate error if the last newline is missing. This requires modification to `parse_names()` to now return the error while accepting the output as a third argument. Signed-off-by: Karthik Nayak <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 1ef32f0 commit f644206

File tree

4 files changed

+49
-26
lines changed

4 files changed

+49
-26
lines changed

reftable/basics.c

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -195,44 +195,55 @@ size_t names_length(const char **names)
195195
return p - names;
196196
}
197197

198-
char **parse_names(char *buf, int size)
198+
int parse_names(char *buf, int size, char ***out)
199199
{
200200
char **names = NULL;
201201
size_t names_cap = 0;
202202
size_t names_len = 0;
203203
char *p = buf;
204204
char *end = buf + size;
205+
int err = 0;
205206

206207
while (p < end) {
207208
char *next = strchr(p, '\n');
208-
if (next && next < end) {
209-
*next = 0;
209+
if (!next) {
210+
err = REFTABLE_FORMAT_ERROR;
211+
goto done;
212+
} else if (next < end) {
213+
*next = '\0';
210214
} else {
211215
next = end;
212216
}
217+
213218
if (p < next) {
214219
if (REFTABLE_ALLOC_GROW(names, names_len + 1,
215-
names_cap))
216-
goto err;
220+
names_cap)) {
221+
err = REFTABLE_OUT_OF_MEMORY_ERROR;
222+
goto done;
223+
}
217224

218225
names[names_len] = reftable_strdup(p);
219-
if (!names[names_len++])
220-
goto err;
226+
if (!names[names_len++]) {
227+
err = REFTABLE_OUT_OF_MEMORY_ERROR;
228+
goto done;
229+
}
221230
}
222231
p = next + 1;
223232
}
224233

225-
if (REFTABLE_ALLOC_GROW(names, names_len + 1, names_cap))
226-
goto err;
234+
if (REFTABLE_ALLOC_GROW(names, names_len + 1, names_cap)) {
235+
err = REFTABLE_OUT_OF_MEMORY_ERROR;
236+
goto done;
237+
}
227238
names[names_len] = NULL;
228239

229-
return names;
230-
231-
err:
240+
*out = names;
241+
return 0;
242+
done:
232243
for (size_t i = 0; i < names_len; i++)
233244
reftable_free(names[i]);
234245
reftable_free(names);
235-
return NULL;
246+
return err;
236247
}
237248

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

reftable/basics.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,11 @@ void free_names(char **a);
167167

168168
/*
169169
* Parse a newline separated list of names. `size` is the length of the buffer,
170-
* without terminating '\0'. Empty names are discarded. Returns a `NULL`
171-
* pointer when allocations fail.
170+
* without terminating '\0'. Empty names are discarded.
171+
*
172+
* Returns 0 on success, a reftable error code on error.
172173
*/
173-
char **parse_names(char *buf, int size);
174+
int parse_names(char *buf, int size, char ***out);
174175

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

reftable/stack.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -169,12 +169,7 @@ static int fd_read_lines(int fd, char ***namesp)
169169
}
170170
buf[size] = 0;
171171

172-
*namesp = parse_names(buf, size);
173-
if (!*namesp) {
174-
err = REFTABLE_OUT_OF_MEMORY_ERROR;
175-
goto done;
176-
}
177-
172+
err = parse_names(buf, size, namesp);
178173
done:
179174
reftable_free(buf);
180175
return err;

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

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ license that can be found in the LICENSE file or at
99
#include "unit-test.h"
1010
#include "lib-reftable.h"
1111
#include "reftable/basics.h"
12+
#include "reftable/reftable-error.h"
1213

1314
struct integer_needle_lesseq_args {
1415
int needle;
@@ -79,14 +80,18 @@ void test_reftable_basics__names_equal(void)
7980
void test_reftable_basics__parse_names(void)
8081
{
8182
char in1[] = "line\n";
82-
char in2[] = "a\nb\nc";
83-
char **out = parse_names(in1, strlen(in1));
83+
char in2[] = "a\nb\nc\n";
84+
char **out = NULL;
85+
int err = parse_names(in1, strlen(in1), &out);
86+
cl_assert(err == 0);
8487
cl_assert(out != NULL);
8588
cl_assert_equal_s(out[0], "line");
8689
cl_assert(!out[1]);
8790
free_names(out);
8891

89-
out = parse_names(in2, strlen(in2));
92+
out = NULL;
93+
err = parse_names(in2, strlen(in2), &out);
94+
cl_assert(err == 0);
9095
cl_assert(out != NULL);
9196
cl_assert_equal_s(out[0], "a");
9297
cl_assert_equal_s(out[1], "b");
@@ -95,10 +100,21 @@ void test_reftable_basics__parse_names(void)
95100
free_names(out);
96101
}
97102

103+
void test_reftable_basics__parse_names_missing_newline(void)
104+
{
105+
char in1[] = "line\nline2";
106+
char **out = NULL;
107+
int err = parse_names(in1, strlen(in1), &out);
108+
cl_assert(err == REFTABLE_FORMAT_ERROR);
109+
cl_assert(out == NULL);
110+
}
111+
98112
void test_reftable_basics__parse_names_drop_empty_string(void)
99113
{
100114
char in[] = "a\n\nb\n";
101-
char **out = parse_names(in, strlen(in));
115+
char **out = NULL;
116+
int err = parse_names(in, strlen(in), &out);
117+
cl_assert(err == 0);
102118
cl_assert(out != NULL);
103119
cl_assert_equal_s(out[0], "a");
104120
/* simply '\n' should be dropped as empty string */

0 commit comments

Comments
 (0)