[PATCH 3/5] config: set errno in numeric git_parse_* functions
- From
Jeff King <peff@peff.net>
- Date
- Sep 8, 2013, 08:36 UTC
- Message-ID
- <20130908083642.GC29554@sigill.intra.peff.net>
- In-Reply-To
- <20130908082724.GA27184@sigill.intra.peff.net>
When we are parsing an integer or unsigned long, we use the strto*max functions, which properly set errno to ERANGE if we get a large value. However, we also do further range checks after applying our multiplication factor, but do not set ERANGE. This means that a caller cannot tell if an error was caused by ERANGE or if the input was simply not a valid number.
This patch teaches git_parse_signed and git_parse_unsigned reliably set ERANGE for range errors, and EINVAL for other errors.
Signed-off-by: Jeff King <peff@peff.net> --- I'm a little iffy on using errno like this. The "normal" way in git would be to return an enum like:
enum config_parse_error {
CONFIG_PARSE_SUCCESS = 0,
CONFIG_PARSE_RANGE = -1,
CONFIG_PARSE_INVALID_UNIT = -2
};But that would be changing the return semantics of git_parse_ulong (which currently is "0" for fail, "1" for success) without changing its signature. I figured this was the path of least resistance since we already get ERANGE out of strtoimax, but I'm happy to switch it, too.
config.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-)
diff --git a/config.c b/config.c index 0a65ac2..7332b06 100644 --- a/config.c +++ b/config.c @@ -480,16 +480,21 @@ static int git_parse_signed(const char *value, intmax_t *ret, intmax_t max) 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 > max || abs(val) > uval) + if (uval > max || abs(val) > uval) { + errno = ERANGE; return 0; + } val *= factor; *ret = val; return 1; } + errno = EINVAL; return 0; } @@ -505,13 +510,18 @@ int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max) 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 > max || oldval > val) + } + if (val > max || oldval > val) { + errno = ERANGE; return 0; + } *ret = val; return 1; } + errno = EINVAL; return 0; }
-- 1.8.4.2.g87d4a77