Support sizes >=2G in various config options accepting 'g' sizes.

The config options core.packedGitWindowSize, core.packedGitLimit, core.deltaBaseCacheLimit, core.bigFileThreshold, pack.windowMemory and pack.packSizeLimit all claim to support suffixes up to and including 'g'. This implies that they should accept sizes >=2G on 64-bit systems: certainly, specifying a size of 3g should not silently be translated to zero or transformed into a large negative value due to integer overflow. However, due to use of git_config_int() rather than git_config_ulong(), that is exactly what happens: % git config core.bigFileThreshold 2g % git gc --aggressive # with extra debugging code to print out # core.bigfilethreshold after parsing bigfilethreshold: -2147483648 [...] This is probably irrelevant for core.deltaBaseCacheLimit, but is problematic for the other values. (It is particularly problematic for core.packedGitLimit, which can't even be set to its default value in the config file due to this bug.) This fixes things for 32-bit platforms as well. They get the usual bad config error if an overlarge value is specified, e.g.: fatal: bad config value for 'core.bigfilethreshold' in /home/nix/.gitconfig This is detected in all cases, even if the 32-bit platform has no size larger than 'long'. For signed integral configuration values, we also detect the case where the value is too large for the signed type but not the unsigned type. Signed-off-by: Nick Alcock <nix@esperi.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Nick Alcock committed Nov 2, 2011 at 15:46 UTC ebaa1bd407745c4b4c1c0f20c322929fc4371467
1 file changed +31 -10
config.c
+31 -10
@@ -326,7 +326,7 @@ static int git_parse_file(config_fn_t fn, void *data)
326 die("bad config file line %d in %s", config_linenr, config_file_name);
327 }
328
329 -static int parse_unit_factor(const char *end, unsigned long *val)
329 +static int parse_unit_factor(const char *end, uintmax_t *val)
330 {
331 if (!*end)
332 return 1;
@@ -349,11 +349,23 @@ static int git_parse_long(const char *value, long *ret)
349 {
350 if (value && *value) {
351 char *end;
352 - long val = strtol(value, &end, 0);
353 - unsigned long factor = 1;
352 + intmax_t val;
353 + uintmax_t uval;
354 + uintmax_t factor = 1;
355 +
356 + errno = 0;
357 + val = strtoimax(value, &end, 0);
358 + if (errno == ERANGE)
359 + return 0;
360 if (!parse_unit_factor(end, &factor))
361 return 0;
356 - *ret = val * factor;
362 + uval = abs(val);
363 + uval *= factor;
364 + if ((uval > maximum_signed_value_of_type(long)) ||
365 + (abs(val) > uval))
366 + return 0;
367 + val *= factor;
368 + *ret = val;
369 return 1;
370 }
371 return 0;
@@ -363,9 +375,19 @@ int git_parse_ulong(const char *value, unsigned long *ret)
375 {
376 if (value && *value) {
377 char *end;
366 - unsigned long val = strtoul(value, &end, 0);
378 + uintmax_t val;
379 + uintmax_t oldval;
380 +
381 + errno = 0;
382 + val = strtoumax(value, &end, 0);
383 + if (errno == ERANGE)
384 + return 0;
385 + oldval = val;
386 if (!parse_unit_factor(end, &val))
387 return 0;
388 + if ((val > maximum_unsigned_value_of_type(long)) ||
389 + (oldval > val))
390 + return 0;
391 *ret = val;
392 return 1;
393 }
@@ -543,7 +565,7 @@ static int git_default_core_config(const char *var, const char *value)
565
566 if (!strcmp(var, "core.packedgitwindowsize")) {
567 int pgsz_x2 = getpagesize() * 2;
546 - packed_git_window_size = git_config_int(var, value);
568 + packed_git_window_size = git_config_ulong(var, value);
569
570 /* This value must be multiple of (pagesize * 2) */
571 packed_git_window_size /= pgsz_x2;
@@ -554,18 +576,17 @@ static int git_default_core_config(const char *var, const char *value)
576 }
577
578 if (!strcmp(var, "core.bigfilethreshold")) {
557 - long n = git_config_int(var, value);
558 - big_file_threshold = 0 < n ? n : 0;
579 + big_file_threshold = git_config_ulong(var, value);
580 return 0;
581 }
582
583 if (!strcmp(var, "core.packedgitlimit")) {
563 - packed_git_limit = git_config_int(var, value);
584 + packed_git_limit = git_config_ulong(var, value);
585 return 0;
586 }
587
588 if (!strcmp(var, "core.deltabasecachelimit")) {
568 - delta_base_cache_limit = git_config_int(var, value);
589 + delta_base_cache_limit = git_config_ulong(var, value);
590 return 0;
591 }
592