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