From 93d13ad2acc6a52d58e09d84e76826cd36ee64f0 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 24 Apr 2015 21:44:42 +0800 Subject: [PATCH 1/3] Fix #313 Assertion In `Pow10.h` is triggered in Document::Parse --- include/rapidjson/reader.h | 5 +++++ test/unittest/readertest.cpp | 14 +++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 08297a08..320428ff 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -929,6 +929,11 @@ private: exp = exp * 10 + (s.Take() - '0'); if (exp > 308 && !expMinus) // exp > 308 should be rare, so it should be checked first. RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell()); + else if (exp >= 429496729 && expMinus) { // Issue #313: prevent overflow exponent + while (s.Peek() >= '0' && s.Peek() <= '9') // Consume the rest of exponent + s.Take(); + break; + } } } else diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index 4e8d4e4a..86199fab 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -219,13 +219,17 @@ static void TestParseDouble() { TEST_DOUBLE(fullPrecision, "2.2250738585072009e-308", 2.2250738585072009e-308); // Max subnormal double TEST_DOUBLE(fullPrecision, "2.2250738585072014e-308", 2.2250738585072014e-308); // Min normal positive double TEST_DOUBLE(fullPrecision, "1.7976931348623157e+308", 1.7976931348623157e+308); // Max double - TEST_DOUBLE(fullPrecision, "1e-10000", 0.0); // must underflow - TEST_DOUBLE(fullPrecision, "18446744073709551616", 18446744073709551616.0); // 2^64 (max of uint64_t + 1, force to use double) - TEST_DOUBLE(fullPrecision, "-9223372036854775809", -9223372036854775809.0); // -2^63 - 1(min of int64_t + 1, force to use double) - TEST_DOUBLE(fullPrecision, "0.9868011474609375", 0.9868011474609375); // https://github.com/miloyip/rapidjson/issues/120 - TEST_DOUBLE(fullPrecision, "123e34", 123e34); // Fast Path Cases In Disguise + TEST_DOUBLE(fullPrecision, "1e-10000", 0.0); // must underflow + TEST_DOUBLE(fullPrecision, "18446744073709551616", 18446744073709551616.0); // 2^64 (max of uint64_t + 1, force to use double) + TEST_DOUBLE(fullPrecision, "-9223372036854775809", -9223372036854775809.0); // -2^63 - 1(min of int64_t + 1, force to use double) + TEST_DOUBLE(fullPrecision, "0.9868011474609375", 0.9868011474609375); // https://github.com/miloyip/rapidjson/issues/120 + TEST_DOUBLE(fullPrecision, "123e34", 123e34); // Fast Path Cases In Disguise TEST_DOUBLE(fullPrecision, "45913141877270640000.0", 45913141877270640000.0); TEST_DOUBLE(fullPrecision, "2.2250738585072011e-308", 2.2250738585072011e-308); // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/ + TEST_DOUBLE(fullPrecision, "1e-00011111111111", 0.0); // Issue #313 + TEST_DOUBLE(fullPrecision, "-1e-00011111111111", -0.0); + TEST_DOUBLE(fullPrecision, "1e-429496729", 0.0); // Maximum supported negative exponent + // Since // abs((2^-1022 - 2^-1074) - 2.2250738585072012e-308) = 3.109754131239141401123495768877590405345064751974375599... กม 10^-324 From 735354efd328709a8efb6a2a43a584bb85f2de6b Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Fri, 24 Apr 2015 22:50:42 +0800 Subject: [PATCH 2/3] Separate handling for pos/neg exp and improve pos exp overflow --- include/rapidjson/reader.h | 23 +++++++++++++++-------- test/unittest/readertest.cpp | 1 + 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index 320428ff..d809d573 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -925,14 +925,21 @@ private: if (s.Peek() >= '0' && s.Peek() <= '9') { exp = s.Take() - '0'; - while (s.Peek() >= '0' && s.Peek() <= '9') { - exp = exp * 10 + (s.Take() - '0'); - if (exp > 308 && !expMinus) // exp > 308 should be rare, so it should be checked first. - RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell()); - else if (exp >= 429496729 && expMinus) { // Issue #313: prevent overflow exponent - while (s.Peek() >= '0' && s.Peek() <= '9') // Consume the rest of exponent - s.Take(); - break; + if (expMinus) { + while (s.Peek() >= '0' && s.Peek() <= '9') { + exp = exp * 10 + (s.Take() - '0'); + if (exp >= 429496729) { // Issue #313: prevent overflow exponent + while (s.Peek() >= '0' && s.Peek() <= '9') // Consume the rest of exponent + s.Take(); + } + } + } + else { // positive exp + int maxExp = 308 - expFrac; + while (s.Peek() >= '0' && s.Peek() <= '9') { + exp = exp * 10 + (s.Take() - '0'); + if (exp > maxExp) + RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell()); } } } diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index 86199fab..e55380c6 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -229,6 +229,7 @@ static void TestParseDouble() { TEST_DOUBLE(fullPrecision, "1e-00011111111111", 0.0); // Issue #313 TEST_DOUBLE(fullPrecision, "-1e-00011111111111", -0.0); TEST_DOUBLE(fullPrecision, "1e-429496729", 0.0); // Maximum supported negative exponent + TEST_DOUBLE(fullPrecision, "0.017976931348623157e+310", 1.7976931348623157e+308); // Max double in another form // Since From 7708215b609733bcfa06074b67463920c03782e8 Mon Sep 17 00:00:00 2001 From: Milo Yip Date: Sat, 25 Apr 2015 00:13:09 +0800 Subject: [PATCH 3/3] Try to fix #313 again --- include/rapidjson/reader.h | 2 +- test/unittest/readertest.cpp | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h index d809d573..be0d9fb9 100644 --- a/include/rapidjson/reader.h +++ b/include/rapidjson/reader.h @@ -928,7 +928,7 @@ private: if (expMinus) { while (s.Peek() >= '0' && s.Peek() <= '9') { exp = exp * 10 + (s.Take() - '0'); - if (exp >= 429496729) { // Issue #313: prevent overflow exponent + if (exp >= 214748364) { // Issue #313: prevent overflow exponent while (s.Peek() >= '0' && s.Peek() <= '9') // Consume the rest of exponent s.Take(); } diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index e55380c6..bee19a8e 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -228,9 +228,10 @@ static void TestParseDouble() { TEST_DOUBLE(fullPrecision, "2.2250738585072011e-308", 2.2250738585072011e-308); // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/ TEST_DOUBLE(fullPrecision, "1e-00011111111111", 0.0); // Issue #313 TEST_DOUBLE(fullPrecision, "-1e-00011111111111", -0.0); - TEST_DOUBLE(fullPrecision, "1e-429496729", 0.0); // Maximum supported negative exponent + TEST_DOUBLE(fullPrecision, "1e-214748363", 0.0); // Maximum supported negative exponent + TEST_DOUBLE(fullPrecision, "1e-214748364", 0.0); + TEST_DOUBLE(fullPrecision, "1e-21474836311", 0.0); TEST_DOUBLE(fullPrecision, "0.017976931348623157e+310", 1.7976931348623157e+308); // Max double in another form - // Since // abs((2^-1022 - 2^-1074) - 2.2250738585072012e-308) = 3.109754131239141401123495768877590405345064751974375599... กม 10^-324