Remove the hard coded length limit on variable names in config files

Previously while reading the variable names in config files, there was a 256 character limit with at most 128 of those characters being used by the section header portion of the variable name. This limitation was only enforced while reading the config files. It was possible to write a config file that was not subsequently readable. Instead of enforcing this limitation for both reading and writing, remove it entirely by changing the var member of the config_file struct to a strbuf instead of a fixed length buffer. Update all of the parsing functions in config.c to use the strbuf instead of the static buffer. The parsing functions that returned the base length of the variable name now return simply 0 for success and -1 for failure. The base length information is obtained through the strbuf's len member. We now send the buf member of the strbuf to external callback functions to preserve the external api. None of the external callers rely on the old size limitation for sizing their own buffers so removing the limit should have no externally visible effect. Signed-off-by: Ben Walton <bdwalton@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Ben Walton committed Sep 30, 2012 at 20:44 UTC 0971e992c4e2806b427a09239ee48a90280c9b15
1 file changed +29 -30
config.c
+29 -30
@@ -10,8 +10,6 @@
10 #include "strbuf.h"
11 #include "quote.h"
12
13 -#define MAXNAME (256)
14 -
13 typedef struct config_file {
14 struct config_file *prev;
15 FILE *f;
@@ -19,7 +17,7 @@ typedef struct config_file {
17 int linenr;
18 int eof;
19 struct strbuf value;
22 - char var[MAXNAME];
20 + struct strbuf var;
21 } config_file;
22
23 static config_file *cf;
@@ -260,7 +258,7 @@ static inline int iskeychar(int c)
258 return isalnum(c) || c == '-';
259 }
260
263 -static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
261 +static int get_value(config_fn_t fn, void *data, struct strbuf *name)
262 {
263 int c;
264 char *value;
@@ -272,11 +270,9 @@ static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
270 break;
271 if (!iskeychar(c))
272 break;
275 - name[len++] = tolower(c);
276 - if (len >= MAXNAME)
277 - return -1;
273 + strbuf_addch(name, tolower(c));
274 }
279 - name[len] = 0;
275 +
276 while (c == ' ' || c == '\t')
277 c = get_next_char();
278
@@ -288,10 +284,10 @@ static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
284 if (!value)
285 return -1;
286 }
291 - return fn(name, value, data);
287 + return fn(name->buf, value, data);
288 }
289
294 -static int get_extended_base_var(char *name, int baselen, int c)
290 +static int get_extended_base_var(struct strbuf *name, int c)
291 {
292 do {
293 if (c == '\n')
@@ -302,7 +298,7 @@ static int get_extended_base_var(char *name, int baselen, int c)
298 /* We require the format to be '[base "extension"]' */
299 if (c != '"')
300 return -1;
305 - name[baselen++] = '.';
301 + strbuf_addch(name, '.');
302
303 for (;;) {
304 int c = get_next_char();
@@ -315,37 +311,31 @@ static int get_extended_base_var(char *name, int baselen, int c)
311 if (c == '\n')
312 goto error_incomplete_line;
313 }
318 - name[baselen++] = c;
319 - if (baselen > MAXNAME / 2)
320 - return -1;
314 + strbuf_addch(name, c);
315 }
316
317 /* Final ']' */
318 if (get_next_char() != ']')
319 return -1;
326 - return baselen;
320 + return 0;
321 error_incomplete_line:
322 cf->linenr--;
323 return -1;
324 }
325
332 -static int get_base_var(char *name)
326 +static int get_base_var(struct strbuf *name)
327 {
334 - int baselen = 0;
335 -
328 for (;;) {
329 int c = get_next_char();
330 if (cf->eof)
331 return -1;
332 if (c == ']')
341 - return baselen;
333 + return 0;
334 if (isspace(c))
343 - return get_extended_base_var(name, baselen, c);
335 + return get_extended_base_var(name, c);
336 if (!iskeychar(c) && c != '.')
337 return -1;
346 - if (baselen > MAXNAME / 2)
347 - return -1;
348 - name[baselen++] = tolower(c);
338 + strbuf_addch(name, tolower(c));
339 }
340 }
341
@@ -353,7 +343,7 @@ static int git_parse_file(config_fn_t fn, void *data)
343 {
344 int comment = 0;
345 int baselen = 0;
356 - char *var = cf->var;
346 + struct strbuf *var = &cf->var;
347
348 /* U+FEFF Byte Order Mark in UTF8 */
349 static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf";
@@ -389,17 +379,24 @@ static int git_parse_file(config_fn_t fn, void *data)
379 continue;
380 }
381 if (c == '[') {
392 - baselen = get_base_var(var);
393 - if (baselen <= 0)
382 + /* Reset prior to determining a new stem */
383 + strbuf_reset(var);
384 + if (get_base_var(var) < 0 || var->len < 1)
385 break;
395 - var[baselen++] = '.';
396 - var[baselen] = 0;
386 + strbuf_addch(var, '.');
387 + baselen = var->len;
388 continue;
389 }
390 if (!isalpha(c))
391 break;
401 - var[baselen] = tolower(c);
402 - if (get_value(fn, data, var, baselen+1) < 0)
392 + /*
393 + * Truncate the var name back to the section header
394 + * stem prior to grabbing the suffix part of the name
395 + * and the value.
396 + */
397 + strbuf_setlen(var, baselen);
398 + strbuf_addch(var, tolower(c));
399 + if (get_value(fn, data, var) < 0)
400 break;
401 }
402 die("bad config file line %d in %s", cf->linenr, cf->name);
@@ -899,12 +896,14 @@ int git_config_from_file(config_fn_t fn, const char *filename, void *data)
896 top.linenr = 1;
897 top.eof = 0;
898 strbuf_init(&top.value, 1024);
899 + strbuf_init(&top.var, 1024);
900 cf = &top;
901
902 ret = git_parse_file(fn, data);
903
904 /* pop config-file parsing state stack */
905 strbuf_release(&top.value);
906 + strbuf_release(&top.var);
907 cf = top.prev;
908
909 fclose(f);