From 4e9b4f6d6a57bb6fb1419b824073073078dbceb3 Mon Sep 17 00:00:00 2001 From: abolz Date: Fri, 15 Jun 2018 11:32:32 +0200 Subject: [PATCH] Return 0 if binary exponent is too small --- include/rapidjson/internal/diyfp.h | 19 +++++++++++-------- test/unittest/readertest.cpp | 17 +++++++++++++---- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/include/rapidjson/internal/diyfp.h b/include/rapidjson/internal/diyfp.h index b02e0ca..85243af 100644 --- a/include/rapidjson/internal/diyfp.h +++ b/include/rapidjson/internal/diyfp.h @@ -1,5 +1,5 @@ // Tencent is pleased to support the open source community by making RapidJSON available. -// +// // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except @@ -7,9 +7,9 @@ // // http://opensource.org/licenses/MIT // -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. // This is a C++ header-only implementation of Grisu2 algorithm from the publication: @@ -56,7 +56,7 @@ struct DiyFp { if (biased_e != 0) { f = significand + kDpHiddenBit; e = biased_e - kDpExponentBias; - } + } else { f = significand; e = kDpMinExponent + 1; @@ -142,9 +142,12 @@ struct DiyFp { uint64_t u64; }u; RAPIDJSON_ASSERT(f <= kDpHiddenBit + kDpSignificandMask); - RAPIDJSON_ASSERT(e >= kDpDenormalExponent); + if (e < kDpDenormalExponent) { + // Underflow. + return 0.0; + } RAPIDJSON_ASSERT(e < kDpMaxExponent); - const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 : + const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 : static_cast(e + kDpExponentBias); u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize); return u.d; @@ -226,7 +229,7 @@ inline DiyFp GetCachedPowerByIndex(size_t index) { RAPIDJSON_ASSERT(index < 87); return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]); } - + inline DiyFp GetCachedPower(int e, int* K) { //int k = static_cast(ceil((-61 - e) * 0.30102999566398114)) + 374; diff --git a/test/unittest/readertest.cpp b/test/unittest/readertest.cpp index 622de60..ac0cb31 100644 --- a/test/unittest/readertest.cpp +++ b/test/unittest/readertest.cpp @@ -392,6 +392,15 @@ static void TestParseDouble() { "83723677529752585477247372368372368547354737253685475529752", 6223372036854775808.0); + + TEST_DOUBLE(fullPrecision, "1e-325", 0.0); + TEST_DOUBLE(fullPrecision, "1e-324", 0.0); + TEST_DOUBLE(fullPrecision, "2e-324", 0.0); + TEST_DOUBLE(fullPrecision, "2.4703282292062327e-324", 0.0); + TEST_DOUBLE(fullPrecision, "2.4703282292062328e-324", 2.4703282292062328e-324); + TEST_DOUBLE(fullPrecision, "2.48e-324", 2.48e-324); + TEST_DOUBLE(fullPrecision, "2.5e-324", 2.5e-324); + #undef TEST_DOUBLE } @@ -1346,20 +1355,20 @@ TEST(Reader, IterativePullParsing_General) { handler.LOG_DOUBLE, handler.LOG_ENDARRAY | 7 }; - + StringStream is("[1, {\"k\": [1, 2]}, null, false, true, \"string\", 1.2]"); Reader reader; - + reader.IterativeParseInit(); while (!reader.IterativeParseComplete()) { size_t oldLogCount = handler.LogCount; EXPECT_TRUE(oldLogCount < sizeof(e) / sizeof(int)) << "overrun"; - + EXPECT_TRUE(reader.IterativeParseNext(is, handler)) << "parse fail"; EXPECT_EQ(handler.LogCount, oldLogCount + 1) << "handler should be invoked exactly once each time"; EXPECT_EQ(e[oldLogCount], handler.Logs[oldLogCount]) << "wrong event returned"; } - + EXPECT_FALSE(reader.HasParseError()); EXPECT_EQ(sizeof(e) / sizeof(int), handler.LogCount) << "handler invoked wrong number of times";