diff options
author | Arne Juul <arnej@yahoo-inc.com> | 2019-06-12 12:03:25 +0000 |
---|---|---|
committer | Arne Juul <arnej@yahoo-inc.com> | 2019-06-12 12:09:47 +0000 |
commit | 64fb9d91dcfd8511c94ecae3ca0a7652010e3892 (patch) | |
tree | 686536d56996fe196babc7fdae107e0cf6e079e1 /vespalib/src | |
parent | 07d3c4efed886275aa86b5c8587b768904237e04 (diff) |
* no exception on underflow in strtof() and strtod()
* still throw exception on overflow instead of returning HUGE_VAL
* change exception message to make it readable
* unit test float and double conversion from denormalized numbers
Diffstat (limited to 'vespalib/src')
-rw-r--r-- | vespalib/src/tests/stllike/asciistream_test.cpp | 65 | ||||
-rw-r--r-- | vespalib/src/vespa/vespalib/stllike/asciistream.cpp | 25 |
2 files changed, 83 insertions, 7 deletions
diff --git a/vespalib/src/tests/stllike/asciistream_test.cpp b/vespalib/src/tests/stllike/asciistream_test.cpp index b0f6d8cb455..e38a7e8b3e5 100644 --- a/vespalib/src/tests/stllike/asciistream_test.cpp +++ b/vespalib/src/tests/stllike/asciistream_test.cpp @@ -4,7 +4,9 @@ #include <vespa/vespalib/testkit/testapp.h> #include <vespa/vespalib/stllike/asciistream.h> #include <vespa/vespalib/util/exceptions.h> +#include <vespa/vespalib/locale/c.h> #include <iomanip> +#include <float.h> using namespace vespalib; @@ -26,6 +28,7 @@ public: void testMoveIsWellDefined(); void testIllegalNumbers(); void testDouble(); + void testFloat(); void testStateSaver(); }; @@ -83,10 +86,10 @@ AsciistreamTest::testIllegalNumbers() is << "777777777777"; EXPECT_EQUAL(24u, is.size()); uint64_t l(0); - EXPECT_EXCEPTION(is >> l, IllegalArgumentException, "value is outside of range '777777777777777777777777'"); + EXPECT_EXCEPTION(is >> l, IllegalArgumentException, "value '777777777777777777777777' is outside of range"); EXPECT_EQUAL(24u, is.size()); int64_t li(0); - EXPECT_EXCEPTION(is >> li, IllegalArgumentException, "value is outside of range '777777777777777777777777'"); + EXPECT_EXCEPTION(is >> li, IllegalArgumentException, "value '777777777777777777777777' is outside of range"); EXPECT_EQUAL(24u, is.size()); } { @@ -102,13 +105,13 @@ AsciistreamTest::testIllegalNumbers() asciistream is("7777777777777777777777777777777777777777"); EXPECT_EQUAL(40u, is.size()); float f(0); - EXPECT_EXCEPTION(is >> f, IllegalArgumentException, "float value is outside of range '7777777777777777777777777777777777777777'"); + EXPECT_EXCEPTION(is >> f, IllegalArgumentException, "float value '7777777777777777777777777777777777777777' is outside of range"); EXPECT_EQUAL(40u, is.size()); vespalib::string tmp = is.str(); is << "e" << tmp; EXPECT_EQUAL(81u, is.size()); double d(0); - EXPECT_EXCEPTION(is >> d, IllegalArgumentException, "double value is outside of range '7777777777777777777777777777777777777777e7777777777777777777777777777777777777777'"); + EXPECT_EXCEPTION(is >> d, IllegalArgumentException, "double value '7777777777777777777777777777777777777777e7777777777777777777777777777777777777777' is outside of range"); EXPECT_EQUAL(81u, is.size()); } { @@ -481,6 +484,59 @@ AsciistreamTest::testDouble() { VERIFY_DOUBLE_SERIALIZATION(0.0, "0.0", automatic << forcedot, 1); VERIFY_DOUBLE_SERIALIZATION(0.0, "0.0", automatic << forcedot, 16); VERIFY_DOUBLE_SERIALIZATION(maxInteger, "9007199254740992.0", automatic << forcedot, 16); + + asciistream as; + as.clear(); + as << (3 * std::numeric_limits<double>::min()); + double dv = 0; + as >> dv; + EXPECT_TRUE(dv > 0); + + as.clear(); + as << (3 * std::numeric_limits<double>::denorm_min()); + dv = 0; + as >> dv; + EXPECT_TRUE(dv > 0); + + as.clear(); + as << "1.0e-325"; + dv = 42.0; + as >> dv; + EXPECT_EQUAL(dv, 0.0); + + as.clear(); + as << "1.0e666"; + dv = 42.0; + EXPECT_EXCEPTION(as >> dv, IllegalArgumentException, "double value '1.0e666' is outside of range."); + EXPECT_EQUAL(dv, 42.0); +} + +void +AsciistreamTest::testFloat() { + float f = 0; + asciistream as("-5.490412E-39"); + try { + as >> f; + } catch (std::exception &e) { + EXPECT_EQUAL("should not reach this point", e.what()); + } + EXPECT_EQUAL(f, -5.490412E-39f); + + as.clear(); + as << "0.0001E-50"; + f = 42.0; + try { + as >> f; + } catch (std::exception &e) { + EXPECT_EQUAL("should not reach this point", e.what()); + } + EXPECT_EQUAL(f, 0.0); + + as.clear(); + as << "123.4E50"; + f = 42.0; + EXPECT_EXCEPTION(as >> f, IllegalArgumentException, "float value '123.4E50' is outside of range."); + EXPECT_EQUAL(f, 42.0); } void @@ -547,6 +603,7 @@ AsciistreamTest::Main() testGetLine(); testIllegalNumbers(); testDouble(); + testFloat(); testStateSaver(); TEST_DONE(); } diff --git a/vespalib/src/vespa/vespalib/stllike/asciistream.cpp b/vespalib/src/vespa/vespalib/stllike/asciistream.cpp index 30a963c374c..499171dc6e7 100644 --- a/vespalib/src/vespa/vespalib/stllike/asciistream.cpp +++ b/vespalib/src/vespa/vespalib/stllike/asciistream.cpp @@ -10,6 +10,7 @@ #include <limits> #include <stdexcept> #include <cassert> +#include <math.h> #include <vespa/log/log.h> LOG_SETUP(".vespalib.stllike.asciistream"); @@ -154,7 +155,7 @@ void throwInputError(int e, const char * t, const char * buf) if (e == 0) { throw IllegalArgumentException("Failed decoding a " + string(t) + " from '" + string(buf) + "'.", VESPA_STRLOC); } else if (errno == ERANGE) { - throw IllegalArgumentException(string(t) + " value is outside of range '" + string(buf) + "'.", VESPA_STRLOC); + throw IllegalArgumentException(string(t) + " value '" + string(buf) + "' is outside of range.", VESPA_STRLOC); } else if (errno == EINVAL) { throw IllegalArgumentException("Illegal " + string(t) + " value '" + string(buf) + "'.", VESPA_STRLOC); } else { @@ -172,7 +173,16 @@ int getValue(double & val, const char *buf) char *ebuf; errno = 0; val = locale::c::strtod(buf, &ebuf); - if ((errno != 0) || (buf == ebuf)) { + bool failed = (buf == ebuf); + if (errno != 0) { + if (errno == ERANGE) { + if (val == HUGE_VAL) failed = true; + if (val == -HUGE_VAL) failed = true; + } else { + failed = true; + } + } + if (failed) { throwInputError(errno, "double", buf); } return ebuf - buf; @@ -183,7 +193,16 @@ int getValue(float & val, const char *buf) char *ebuf; errno = 0; val = locale::c::strtof(buf, &ebuf); - if ((errno != 0) || (buf == ebuf)) { + bool failed = (buf == ebuf); + if (errno != 0) { + if (errno == ERANGE) { + if (val == HUGE_VALF) failed = true; + if (val == -HUGE_VALF) failed = true; + } else { + failed = true; + } + } + if (failed) { throwInputError(errno, "float", buf); } return ebuf - buf; |