Skip to content

Commit c7c377d

Browse files
committed
Merge branch 'jk/config-int-range-check'
"git config" did not provide a way to set or access numbers larger than a native "int" on the platform; it now provides 64-bit signed integers on all platforms. * jk/config-int-range-check: git-config: always treat --int as 64-bit internally config: make numeric parsing errors more clear config: set errno in numeric git_parse_* functions config: properly range-check integer values config: factor out integer parsing from range checks
2 parents a194ead + 0016024 commit c7c377d

File tree

5 files changed

+83
-24
lines changed

5 files changed

+83
-24
lines changed

builtin/config.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,8 @@ static int format_config(struct strbuf *buf, const char *key_, const char *value
119119
must_print_delim = 1;
120120
}
121121
if (types == TYPE_INT)
122-
sprintf(value, "%d", git_config_int(key_, value_ ? value_ : ""));
122+
sprintf(value, "%"PRId64,
123+
git_config_int64(key_, value_ ? value_ : ""));
123124
else if (types == TYPE_BOOL)
124125
vptr = git_config_bool(key_, value_) ? "true" : "false";
125126
else if (types == TYPE_BOOL_OR_INT) {
@@ -268,8 +269,8 @@ static char *normalize_value(const char *key, const char *value)
268269
else {
269270
normalized = xmalloc(64);
270271
if (types == TYPE_INT) {
271-
int v = git_config_int(key, value);
272-
sprintf(normalized, "%d", v);
272+
int64_t v = git_config_int64(key, value);
273+
sprintf(normalized, "%"PRId64, v);
273274
}
274275
else if (types == TYPE_BOOL)
275276
sprintf(normalized, "%s",

cache.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,6 +1115,7 @@ extern int git_config_with_options(config_fn_t fn, void *,
11151115
extern int git_config_early(config_fn_t fn, void *, const char *repo_config);
11161116
extern int git_parse_ulong(const char *, unsigned long *);
11171117
extern int git_config_int(const char *, const char *);
1118+
extern int64_t git_config_int64(const char *, const char *);
11181119
extern unsigned long git_config_ulong(const char *, const char *);
11191120
extern int git_config_bool_or_int(const char *, const char *, int *);
11201121
extern int git_config_bool(const char *, const char *);

config.c

Lines changed: 67 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ static int parse_unit_factor(const char *end, uintmax_t *val)
468468
return 0;
469469
}
470470

471-
static int git_parse_long(const char *value, long *ret)
471+
static int git_parse_signed(const char *value, intmax_t *ret, intmax_t max)
472472
{
473473
if (value && *value) {
474474
char *end;
@@ -480,21 +480,25 @@ static int git_parse_long(const char *value, long *ret)
480480
val = strtoimax(value, &end, 0);
481481
if (errno == ERANGE)
482482
return 0;
483-
if (!parse_unit_factor(end, &factor))
483+
if (!parse_unit_factor(end, &factor)) {
484+
errno = EINVAL;
484485
return 0;
486+
}
485487
uval = abs(val);
486488
uval *= factor;
487-
if ((uval > maximum_signed_value_of_type(long)) ||
488-
(abs(val) > uval))
489+
if (uval > max || abs(val) > uval) {
490+
errno = ERANGE;
489491
return 0;
492+
}
490493
val *= factor;
491494
*ret = val;
492495
return 1;
493496
}
497+
errno = EINVAL;
494498
return 0;
495499
}
496500

497-
int git_parse_ulong(const char *value, unsigned long *ret)
501+
int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max)
498502
{
499503
if (value && *value) {
500504
char *end;
@@ -506,37 +510,83 @@ int git_parse_ulong(const char *value, unsigned long *ret)
506510
if (errno == ERANGE)
507511
return 0;
508512
oldval = val;
509-
if (!parse_unit_factor(end, &val))
513+
if (!parse_unit_factor(end, &val)) {
514+
errno = EINVAL;
510515
return 0;
511-
if ((val > maximum_unsigned_value_of_type(long)) ||
512-
(oldval > val))
516+
}
517+
if (val > max || oldval > val) {
518+
errno = ERANGE;
513519
return 0;
520+
}
514521
*ret = val;
515522
return 1;
516523
}
524+
errno = EINVAL;
517525
return 0;
518526
}
519527

520-
static void die_bad_config(const char *name)
528+
static int git_parse_int(const char *value, int *ret)
521529
{
530+
intmax_t tmp;
531+
if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int)))
532+
return 0;
533+
*ret = tmp;
534+
return 1;
535+
}
536+
537+
static int git_parse_int64(const char *value, int64_t *ret)
538+
{
539+
intmax_t tmp;
540+
if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int64_t)))
541+
return 0;
542+
*ret = tmp;
543+
return 1;
544+
}
545+
546+
int git_parse_ulong(const char *value, unsigned long *ret)
547+
{
548+
uintmax_t tmp;
549+
if (!git_parse_unsigned(value, &tmp, maximum_unsigned_value_of_type(long)))
550+
return 0;
551+
*ret = tmp;
552+
return 1;
553+
}
554+
555+
static void die_bad_number(const char *name, const char *value)
556+
{
557+
const char *reason = errno == ERANGE ?
558+
"out of range" :
559+
"invalid unit";
560+
if (!value)
561+
value = "";
562+
522563
if (cf && cf->name)
523-
die("bad config value for '%s' in %s", name, cf->name);
524-
die("bad config value for '%s'", name);
564+
die("bad numeric config value '%s' for '%s' in %s: %s",
565+
value, name, cf->name, reason);
566+
die("bad numeric config value '%s' for '%s': %s", value, name, reason);
525567
}
526568

