зеркало из https://github.com/microsoft/git.git
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:
Коммит
c7c377d83f
|
@ -119,7 +119,8 @@ static int format_config(struct strbuf *buf, const char *key_, const char *value
|
|||
must_print_delim = 1;
|
||||
}
|
||||
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)
|
||||
vptr = git_config_bool(key_, value_) ? "true" : "false";
|
||||
else if (types == TYPE_BOOL_OR_INT) {
|
||||
|
@ -268,8 +269,8 @@ static char *normalize_value(const char *key, const char *value)
|
|||
else {
|
||||
normalized = xmalloc(64);
|
||||
if (types == TYPE_INT) {
|
||||
int v = git_config_int(key, value);
|
||||
sprintf(normalized, "%d", v);
|
||||
int64_t v = git_config_int64(key, value);
|
||||
sprintf(normalized, "%"PRId64, v);
|
||||
}
|
||||
else if (types == TYPE_BOOL)
|
||||
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_parse_ulong(const char *, unsigned long *);
|
||||
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 int git_config_bool_or_int(const char *, const char *, int *);
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
char *end;
|
||||
|
@ -480,21 +480,25 @@ static int git_parse_long(const char *value, long *ret)
|
|||
val = strtoimax(value, &end, 0);
|
||||
if (errno == ERANGE)
|
||||
return 0;
|
||||
if (!parse_unit_factor(end, &factor))
|
||||
if (!parse_unit_factor(end, &factor)) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
uval = abs(val);
|
||||
uval *= factor;
|
||||
if ((uval > maximum_signed_value_of_type(long)) ||
|
||||
(abs(val) > uval))
|
||||
if (uval > max || abs(val) > uval) {
|
||||
errno = ERANGE;
|
||||
return 0;
|
||||
}
|
||||
val *= factor;
|
||||
*ret = val;
|
||||
return 1;
|
||||
}
|
||||
errno = EINVAL;
|
||||
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) {
|
||||
char *end;
|
||||
|
@ -506,29 +510,75 @@ int git_parse_ulong(const char *value, unsigned long *ret)
|
|||
if (errno == ERANGE)
|
||||
return 0;
|
||||
oldval = val;
|
||||
if (!parse_unit_factor(end, &val))
|
||||
if (!parse_unit_factor(end, &val)) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
if ((val > maximum_unsigned_value_of_type(long)) ||
|
||||
(oldval > val))
|
||||
}
|
||||
if (val > max || oldval > val) {
|
||||
errno = ERANGE;
|
||||
return 0;
|
||||
}
|
||||
*ret = val;
|
||||
return 1;
|
||||
}
|
||||
errno = EINVAL;
|
||||
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)
|
||||
die("bad config value for '%s' in %s", name, cf->name);
|
||||
die("bad config value for '%s'", name);
|
||||
die("bad numeric config value '%s' for '%s' in %s: %s",
|
||||
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)
|
||||
{
|
||||
long ret = 0;
|
||||
if (!git_parse_long(value, &ret))
|
||||
die_bad_config(name);
|
||||
int ret;
|
||||
if (!git_parse_int(value, &ret))
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -536,7 +586,7 @@ unsigned long git_config_ulong(const char *name, const char *value)
|
|||
{
|
||||
unsigned long ret;
|
||||
if (!git_parse_ulong(value, &ret))
|
||||
die_bad_config(name);
|
||||
die_bad_number(name, value);
|
||||
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)
|
||||
{
|
||||
long v = git_config_maybe_bool_text(name, value);
|
||||
int v = git_config_maybe_bool_text(name, value);
|
||||
if (0 <= v)
|
||||
return v;
|
||||
if (git_parse_long(value, &v))
|
||||
if (git_parse_int(value, &v))
|
||||
return !!v;
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -652,16 +652,23 @@ test_expect_success numbers '
|
|||
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' '
|
||||
git config aninvalid.unit "1auto" &&
|
||||
echo 1auto >expect &&
|
||||
git config aninvalid.unit >actual &&
|
||||
test_cmp expect actual &&
|
||||
cat > expect <<-\EOF
|
||||
fatal: bad config value for '\''aninvalid.unit'\'' in .git/config
|
||||
cat >expect <<-\EOF
|
||||
fatal: bad numeric config value '\''1auto'\'' for '\''aninvalid.unit'\'' in .git/config: invalid unit
|
||||
EOF
|
||||
test_must_fail git config --int --get aninvalid.unit 2>actual &&
|
||||
test_cmp actual expect
|
||||
test_i18ncmp expect actual
|
||||
'
|
||||
|
||||
cat > expect << EOF
|
||||
|
|
|
@ -73,7 +73,7 @@ test_expect_success 'plumbing not affected' '
|
|||
test_expect_success 'non-integer config parsing' '
|
||||
git config diff.context no &&
|
||||
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' '
|
||||
|
|
Загрузка…
Ссылка в новой задаче