[PATCH v2] msvcrt: Fix strtof() error reporting for values out of float range

Martin Storsjo martin at martin.st
Wed Jul 28 09:43:19 CDT 2021


If the values weren't out of range for the internal strtod() call,
we still must mark them as out of range when returning as float.

Signed-off-by: Martin Storsjo <martin at martin.st>
---
Mimicing UCRT exactly for float denormals too.
---
 dlls/msvcrt/string.c         |  8 +++++++-
 dlls/msvcrt/wcs.c            |  8 +++++++-
 dlls/ucrtbase/tests/string.c | 37 ++++++++++++++++++++++++++++++++++++
 3 files changed, 51 insertions(+), 2 deletions(-)

diff --git a/dlls/msvcrt/string.c b/dlls/msvcrt/string.c
index 27e3284326a..4d09405094d 100644
--- a/dlls/msvcrt/string.c
+++ b/dlls/msvcrt/string.c
@@ -1065,7 +1065,13 @@ double CDECL strtod( const char *str, char **end )
  */
 float CDECL _strtof_l( const char *str, char **end, _locale_t locale )
 {
-    return _strtod_l(str, end, locale);
+    double ret = _strtod_l(str, end, locale);
+    if (ret && isfinite(ret)) {
+        float f = ret;
+        if (!f || !isfinite(f))
+            *_errno() = ERANGE;
+    }
+    return ret;
 }
 
 /*********************************************************************
diff --git a/dlls/msvcrt/wcs.c b/dlls/msvcrt/wcs.c
index 615b4f36a33..aeab5527db4 100644
--- a/dlls/msvcrt/wcs.c
+++ b/dlls/msvcrt/wcs.c
@@ -798,7 +798,13 @@ double CDECL _wtof_l(const wchar_t *str, _locale_t locale)
  */
 float CDECL _wcstof_l( const wchar_t *str, wchar_t **end, _locale_t locale )
 {
-    return _wcstod_l(str, end, locale);
+    double ret = _wcstod_l(str, end, locale);
+    if (ret && isfinite(ret)) {
+        float f = ret;
+        if (!f || !isfinite(f))
+            *_errno() = ERANGE;
+    }
+    return ret;
 }
 
 /*********************************************************************
diff --git a/dlls/ucrtbase/tests/string.c b/dlls/ucrtbase/tests/string.c
index 9b1d21b801c..734dd68db76 100644
--- a/dlls/ucrtbase/tests/string.c
+++ b/dlls/ucrtbase/tests/string.c
@@ -152,6 +152,42 @@ static void test_strtod(void)
     test_strtod_str_errno("2.47e-324", 0, 9, ERANGE);
 }
 
+static void test_strtof(void)
+{
+    static const struct {
+        const char *str;
+        int len;
+        float ret;
+        int err;
+    } tests[] = {
+        { "12.1", 4, 12.1f },
+        { "-13.721", 7, -13.721f },
+        { "1.e40", 5, INFINITY, ERANGE },
+        { "-1.e40", 6, -INFINITY, ERANGE },
+        { "0.0", 3, 0.0f },
+        { "-0.0", 4, 0.0f },
+        { "1.4e-45", 7, 1.4e-45f },
+        { "-1.4e-45", 8, -1.4e-45f },
+        { "1.e-60", 6, 0, ERANGE },
+        { "-1.e-60", 7, 0, ERANGE },
+    };
+
+    char *end;
+    float f;
+    int i;
+
+    for (i=0; i<ARRAY_SIZE(tests); i++)
+    {
+        errno = 0xdeadbeef;
+        f = strtof(tests[i].str, &end);
+        ok(f == tests[i].ret, "%d) f = %.16e\n", i, f);
+        ok(end == tests[i].str + tests[i].len, "%d) len = %d\n",
+                i, (int)(end - tests[i].str));
+        ok(errno == tests[i].err || (!tests[i].err && errno == 0xdeadbeef),
+                "%d) errno = %d\n", i, errno);
+    }
+}
+
 static void test__memicmp(void)
 {
     static const char *s1 = "abc";
@@ -558,6 +594,7 @@ START_TEST(string)
             "Invalid parameter handler was already set\n");
 
     test_strtod();
+    test_strtof();
     test__memicmp();
     test__memicmp_l();
     test___strncnt();
-- 
2.25.1




More information about the wine-devel mailing list