1From 2d55c7445ffedf30db62231f223137ef02e611a9 Mon Sep 17 00:00:00 2001 2From: Tero Kinnunen <tero.kinnunen@gmail.com> 3Date: Wed, 15 Dec 2021 04:00:28 +0200 4Subject: [PATCH] Parse large floats as infinity (#1349) (#1353) 5 6Return 1.9.1 functionality where values too large to fit in 7double are converted to positive or negative infinity. 8 9Commit 645cd04 changed functionality so that large floats cause 10parse error, while version 1.9.1 accepted them as infinite. 11This is problematic because writer outputs infinity values 12as `1e+9999`, which could no longer be parsed back. 13 14Fixed also legacy Reader even though it did not parse large values 15even before breaking change, due to problematic output/parse asymmetry. 16 17`>>` operator sets value to numeric_limits::max/lowest value if 18representation is too large to fit to double. [1][2] In macos 19value appears to be parsed to infinity. 20 21> | value in *val* | description | 22> |--------------------------|-------------| 23> | numeric_limits::max() | The sequence represents a value too large for the type of val | 24> | numeric_limits::lowest() | The sequence represents a value too large negative for the type of val | 25 26[1] https://www.cplusplus.com/reference/istream/istream/operator%3E%3E/ 27[2] https://www.cplusplus.com/reference/locale/num_get/get/ 28 29Signed-off-by: Tero Kinnunen <tero.kinnunen@vaisala.com> 30 31Co-authored-by: Tero Kinnunen <tero.kinnunen@vaisala.com> 32--- 33 src/lib_json/json_reader.cpp | 18 +++++++++++++++--- 34 test/data/legacy_test_real_13.expected | 3 +++ 35 test/data/legacy_test_real_13.json | 1 + 36 3 files changed, 19 insertions(+), 3 deletions(-) 37 create mode 100644 test/data/legacy_test_real_13.expected 38 create mode 100644 test/data/legacy_test_real_13.json 39 40diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp 41index a6a3f4e..896bf1b 100644 42--- a/src/lib_json/json_reader.cpp 43+++ b/src/lib_json/json_reader.cpp 44@@ -12,6 +12,7 @@ 45 #endif // if !defined(JSON_IS_AMALGAMATION) 46 #include <algorithm> 47 #include <cassert> 48+#include <cmath> 49 #include <cstring> 50 #include <iostream> 51 #include <istream> 52@@ -600,9 +601,15 @@ bool Reader::decodeDouble(Token& token, Value& decoded) { 53 double value = 0; 54 String buffer(token.start_, token.end_); 55 IStringStream is(buffer); 56- if (!(is >> value)) 57- return addError( 58+ if (!(is >> value)) { 59+ if (value == std::numeric_limits<double>::max()) 60+ value = std::numeric_limits<double>::infinity(); 61+ else if (value == std::numeric_limits<double>::lowest()) 62+ value = -std::numeric_limits<double>::infinity(); 63+ else if (!std::isinf(value)) 64+ return addError( 65 "'" + String(token.start_, token.end_) + "' is not a number.", token); 66+ } 67 decoded = value; 68 return true; 69 } 70@@ -1647,7 +1654,12 @@ bool OurReader::decodeDouble(Token& token, Value& decoded) { 71 const String buffer(token.start_, token.end_); 72 IStringStream is(buffer); 73 if (!(is >> value)) { 74- return addError( 75+ if (value == std::numeric_limits<double>::max()) 76+ value = std::numeric_limits<double>::infinity(); 77+ else if (value == std::numeric_limits<double>::lowest()) 78+ value = -std::numeric_limits<double>::infinity(); 79+ else if (!std::isinf(value)) 80+ return addError( 81 "'" + String(token.start_, token.end_) + "' is not a number.", token); 82 } 83 decoded = value; 84diff --git a/test/data/legacy_test_real_13.expected b/test/data/legacy_test_real_13.expected 85new file mode 100644 86index 0000000..8d3f03f 87--- /dev/null 88+++ b/test/data/legacy_test_real_13.expected 89@@ -0,0 +1,3 @@ 90+.=[] 91+.[0]=-inf 92+.[1]=inf 93diff --git a/test/data/legacy_test_real_13.json b/test/data/legacy_test_real_13.json 94new file mode 100644 95index 0000000..287258a 96--- /dev/null 97+++ b/test/data/legacy_test_real_13.json 98@@ -0,0 +1 @@ 99+[-1e+9999, 1e+9999] 100-- 1012.42.0.windows.2 102 103