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

Martin Storsjo martin at martin.st
Tue Jul 27 17:44:47 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>
---
 dlls/msvcrt/string.c         | 15 ++++++++++++++-
 dlls/msvcrt/wcs.c            | 16 +++++++++++++++-
 dlls/ucrtbase/tests/string.c | 33 +++++++++++++++++++++++++++++++++
 3 files changed, 62 insertions(+), 2 deletions(-)

diff --git a/dlls/msvcrt/string.c b/dlls/msvcrt/string.c
index 27e3284326a..823e1e77b9a 100644
--- a/dlls/msvcrt/string.c
+++ b/dlls/msvcrt/string.c
@@ -1065,7 +1065,20 @@ 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 (isfinite(ret)) {
+        /* Check for cases that aren't out of range for doubles, but that are
+         * for floats. */
+        if (ret > FLT_MAX)
+            *_errno() = ERANGE;
+        else if (ret < -FLT_MAX)
+            *_errno() = ERANGE;
+        else if (ret > 0 && ret < FLT_MIN)
+            *_errno() = ERANGE;
+        else if (ret < 0 && ret > -FLT_MIN)
+            *_errno() = ERANGE;
+    }
+    return ret;
 }
 
 /*********************************************************************
diff --git a/dlls/msvcrt/wcs.c b/dlls/msvcrt/wcs.c
index 615b4f36a33..1baed5d1458 100644
--- a/dlls/msvcrt/wcs.c
+++ b/dlls/msvcrt/wcs.c
@@ -23,6 +23,7 @@
 #include <limits.h>
 #include <locale.h>
 #include <math.h>
+#include <float.h>
 #include <assert.h>
 #include <wchar.h>
 #include <wctype.h>
@@ -798,7 +799,20 @@ 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 (isfinite(ret)) {
+        /* Check for cases that aren't out of range for doubles, but that are
+         * for floats. */
+        if (ret > FLT_MAX)
+            *_errno() = ERANGE;
+        else if (ret < -FLT_MAX)
+            *_errno() = ERANGE;
+        else if (ret > 0 && ret < FLT_MIN)
+            *_errno() = ERANGE;
+        else if (ret < 0 && ret > -FLT_MIN)
+            *_errno() = ERANGE;
+    }
+    return ret;
 }
 
 /*********************************************************************
diff --git a/dlls/ucrtbase/tests/string.c b/dlls/ucrtbase/tests/string.c
index 9b1d21b801c..92626048410 100644
--- a/dlls/ucrtbase/tests/string.c
+++ b/dlls/ucrtbase/tests/string.c
@@ -152,6 +152,38 @@ 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 },
+        { "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 +590,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