sal/qa/rtl/math/test-rtl-math.cxx |    6 ++++++
 sal/rtl/math.cxx                  |   33 +++++++++++++++++++++------------
 2 files changed, 27 insertions(+), 12 deletions(-)

New commits:
commit a3aaa11db039675252fe9d5bc4a9d43be34940e8
Author:     Mike Kaganski <[email protected]>
AuthorDate: Wed Sep 17 13:15:15 2025 +0500
Commit:     Mike Kaganski <[email protected]>
CommitDate: Wed Sep 17 15:15:27 2025 +0200

    tdf#168423: Allow subnormals from strtod
    
    dtoa sets ERANGE with subnormals. We need to support these, so check
    for infinity and zero explicitly, and allow other results. NaNs can't
    appear here.
    
    Change-Id: I006a42ebff03b07d219b423c13bf8230348e1def
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/191071
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <[email protected]>

diff --git a/sal/qa/rtl/math/test-rtl-math.cxx 
b/sal/qa/rtl/math/test-rtl-math.cxx
index 53b6827c818b..22714fdd4592 100644
--- a/sal/qa/rtl/math/test-rtl-math.cxx
+++ b/sal/qa/rtl/math/test-rtl-math.cxx
@@ -234,6 +234,12 @@ public:
         CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
         CPPUNIT_ASSERT_EQUAL(sal_Int32(23), end);
         CPPUNIT_ASSERT_EQUAL(fValAfter, res);
+
+        // Minimal subnormal value, as documented for Basic
+        res = rtl::math::stringToDouble("4.94065645841247E-324", '.', ',', 
&status, &end);
+        CPPUNIT_ASSERT_EQUAL(rtl_math_ConversionStatus_Ok, status);
+        CPPUNIT_ASSERT_EQUAL(sal_Int32(21), end);
+        CPPUNIT_ASSERT_EQUAL(0x1p-1074, res);
     }
 
     void test_stringToDouble_bad() {
diff --git a/sal/rtl/math.cxx b/sal/rtl/math.cxx
index 26b539a9cc8c..dbeef855e9c5 100644
--- a/sal/rtl/math.cxx
+++ b/sal/rtl/math.cxx
@@ -372,23 +372,32 @@ double stringToDouble(CharT const* pBegin, CharT const* 
pEnd, CharT cDecSeparato
             fVal = strtod_nolocale(buf, &pCharParseEnd);
             if (errno == ERANGE)
             {
-                // Check for the dreaded rounded to 15 digits max value
-                // 1.79769313486232e+308 for 1.7976931348623157e+308 we wrote
-                // everywhere, accept with or without plus sign in exponent.
-                const char* b = buf;
-                if (b[0] == '-')
-                    ++b;
-                if (((pCharParseEnd - b == 21) || (pCharParseEnd - b == 20))
-                    && !strncmp(b, "1.79769313486232", 16) && (b[16] == 'e' || 
b[16] == 'E')
-                    && (((pCharParseEnd - b == 21) && !strncmp(b + 17, "+308", 
4))
-                        || ((pCharParseEnd - b == 20) && !strncmp(b + 17, 
"308", 3))))
+                // This happens with overflow and underflow (including 
subnormals!)
+                if (std::isinf(fVal))
                 {
-                    fVal = (buf < b) ? -DBL_MAX : DBL_MAX;
+                    // Check for the dreaded rounded to 15 digits max value
+                    // 1.79769313486232e+308 for 1.7976931348623157e+308 we 
wrote
+                    // everywhere, accept with or without plus sign in 
exponent.
+                    const char* b = buf;
+                    if (b[0] == '-')
+                        ++b;
+                    if (((pCharParseEnd - b == 21) || (pCharParseEnd - b == 
20))
+                        && !strncmp(b, "1.79769313486232", 16) && (b[16] == 
'e' || b[16] == 'E')
+                        && (((pCharParseEnd - b == 21) && !strncmp(b + 17, 
"+308", 4))
+                            || ((pCharParseEnd - b == 20) && !strncmp(b + 17, 
"308", 3))))
+                    {
+                        fVal = (buf < b) ? -DBL_MAX : DBL_MAX;
+                    }
+                    else
+                    {
+                        eStatus = rtl_math_ConversionStatus_OutOfRange;
+                    }
                 }
-                else
+                else if (fVal == 0)
                 {
                     eStatus = rtl_math_ConversionStatus_OutOfRange;
                 }
+                // else it's subnormal: allow it
             }
             p = bufmap[pCharParseEnd - buf];
             bSign = false;

Reply via email to