527569
int git_config_int(const char *name, const char *value)
528570
{
529-
long ret = 0;
530-
if (!git_parse_long(value, &ret))
531-
die_bad_config(name);
571+
int ret;
572+
if (!git_parse_int(value, &ret))
573+
die_bad_number(name, value);
574+
return ret;
575+
}
576+
577+
int64_t git_config_int64(const char *name, const char *value)
578+
{
579+
int64_t ret;
580+
if (!git_parse_int64(value, &ret))
581+
die_bad_number(name, value);
532582
return ret;
533583
}
534584

535585
unsigned long git_config_ulong(const char *name, const char *value)
536586
{
537587
unsigned long ret;
538588
if (!git_parse_ulong(value, &ret))
539-
die_bad_config(name);
589+
die_bad_number(name, value);
540590
return ret;
541591
}
542592

@@ -559,10 +609,10 @@ static int git_config_maybe_bool_text(const char *name, const char *value)
559609

560610
int git_config_maybe_bool(const char *name, const char *value)
561611
{
562-
long v = git_config_maybe_bool_text(name, value);
612+
int v = git_config_maybe_bool_text(name, value);
563613
if (0 <= v)
564614
return v;
565-
if (git_parse_long(value, &v))
615+
if (git_parse_int(value, &v))
566616
return !!v;
567617
return -1;
568618
}

t/t1300-repo-config.sh

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -652,16 +652,23 @@ test_expect_success numbers '
652652
test_cmp expect actual
653653
'
654654

655+
test_expect_success '--int is at least 64 bits' '
656+
git config giga.watts 121g &&
657+
echo 129922760704 >expect &&
658+
git config --int --get giga.watts >actual &&
659+
test_cmp expect actual
660+
'
661+
655662
test_expect_success 'invalid unit' '
656663
git config aninvalid.unit "1auto" &&
657664
echo 1auto >expect &&
658665
git config aninvalid.unit >actual &&
659666
test_cmp expect actual &&
660-
cat > expect <<-\EOF
661-
fatal: bad config value for '\''aninvalid.unit'\'' in .git/config
667+
cat >expect <<-\EOF
668+
fatal: bad numeric config value '\''1auto'\'' for '\''aninvalid.unit'\'' in .git/config: invalid unit
662669
EOF
663670
test_must_fail git config --int --get aninvalid.unit 2>actual &&
664-
test_cmp actual expect
671+
test_i18ncmp expect actual
665672
'
666673

667674
cat > expect << EOF

t/t4055-diff-context.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ test_expect_success 'plumbing not affected' '
7373
test_expect_success 'non-integer config parsing' '
7474
git config diff.context no &&
7575
test_must_fail git diff 2>output &&
76-
test_i18ngrep "bad config value" output
76+
test_i18ngrep "bad numeric config value" output
7777
'
7878

7979
test_expect_success 'negative integer config parsing' '

0 commit comments

Comments
 (0)