Erich E. Hoover : msvcrt: Fix [str|wcs]tod result being compared against FLT_MAX.

Alexandre Julliard julliard at winehq.org
Mon Dec 23 17:42:12 CST 2019


Module: wine
Branch: master
Commit: 27b9a420ea87fd85c0c933b7db77a9efb22f94cf
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=27b9a420ea87fd85c0c933b7db77a9efb22f94cf

Author: Erich E. Hoover <erich.e.hoover at gmail.com>
Date:   Sun Dec 22 07:33:38 2019 -0700

msvcrt: Fix [str|wcs]tod result being compared against FLT_MAX.

Also a more straightforward way of fixing the tests on i386 Linux.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=48324
Signed-off-by: Erich E. Hoover <erich.e.hoover at gmail.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/msvcrt/msvcrt.h       |  2 ++
 dlls/msvcrt/string.c       | 14 ++++----------
 dlls/msvcrt/tests/string.c |  5 ++++-
 dlls/msvcrt/wcs.c          | 14 ++++----------
 4 files changed, 14 insertions(+), 21 deletions(-)

diff --git a/dlls/msvcrt/msvcrt.h b/dlls/msvcrt/msvcrt.h
index 2ac7977182..c333ddc62f 100644
--- a/dlls/msvcrt/msvcrt.h
+++ b/dlls/msvcrt/msvcrt.h
@@ -49,6 +49,8 @@
 #define MSVCRT_I64_MIN    (-MSVCRT_I64_MAX-1)
 #define MSVCRT_UI64_MAX   (((unsigned __int64)0xffffffff << 32) | 0xffffffff)
 #define MSVCRT_MB_LEN_MAX 5
+#define MSVCRT_FLT_MAX_10_EXP 38
+#define MSVCRT_FLT_MIN_10_EXP (-37)
 #define MSVCRT_DBL_MAX_10_EXP 308
 #define MSVCRT_DBL_MIN_10_EXP (-307)
 #ifdef _WIN64
diff --git a/dlls/msvcrt/string.c b/dlls/msvcrt/string.c
index 03d80a5dec..ae1ec4c796 100644
--- a/dlls/msvcrt/string.c
+++ b/dlls/msvcrt/string.c
@@ -571,10 +571,10 @@ static double MSVCRT_mul_pow10(double x, int exp)
 
 static double strtod_helper(const char *str, char **end, MSVCRT__locale_t locale, int *err)
 {
-    BOOL found_digit = FALSE, overflow, underflow;
     int exp1=0, exp2=0, exp3=0, sign=1;
     MSVCRT_pthreadlocinfo locinfo;
     unsigned __int64 d=0, hlp;
+    BOOL found_digit = FALSE;
     unsigned fpcontrol;
     const char *p;
     double ret;
@@ -694,18 +694,12 @@ static double strtod_helper(const char *str, char **end, MSVCRT__locale_t locale
                |MSVCRT__EM_OVERFLOW|MSVCRT__EM_UNDERFLOW|MSVCRT__EM_INEXACT|MSVCRT__PC_64,
                MSVCRT__MCW_EM | MSVCRT__MCW_PC );
 
-    /* if we have a simple case then just calculate the result directly */
-    overflow = (exp3-exp1 > MSVCRT_DBL_MAX_10_EXP);
-    underflow = (exp3-exp1 < MSVCRT_DBL_MIN_10_EXP);
-    if(!overflow && !underflow) {
-        exp1 += exp3;
-        exp3 = 0;
-    }
     /* take the number without exponent and convert it into a double */
     ret = MSVCRT_mul_pow10(d, exp1);
     /* shift the number to the representation where the first non-zero digit is in the ones place */
-    if(overflow || underflow)
-        exp2 = (ret != 0.0 ? (int)log10(ret) : 0);
+    exp2 = (ret != 0.0 ? (int)round(log10(ret)) : 0);
+    if (exp3-exp2 >= MSVCRT_FLT_MIN_10_EXP && exp3-exp2 <= MSVCRT_FLT_MAX_10_EXP)
+        exp2 = 0; /* only bother to take this extra step with very small or very large numbers */
     /* incorporate an additional shift to deal with floating point denormal values (if necessary) */
     if(exp3-exp2 < MSVCRT_DBL_MIN_10_EXP)
         exp2 += exp3-exp2-MSVCRT_DBL_MIN_10_EXP;
diff --git a/dlls/msvcrt/tests/string.c b/dlls/msvcrt/tests/string.c
index beca47f1b6..fa2c8d6196 100644
--- a/dlls/msvcrt/tests/string.c
+++ b/dlls/msvcrt/tests/string.c
@@ -1999,8 +1999,11 @@ static void test__strtod(void)
     strtod("-1d309", NULL);
     ok(errno == ERANGE, "errno = %x\n", errno);
 
+    d = strtod("3.4028234663852887e38", NULL);
+    ok(d <= FLT_MAX, "d = %e\n", d);
+
     d = strtod("1.7976931348623158e+308", NULL);
-    ok(almost_equal(d, DBL_MAX), "d = %lf (%lf)\n", d, DBL_MAX);
+    ok(d == DBL_MAX, "d = %le\n", d);
 }
 
 static void test_mbstowcs(void)
