From 27b9a420ea87fd85c0c933b7db77a9efb22f94cf Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" Date: Sun, 22 Dec 2019 07:33:38 -0700 Subject: [PATCH] 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 Signed-off-by: Alexandre Julliard --- 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 2ac7977182f..c333ddc62f8 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 03d80a5dec6..ae1ec4c7965 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 beca47f1b61..fa2c8d61969 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 855e3d8593a..6d03997d9e9 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;