From ce562d9c65fee59e71dadff9a29ba86a7fba3b68 Mon Sep 17 00:00:00 2001 From: Maya Warrier Date: Thu, 14 Sep 2023 20:51:26 -0400 Subject: [PATCH] Disallow inf/nan in json mode --- include/fast_float/ascii_number.h | 8 ++++---- include/fast_float/float_common.h | 5 ++++- include/fast_float/parse_number.h | 8 +++++++- tests/json_fmt.cpp | 2 +- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 21fbac4..9653889 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -280,7 +280,7 @@ parsed_number_string_t parse_number_string(UC const *p, UC const * pend, par answer.too_many_digits = false; answer.negative = (*p == UC('-')); #ifdef FASTFLOAT_ALLOWS_LEADING_PLUS // disabled by default - if ((*p == UC('-')) || (fmt != chars_format::json && *p == UC('+'))) { + if ((*p == UC('-')) || (!(fmt & FASTFLOAT_JSONFMT) && *p == UC('+'))) { #else if (*p == UC('-')) { // C++17 20.19.3.(7.1) explicitly forbids '+' sign here #endif @@ -288,7 +288,7 @@ parsed_number_string_t parse_number_string(UC const *p, UC const * pend, par if (p == pend) { return answer; } - if (fmt == chars_format::json) { + if (fmt & FASTFLOAT_JSONFMT) { if (!is_integer(*p)) { // a sign must be followed by an integer return answer; } @@ -312,7 +312,7 @@ parsed_number_string_t parse_number_string(UC const *p, UC const * pend, par UC const * const end_of_integer_part = p; int64_t digit_count = int64_t(end_of_integer_part - start_digits); answer.integer = span(start_digits, size_t(digit_count)); - if (fmt == chars_format::json) { + if (fmt & FASTFLOAT_JSONFMT) { // at least 1 digit in integer part, without leading zeros if (digit_count == 0 || (start_digits[0] == UC('0') && digit_count > 1)) { return answer; @@ -337,7 +337,7 @@ parsed_number_string_t parse_number_string(UC const *p, UC const * pend, par answer.fraction = span(before, size_t(p - before)); digit_count -= exponent; } - if (fmt == chars_format::json) { + if (fmt & FASTFLOAT_JSONFMT) { // at least 1 digit in fractional part if (has_decimal_point && exponent == 0) { return answer; diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 7050073..c101673 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -12,11 +12,14 @@ namespace fast_float { +#define FASTFLOAT_JSONFMT (1 << 5) + enum chars_format { scientific = 1 << 0, fixed = 1 << 2, hex = 1 << 3, - json = 1 << 4 | fixed | scientific, + no_infnan = 1 << 4, + json = FASTFLOAT_JSONFMT | fixed | scientific | no_infnan, general = fixed | scientific }; diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index e077b9d..a011a8c 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -164,7 +164,13 @@ from_chars_result_t from_chars_advanced(UC const * first, UC const * last, } parsed_number_string_t pns = parse_number_string(first, last, options); if (!pns.valid) { - return detail::parse_infnan(first, last, value); + if (options.format & chars_format::no_infnan) { + answer.ec = std::errc::invalid_argument; + answer.ptr = first; + return answer; + } else { + return detail::parse_infnan(first, last, value); + } } answer.ec = std::errc(); // be optimistic diff --git a/tests/json_fmt.cpp b/tests/json_fmt.cpp index b1c3977..1fdd636 100644 --- a/tests/json_fmt.cpp +++ b/tests/json_fmt.cpp @@ -12,7 +12,7 @@ int main() { const std::vector expected{ -0.2, 0.02, 0.002, 1., 0. }; const std::vector accept{ "-0.2", "0.02", "0.002", "1e+0000", "0e-2" }; - const std::vector reject{ "-.2", "00.02", "0.e+1", "00.e+1", ".25", "+0.25"}; + const std::vector reject{ "-.2", "00.02", "0.e+1", "00.e+1", ".25", "+0.25", "inf", "nan(snan)"}; const auto fmt = fast_float::chars_format::json; for (std::size_t i = 0; i < accept.size(); ++i)