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
This commit is contained in:
commit
c7c377d83f
@ -119,7 +119,8 @@ static int format_config(struct strbuf *buf, const char *key_, const char *value
|
|||||||
must_print_delim = 1;
|
must_print_delim = 1;
|
||||||
}
|
}
|
||||||
if (types == TYPE_INT)
|
if (types == TYPE_INT)
|
||||||
sprintf(value, "%d", git_config_int(key_, value_ ? value_ : ""));
|
sprintf(value, "%"PRId64,
|
||||||
|
git_config_int64(key_, value_ ? value_ : ""));
|
||||||
else if (types == TYPE_BOOL)
|
else if (types == TYPE_BOOL)
|
||||||
vptr = git_config_bool(key_, value_) ? "true" : "false";
|
vptr = git_config_bool(key_, value_) ? "true" : "false";
|
||||||
else if (types == TYPE_BOOL_OR_INT) {
|
else if (types == TYPE_BOOL_OR_INT) {
|
||||||
@ -268,8 +269,8 @@ static char *normalize_value(const char *key, const char *value)
|
|||||||
else {
|
else {
|
||||||
normalized = xmalloc(64);
|
normalized = xmalloc(64);
|
||||||
if (types == TYPE_INT) {
|
if (types == TYPE_INT) {
|
||||||
int v = git_config_int(key, value);
|
int64_t v = git_config_int64(key, value);
|
||||||
sprintf(normalized, "%d", v);
|
sprintf(normalized, "%"PRId64, v);
|
||||||
}
|
}
|
||||||
else if (types == TYPE_BOOL)
|
else if (types == TYPE_BOOL)
|
||||||
sprintf(normalized, "%s",
|
sprintf(normalized, "%s",
|
||||||
|
1
cache.h
1
cache.h
@ -1115,6 +1115,7 @@ extern int git_config_with_options(config_fn_t fn, void *,
|
|||||||
extern int git_config_early(config_fn_t fn, void *, const char *repo_config);
|
extern int git_config_early(config_fn_t fn, void *, const char *repo_config);
|
||||||
extern int git_parse_ulong(const char *, unsigned long *);
|
extern int git_parse_ulong(const char *, unsigned long *);
|
||||||
extern int git_config_int(const char *, const char *);
|
extern int git_config_int(const char *, const char *);
|
||||||
|
extern int64_t git_config_int64(const char *, const char *);
|
||||||
extern unsigned long git_config_ulong(const char *, const char *);
|
extern unsigned long git_config_ulong(const char *, const char *);
|
||||||
extern int git_config_bool_or_int(const char *, const char *, int *);
|
extern int git_config_bool_or_int(const char *, const char *, int *);
|
||||||
extern int git_config_bool(const char *, const char *);
|
extern int git_config_bool(const char *, const char *);
|
||||||
|
84
config.c
84
config.c
@ -468,7 +468,7 @@ static int parse_unit_factor(const char *end, uintmax_t *val)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int git_parse_long(const char *value, long *ret)
|
static int git_parse_signed(const char *value, intmax_t *ret, intmax_t max)
|
||||||
{
|
{
|
||||||
if (value && *value) {
|
if (value && *value) {
|
||||||
char *end;
|
char *end;
|
||||||
@ -480,21 +480,25 @@ static int git_parse_long(const char *value, long *ret)
|
|||||||
val = strtoimax(value, &end, 0);
|
val = strtoimax(value, &end, 0);
|
||||||
if (errno == ERANGE)
|
if (errno == ERANGE)
|
||||||
return 0;
|
return 0;
|
||||||
if (!parse_unit_factor(end, &factor))
|
if (!parse_unit_factor(end, &factor)) {
|
||||||
|
errno = EINVAL;
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
uval = abs(val);
|
uval = abs(val);
|
||||||
uval *= factor;
|
uval *= factor;
|
||||||
if ((uval > maximum_signed_value_of_type(long)) ||
|
if (uval > max || abs(val) > uval) {
|
||||||
(abs(val) > uval))
|
errno = ERANGE;
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
val *= factor;
|
val *= factor;
|
||||||
*ret = val;
|
*ret = val;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
errno = EINVAL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int git_parse_ulong(const char *value, unsigned long *ret)
|
int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max)
|
||||||
{
|
{
|
||||||
if (value && *value) {
|
if (value && *value) {
|
||||||
char *end;
|
char *end;
|
||||||
@ -506,29 +510,75 @@ int git_parse_ulong(const char *value, unsigned long *ret)
|
|||||||
if (errno == ERANGE)
|
if (errno == ERANGE)
|
||||||
return 0;
|
return 0;
|
||||||
oldval = val;
|
oldval = val;
|
||||||
if (!parse_unit_factor(end, &val))
|
if (!parse_unit_factor(end, &val)) {
|
||||||
|
errno = EINVAL;
|
||||||
return 0;
|
return 0;
|
||||||
if ((val > maximum_unsigned_value_of_type(long)) ||
|
}
|
||||||
(oldval > val))
|
if (val > max || oldval > val) {
|
||||||
|
errno = ERANGE;
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
*ret = val;
|
*ret = val;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
errno = EINVAL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void die_bad_config(const char *name)
|
static int git_parse_int(const char *value, int *ret)
|
||||||
{
|
{
|
||||||
|
intmax_t tmp;
|
||||||
|
if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int)))
|
||||||
|
return 0;
|
||||||
|
*ret = tmp;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int git_parse_int64(const char *value, int64_t *ret)
|
||||||
|
{
|
||||||
|
intmax_t tmp;
|
||||||
|
if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int64_t)))
|
||||||
|
return 0;
|
||||||
|
*ret = tmp;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int git_parse_ulong(const char *value, unsigned long *ret)
|
||||||
|
{
|
||||||
|
uintmax_t tmp;
|
||||||
|
if (!git_parse_unsigned(value, &tmp, maximum_unsigned_value_of_type(long)))
|
||||||
|
return 0;
|
||||||
|
*ret = tmp;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void die_bad_number(const char *name, const char *value)
|
||||||
|
{
|
||||||
|
const char *reason = errno == ERANGE ?
|
||||||
|
"out of range" :
|
||||||
|
"invalid unit";
|
||||||
|
if (!value)
|
||||||
|
value = "";
|
||||||
|
|
||||||
if (cf && cf->name)
|
if (cf && cf->name)
|
||||||
die("bad config value for '%s' in %s", name, cf->name);
|
die("bad numeric config value '%s' for '%s' in %s: %s",
|
||||||
die("bad config value for '%s'", name);
|
value, name, cf->name, reason);
|
||||||
|
die("bad numeric config value '%s' for '%s': %s", value, name, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
int git_config_int(const char *name, const char *value)
|
int git_config_int(const char *name, const char *value)
|
||||||
{
|
{
|
||||||
long ret = 0;
|
int ret;
|
||||||
if (!git_parse_long(value, &ret))
|
if (!git_parse_int(value, &ret))
|
||||||
die_bad_config(name);
|
die_bad_number(name, value);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t git_config_int64(const char *name, const char *value)
|
||||||
|
{
|
||||||
|
int64_t ret;
|
||||||
|
if (!git_parse_int64(value, &ret))
|
||||||
|
die_bad_number(name, value);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -536,7 +586,7 @@ unsigned long git_config_ulong(const char *name, const char *value)
|
|||||||
{
|
{
|
||||||
unsigned long ret;
|
unsigned long ret;
|
||||||
if (!git_parse_ulong(value, &ret))
|
if (!git_parse_ulong(value, &ret))
|
||||||
die_bad_config(name);
|
die_bad_number(name, value);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -559,10 +609,10 @@ static int git_config_maybe_bool_text(const char *name, const char *value)
|
|||||||
|
|
||||||
int git_config_maybe_bool(const char *name, const char *value)
|
int git_config_maybe_bool(const char *name, const char *value)
|
||||||
{
|
{
|
||||||
long v = git_config_maybe_bool_text(name, value);
|
int v = git_config_maybe_bool_text(name, value);
|
||||||
if (0 <= v)
|
if (0 <= v)
|
||||||
return v;
|
return v;
|
||||||
if (git_parse_long(value, &v))
|
if (git_parse_int(value, &v))
|
||||||
return !!v;
|
return !!v;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -652,16 +652,23 @@ test_expect_success numbers '
|
|||||||
test_cmp expect actual
|
test_cmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success '--int is at least 64 bits' '
|
||||||
|
git config giga.watts 121g &&
|
||||||
|
echo 129922760704 >expect &&
|
||||||
|
git config --int --get giga.watts >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success 'invalid unit' '
|
test_expect_success 'invalid unit' '
|
||||||
git config aninvalid.unit "1auto" &&
|
git config aninvalid.unit "1auto" &&
|
||||||
echo 1auto >expect &&
|
echo 1auto >expect &&
|
||||||
git config aninvalid.unit >actual &&
|
git config aninvalid.unit >actual &&
|
||||||
test_cmp expect actual &&
|
test_cmp expect actual &&
|
||||||
cat > expect <<-\EOF
|
cat >expect <<-\EOF
|
||||||
fatal: bad config value for '\''aninvalid.unit'\'' in .git/config
|
fatal: bad numeric config value '\''1auto'\'' for '\''aninvalid.unit'\'' in .git/config: invalid unit
|
||||||
EOF
|
EOF
|
||||||
test_must_fail git config --int --get aninvalid.unit 2>actual &&
|
test_must_fail git config --int --get aninvalid.unit 2>actual &&
|
||||||
test_cmp actual expect
|
test_i18ncmp expect actual
|
||||||
'
|
'
|
||||||
|
|
||||||
cat > expect << EOF
|
cat > expect << EOF
|
||||||
|
@ -73,7 +73,7 @@ test_expect_success 'plumbing not affected' '
|
|||||||
test_expect_success 'non-integer config parsing' '
|
test_expect_success 'non-integer config parsing' '
|
||||||
git config diff.context no &&
|
git config diff.context no &&
|
||||||
test_must_fail git diff 2>output &&
|
test_must_fail git diff 2>output &&
|
||||||
test_i18ngrep "bad config value" output
|
test_i18ngrep "bad numeric config value" output
|
||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'negative integer config parsing' '
|
test_expect_success 'negative integer config parsing' '
|
||||||
|
Loading…
Reference in New Issue
Block a user