From 5355d387e90c8e74ca4c7b9d2e2f7eb828a08ea3 Mon Sep 17 00:00:00 2001 From: Jason King Date: Thu, 7 Sep 2017 17:21:14 +0000 Subject: [PATCH] Use strtoll to parse ints --- json_util.c | 123 ++++------------------------------------------------ 1 file changed, 8 insertions(+), 115 deletions(-) diff --git a/json_util.c b/json_util.c index 4624668..00cdc30 100644 --- a/json_util.c +++ b/json_util.c @@ -57,10 +57,6 @@ #include "json_tokener.h" #include "json_util.h" -static int sscanf_is_broken = 0; -static int sscanf_is_broken_testdone = 0; -static void sscanf_is_broken_test(void); - static int _json_object_to_fd(int fd, struct json_object *obj, int flags, const char *filename); static char _last_err[256] = ""; @@ -195,119 +191,16 @@ int json_parse_double(const char *buf, double *retval) return end == buf ? 1 : 0; } -/* - * Not all implementations of sscanf actually work properly. - * Check whether the one we're currently using does, and if - * it's broken, enable the workaround code. - */ -static void sscanf_is_broken_test() -{ - int64_t num64; - int ret_errno, is_int64_min, ret_errno2, is_int64_max; - - (void)sscanf(" -01234567890123456789012345", "%" SCNd64, &num64); - ret_errno = errno; - is_int64_min = (num64 == INT64_MIN); - - (void)sscanf(" 01234567890123456789012345", "%" SCNd64, &num64); - ret_errno2 = errno; - is_int64_max = (num64 == INT64_MAX); - - if (ret_errno != ERANGE || !is_int64_min || - ret_errno2 != ERANGE || !is_int64_max) - { - MC_DEBUG("sscanf_is_broken_test failed, enabling workaround code\n"); - sscanf_is_broken = 1; - } -} - int json_parse_int64(const char *buf, int64_t *retval) { - int64_t num64; - const char *buf_sig_digits; - int orig_has_neg; - int saved_errno; - - if (!sscanf_is_broken_testdone) - { - sscanf_is_broken_test(); - sscanf_is_broken_testdone = 1; - } - - // Skip leading spaces - while (isspace((int)*buf) && *buf) - buf++; - - errno = 0; // sscanf won't always set errno, so initialize - if (sscanf(buf, "%" SCNd64, &num64) != 1) - { - MC_DEBUG("Failed to parse, sscanf != 1\n"); - return 1; - } - - saved_errno = errno; - buf_sig_digits = buf; - orig_has_neg = 0; - if (*buf_sig_digits == '-') - { - buf_sig_digits++; - orig_has_neg = 1; - } - - // Not all sscanf implementations actually work - if (sscanf_is_broken && saved_errno != ERANGE) - { - char buf_cmp[100]; - char *buf_cmp_start = buf_cmp; - int recheck_has_neg = 0; - int buf_cmp_len; - - // Skip leading zeros, but keep at least one digit - while (buf_sig_digits[0] == '0' && buf_sig_digits[1] != '\0') - buf_sig_digits++; - // Can't check num64==0 because some sscanf impl's parse - // non-zero values to 0. (e.g. Illumos with UINT64_MAX) - if (buf_sig_digits[0] == '0' && buf_sig_digits[1] == '\0') - orig_has_neg = 0; // "-0" is the same as just plain "0" - - snprintf(buf_cmp_start, sizeof(buf_cmp), "%" PRId64, num64); - if (*buf_cmp_start == '-') - { - recheck_has_neg = 1; - buf_cmp_start++; - } - // No need to skip leading spaces or zeros here. - - buf_cmp_len = strlen(buf_cmp_start); - /** - * If the sign is different, or - * some of the digits are different, or - * there is another digit present in the original string - * then we have NOT successfully parsed the value. - */ - if (orig_has_neg != recheck_has_neg || - strncmp(buf_sig_digits, buf_cmp_start, strlen(buf_cmp_start)) != 0 || - ((int)strlen(buf_sig_digits) != buf_cmp_len && - isdigit((int)buf_sig_digits[buf_cmp_len]) - ) - ) - { - saved_errno = ERANGE; - } - } - - // Not all sscanf impl's set the value properly when out of range. - // Always do this, even for properly functioning implementations, - // since it shouldn't slow things down much. - if (saved_errno == ERANGE) - { - if (orig_has_neg) - num64 = INT64_MIN; - else - num64 = INT64_MAX; - } - *retval = num64; - return 0; + char *end = NULL; + int64_t val; + + errno = 0; + val = strtoll(buf, &end, 10); + if (end != buf) + *retval = val; + return ((val == 0 && errno != 0) || (end == buf)) ? 1 : 0; } #ifndef HAVE_REALLOC