diff --git a/dlls/msvcrt/wcs.c b/dlls/msvcrt/wcs.c
index 855e3d8593..6d03997d9e 100644
--- a/dlls/msvcrt/wcs.c
+++ b/dlls/msvcrt/wcs.c
@@ -398,10 +398,10 @@ static double MSVCRT_mul_pow10(double x, int exp)
 double CDECL MSVCRT__wcstod_l(const MSVCRT_wchar_t* str, MSVCRT_wchar_t** end,
         MSVCRT__locale_t locale)
 {
-    BOOL found_digit = FALSE, overflow, underflow;
     int exp1=0, exp2=0, exp3=0, sign=1;
     MSVCRT_pthreadlocinfo locinfo;
     unsigned __int64 d=0, hlp;
+    BOOL found_digit = FALSE;
     unsigned fpcontrol;
     const MSVCRT_wchar_t *p;
     double ret;
@@ -490,18 +490,12 @@ double CDECL MSVCRT__wcstod_l(const MSVCRT_wchar_t* str, MSVCRT_wchar_t** end,
                |MSVCRT__EM_OVERFLOW|MSVCRT__EM_UNDERFLOW|MSVCRT__EM_INEXACT|MSVCRT__PC_64,
                MSVCRT__MCW_EM | MSVCRT__MCW_PC );
 
-    /* if we have a simple case then just calculate the result directly */
-    overflow = (exp3-exp1 > MSVCRT_DBL_MAX_10_EXP);
-    underflow = (exp3-exp1 < MSVCRT_DBL_MIN_10_EXP);
-    if(!overflow && !underflow) {
-        exp1 += exp3;
-        exp3 = 0;
-    }
     /* take the number without exponent and convert it into a double */
     ret = MSVCRT_mul_pow10(d, exp1);
     /* shift the number to the representation where the first non-zero digit is in the ones place */
-    if(overflow || underflow)
-        exp2 = (ret != 0.0 ? (int)log10(ret) : 0);
+    exp2 = (ret != 0.0 ? (int)round(log10(ret)) : 0);
+    if (exp3-exp2 >= MSVCRT_FLT_MIN_10_EXP && exp3-exp2 <= MSVCRT_FLT_MAX_10_EXP)
+        exp2 = 0; /* only bother to take this extra step with very small or very large numbers */
     /* incorporate an additional shift to deal with floating point denormal values (if necessary) */
     if(exp3-exp2 < MSVCRT_DBL_MIN_10_EXP)
         exp2 += exp3-exp2-MSVCRT_DBL_MIN_10_EXP;




More information about the wine-cvs mailing list