Git fork

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 <karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>

authored by

Karthik Nayak and committed by
Junio C Hamano
f6442063 1ef32f09

+49 -26
+24 -13
reftable/basics.c
··· 195 195 return p - names; 196 196 } 197 197 198 - char **parse_names(char *buf, int size) 198 + int parse_names(char *buf, int size, char ***out) 199 199 { 200 200 char **names = NULL; 201 201 size_t names_cap = 0; 202 202 size_t names_len = 0; 203 203 char *p = buf; 204 204 char *end = buf + size; 205 + int err = 0; 205 206 206 207 while (p < end) { 207 208 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'; 210 214 } else { 211 215 next = end; 212 216 } 217 + 213 218 if (p < next) { 214 219 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 + } 217 224 218 225 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 + } 221 230 } 222 231 p = next + 1; 223 232 } 224 233 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 + } 227 238 names[names_len] = NULL; 228 239 229 - return names; 230 - 231 - err: 240 + *out = names; 241 + return 0; 242 + done: 232 243 for (size_t i = 0; i < names_len; i++) 233 244 reftable_free(names[i]); 234 245 reftable_free(names); 235 - return NULL; 246 + return err; 236 247 } 237 248 238 249 int names_equal(const char **a, const char **b)
+4 -3
reftable/basics.h
··· 167 167 168 168 /* 169 169 * 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. 172 173 */ 173 - char **parse_names(char *buf, int size); 174 + int parse_names(char *buf, int size, char ***out); 174 175 175 176 /* compares two NULL-terminated arrays of strings. */ 176 177 int names_equal(const char **a, const char **b);
+1 -6
reftable/stack.c
··· 169 169 } 170 170 buf[size] = 0; 171 171 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); 178 173 done: 179 174 reftable_free(buf); 180 175 return err;
+20 -4
t/unit-tests/u-reftable-basics.c
··· 9 9 #include "unit-test.h" 10 10 #include "lib-reftable.h" 11 11 #include "reftable/basics.h" 12 + #include "reftable/reftable-error.h" 12 13 13 14 struct integer_needle_lesseq_args { 14 15 int needle; ··· 79 80 void test_reftable_basics__parse_names(void) 80 81 { 81 82 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); 84 87 cl_assert(out != NULL); 85 88 cl_assert_equal_s(out[0], "line"); 86 89 cl_assert(!out[1]); 87 90 free_names(out); 88 91 89 - out = parse_names(in2, strlen(in2)); 92 + out = NULL; 93 + err = parse_names(in2, strlen(in2), &out); 94 + cl_assert(err == 0); 90 95 cl_assert(out != NULL); 91 96 cl_assert_equal_s(out[0], "a"); 92 97 cl_assert_equal_s(out[1], "b"); ··· 95 100 free_names(out); 96 101 } 97 102 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 + 98 112 void test_reftable_basics__parse_names_drop_empty_string(void) 99 113 { 100 114 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); 102 118 cl_assert(out != NULL); 103 119 cl_assert_equal_s(out[0], "a"); 104 120 /* simply '\n' should be dropped as empty string */