Disallow inf/nan in json mode

This commit is contained in:
Maya Warrier 2023-09-14 20:51:26 -04:00
parent 2395482ad5
commit ce562d9c65
4 changed files with 16 additions and 7 deletions

View File

@ -280,7 +280,7 @@ parsed_number_string_t<UC> parse_number_string(UC const *p, UC const * pend, par
answer.too_many_digits = false; answer.too_many_digits = false;
answer.negative = (*p == UC('-')); answer.negative = (*p == UC('-'));
#ifdef FASTFLOAT_ALLOWS_LEADING_PLUS // disabled by default #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 #else
if (*p == UC('-')) { // C++17 20.19.3.(7.1) explicitly forbids '+' sign here if (*p == UC('-')) { // C++17 20.19.3.(7.1) explicitly forbids '+' sign here
#endif #endif
@ -288,7 +288,7 @@ parsed_number_string_t<UC> parse_number_string(UC const *p, UC const * pend, par
if (p == pend) { if (p == pend) {
return answer; return answer;
} }
if (fmt == chars_format::json) { if (fmt & FASTFLOAT_JSONFMT) {
if (!is_integer(*p)) { // a sign must be followed by an integer if (!is_integer(*p)) { // a sign must be followed by an integer
return answer; return answer;
} }
@ -312,7 +312,7 @@ parsed_number_string_t<UC> parse_number_string(UC const *p, UC const * pend, par
UC const * const end_of_integer_part = p; UC const * const end_of_integer_part = p;
int64_t digit_count = int64_t(end_of_integer_part - start_digits); int64_t digit_count = int64_t(end_of_integer_part - start_digits);
answer.integer = span<const UC>(start_digits, size_t(digit_count)); answer.integer = span<const UC>(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 // at least 1 digit in integer part, without leading zeros
if (digit_count == 0 || (start_digits[0] == UC('0') && digit_count > 1)) { if (digit_count == 0 || (start_digits[0] == UC('0') && digit_count > 1)) {
return answer; return answer;
@ -337,7 +337,7 @@ parsed_number_string_t<UC> parse_number_string(UC const *p, UC const * pend, par
answer.fraction = span<const UC>(before, size_t(p - before)); answer.fraction = span<const UC>(before, size_t(p - before));
digit_count -= exponent; digit_count -= exponent;
} }
if (fmt == chars_format::json) { if (fmt & FASTFLOAT_JSONFMT) {
// at least 1 digit in fractional part // at least 1 digit in fractional part
if (has_decimal_point && exponent == 0) { if (has_decimal_point && exponent == 0) {
return answer; return answer;

View File

@ -12,11 +12,14 @@
namespace fast_float { namespace fast_float {
#define FASTFLOAT_JSONFMT (1 << 5)
enum chars_format { enum chars_format {
scientific = 1 << 0, scientific = 1 << 0,
fixed = 1 << 2, fixed = 1 << 2,
hex = 1 << 3, hex = 1 << 3,
json = 1 << 4 | fixed | scientific, no_infnan = 1 << 4,
json = FASTFLOAT_JSONFMT | fixed | scientific | no_infnan,
general = fixed | scientific general = fixed | scientific
}; };

View File

@ -164,7 +164,13 @@ from_chars_result_t<UC> from_chars_advanced(UC const * first, UC const * last,
} }
parsed_number_string_t<UC> pns = parse_number_string<UC>(first, last, options); parsed_number_string_t<UC> pns = parse_number_string<UC>(first, last, options);
if (!pns.valid) { 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 answer.ec = std::errc(); // be optimistic

View File

@ -12,7 +12,7 @@ int main()
{ {
const std::vector<double> expected{ -0.2, 0.02, 0.002, 1., 0. }; const std::vector<double> expected{ -0.2, 0.02, 0.002, 1., 0. };
const std::vector<std::string> accept{ "-0.2", "0.02", "0.002", "1e+0000", "0e-2" }; const std::vector<std::string> accept{ "-0.2", "0.02", "0.002", "1e+0000", "0e-2" };
const std::vector<std::string> reject{ "-.2", "00.02", "0.e+1", "00.e+1", ".25", "+0.25"}; const std::vector<std::string> reject{ "-.2", "00.02", "0.e+1", "00.e+1", ".25", "+0.25", "inf", "nan(snan)"};
const auto fmt = fast_float::chars_format::json; const auto fmt = fast_float::chars_format::json;
for (std::size_t i = 0; i < accept.size(); ++i) for (std::size_t i = 0; i < accept.size(); ++i)