From c4117c68ccf45e2f80ea7693766db0c771b6d508 Mon Sep 17 00:00:00 2001 From: StilesCrisis Date: Wed, 22 Feb 2017 21:54:31 -0800 Subject: [PATCH 1/2] Put in unit tests to catch parser failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Noticed that the reader could over-consume “NaN” if token terminated in the middle. --- test/unittest/readertest.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index ac5a067..0973791 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -1832,6 +1832,10 @@ TEST(Reader, ParseNanAndInfinity) { TEST_NAN_INF("Infinity", inf); TEST_NAN_INF("-Inf", -inf); TEST_NAN_INF("-Infinity", -inf); + TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "NInf", 1); + TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "NaInf", 1); + TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "INan", 1); + TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "InNan", 1); TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "nan", 1); TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "-nan", 1); TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "NAN", 1); From 5e785d3db20cdad256a7c0139001b484ea37fab9 Mon Sep 17 00:00:00 2001 From: StilesCrisis Date: Thu, 23 Feb 2017 00:11:12 -0800 Subject: [PATCH 2/2] Fix parsing of NaN/Inf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A failed half-consume of “NaN” now returns “value invalid” instead of attempting to consume an “Inf”. --- include/rapidjson/reader.h | 27 ++++++++++++++++++--------- test/unittest/readertest.cpp | 4 ++-- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index dbb5e16..c1d10e8 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -1170,18 +1170,27 @@ private: } // Parse NaN or Infinity here else if ((parseFlags & kParseNanAndInfFlag) && RAPIDJSON_LIKELY((s.Peek() == 'I' || s.Peek() == 'N'))) { - useNanOrInf = true; - if (RAPIDJSON_LIKELY(Consume(s, 'N') && Consume(s, 'a') && Consume(s, 'N'))) { - d = std::numeric_limits::quiet_NaN(); + if (Consume(s, 'N')) { + if (Consume(s, 'a') && Consume(s, 'N')) { + d = std::numeric_limits::quiet_NaN(); + useNanOrInf = true; + } } - else if (RAPIDJSON_LIKELY(Consume(s, 'I') && Consume(s, 'n') && Consume(s, 'f'))) { - d = (minus ? -std::numeric_limits::infinity() : std::numeric_limits::infinity()); - if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n') - && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y')))) - RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); + else if (RAPIDJSON_LIKELY(Consume(s, 'I'))) { + if (Consume(s, 'n') && Consume(s, 'f')) { + d = (minus ? -std::numeric_limits::infinity() : std::numeric_limits::infinity()); + useNanOrInf = true; + + if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n') + && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y')))) { + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); + } + } } - else + + if (RAPIDJSON_UNLIKELY(!useNanOrInf)) { RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); + } } else RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index 0973791..2217a12 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -1833,9 +1833,9 @@ TEST(Reader, ParseNanAndInfinity) { TEST_NAN_INF("-Inf", -inf); TEST_NAN_INF("-Infinity", -inf); TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "NInf", 1); - TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "NaInf", 1); + TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "NaInf", 2); TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "INan", 1); - TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "InNan", 1); + TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "InNan", 2); TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "nan", 1); TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "-nan", 1); TEST_NAN_INF_ERROR(kParseErrorValueInvalid, "NAN", 1);