From 06e2a291b1492dbabc6929ed77a63bda7427ced0 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 26 Mar 2017 17:26:41 +0200 Subject: [PATCH] :hammer: fixed number parsing --- src/json.hpp | 65 +++++++++++++++++++++------------- test/src/unit-class_parser.cpp | 2 +- test/src/unit-regression.cpp | 1 + test/src/unit-testsuites.cpp | 1 + 4 files changed, 43 insertions(+), 26 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 6cbcdf286..e47abab4b 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -222,8 +222,8 @@ class parse_error : public exception const size_t byte; private: - parse_error(int id, size_t byte_, const char* what_arg) - : exception(id, what_arg), byte(byte_) + parse_error(int id_, size_t byte_, const char* what_arg) + : exception(id_, what_arg), byte(byte_) {} }; @@ -261,8 +261,8 @@ class invalid_iterator : public exception } private: - invalid_iterator(int id, const char* what_arg) - : exception(id, what_arg) + invalid_iterator(int id_, const char* what_arg) + : exception(id_, what_arg) {} }; @@ -300,8 +300,8 @@ class type_error : public exception } private: - type_error(int id, const char* what_arg) - : exception(id, what_arg) + type_error(int id_, const char* what_arg) + : exception(id_, what_arg) {} }; @@ -331,8 +331,8 @@ class out_of_range : public exception } private: - out_of_range(int id, const char* what_arg) - : exception(id, what_arg) + out_of_range(int id_, const char* what_arg) + : exception(id_, what_arg) {} }; @@ -357,8 +357,8 @@ class other_error : public exception } private: - other_error(int id, const char* what_arg) - : exception(id, what_arg) + other_error(int id_, const char* what_arg) + : exception(id_, what_arg) {} }; @@ -10828,24 +10828,33 @@ class basic_json add('\0'); --yylen; - if (has_exp or has_point) + // the conversion + char* endptr = nullptr; + + // try to parse integers first and fall back to floats + if (not has_exp and not has_point) { - value_float = std::strtod(yytext.data(), nullptr); - return token_type::value_float; + errno = 0; + if (has_sign) + { + value_integer = std::strtoll(yytext.data(), &endptr, 10); + if (JSON_LIKELY(errno == 0 and endptr == yytext.data() + yylen)) + { + return token_type::value_integer; + } + } + else + { + value_unsigned = std::strtoull(yytext.data(), &endptr, 10); + if (JSON_LIKELY(errno == 0 and endptr == yytext.data() + yylen)) + { + return token_type::value_unsigned; + } + } } - if (has_sign) - { - char* endptr = nullptr; - value_integer = std::strtoll(yytext.data(), &endptr, 10); - return token_type::value_integer; - } - else - { - char* endptr = nullptr; - value_unsigned = std::strtoull(yytext.data(), &endptr, 10); - return token_type::value_unsigned; - } + value_float = std::strtod(yytext.data(), nullptr); + return token_type::value_float; } token_type scan_true() @@ -10986,6 +10995,12 @@ class basic_json case lexer::token_type::value_float: { + // throw in case of infinity or NAN + if (not std::isfinite(value_float)) + { + JSON_THROW(out_of_range::create(406, "number overflow parsing '" + get_token_string() + "'")); + } + result.m_type = value_t::number_float; result.m_value = static_cast(value_float); return true; diff --git a/test/src/unit-class_parser.cpp b/test/src/unit-class_parser.cpp index 364510422..3e5b28718 100644 --- a/test/src/unit-class_parser.cpp +++ b/test/src/unit-class_parser.cpp @@ -529,7 +529,7 @@ TEST_CASE("parser class") if (c > 0x1f) { CHECK_THROWS_WITH(json::parser(s.c_str()).parse(), - "[json.exception.parse_error.101] parse error at 3: syntax error - invalid string: forbidden character after backspace; last read '\"\\" + std::string(1, c) + "'"); + "[json.exception.parse_error.101] parse error at 3: syntax error - invalid string: forbidden character after backspace; last read '\"\\" + std::string(1, static_cast(c)) + "'"); } break; } diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index 2c09abaa1..df685d2cc 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -216,6 +216,7 @@ TEST_CASE("regression tests") { json a = {1, 2, 3}; json::reverse_iterator rit = ++a.rbegin(); + CHECK(*rit == json(2)); } { json a = {1, 2, 3}; diff --git a/test/src/unit-testsuites.cpp b/test/src/unit-testsuites.cpp index 8d6a81622..c46a4ffa7 100644 --- a/test/src/unit-testsuites.cpp +++ b/test/src/unit-testsuites.cpp @@ -305,6 +305,7 @@ TEST_CASE("compliance tests from nativejson-benchmark") std::string json_string( (std::istreambuf_iterator(f) ), (std::istreambuf_iterator()) ); + CAPTURE(json_string); json j = json::parse(json_string); CHECK(j.dump() == json_string); }