| @@ -57,10 +57,6 @@ | |||||
| #include "json_tokener.h" | #include "json_tokener.h" | ||||
| #include "json_util.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 int _json_object_to_fd(int fd, struct json_object *obj, int flags, const char *filename); | ||||
| static char _last_err[256] = ""; | static char _last_err[256] = ""; | ||||
| @@ -195,119 +191,16 @@ int json_parse_double(const char *buf, double *retval) | |||||
| return end == buf ? 1 : 0; | 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) | 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 | #ifndef HAVE_REALLOC | ||||