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@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Erich E. Hoover 2019-12-22 07:33:38 -07:00 committed by Alexandre Julliard
parent 1b5f14d732
commit 27b9a420ea
4 changed files with 14 additions and 21 deletions

View File

@ -49,6 +49,8 @@
#define MSVCRT_I64_MIN (-MSVCRT_I64_MAX-1) #define MSVCRT_I64_MIN (-MSVCRT_I64_MAX-1)
#define MSVCRT_UI64_MAX (((unsigned __int64)0xffffffff << 32) | 0xffffffff) #define MSVCRT_UI64_MAX (((unsigned __int64)0xffffffff << 32) | 0xffffffff)
#define MSVCRT_MB_LEN_MAX 5 #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_MAX_10_EXP 308
#define MSVCRT_DBL_MIN_10_EXP (-307) #define MSVCRT_DBL_MIN_10_EXP (-307)
#ifdef _WIN64 #ifdef _WIN64

View File

@ -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) 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; int exp1=0, exp2=0, exp3=0, sign=1;
MSVCRT_pthreadlocinfo locinfo; MSVCRT_pthreadlocinfo locinfo;
unsigned __int64 d=0, hlp; unsigned __int64 d=0, hlp;
BOOL found_digit = FALSE;
unsigned fpcontrol; unsigned fpcontrol;
const char *p; const char *p;
double ret; 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__EM_OVERFLOW|MSVCRT__EM_UNDERFLOW|MSVCRT__EM_INEXACT|MSVCRT__PC_64,
MSVCRT__MCW_EM | MSVCRT__MCW_PC ); 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 */ /* take the number without exponent and convert it into a double */
ret = MSVCRT_mul_pow10(d, exp1); ret = MSVCRT_mul_pow10(d, exp1);
/* shift the number to the representation where the first non-zero digit is in the ones place */ /* 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)round(log10(ret)) : 0);
exp2 = (ret != 0.0 ? (int)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) */ /* incorporate an additional shift to deal with floating point denormal values (if necessary) */
if(exp3-exp2 < MSVCRT_DBL_MIN_10_EXP) if(exp3-exp2 < MSVCRT_DBL_MIN_10_EXP)
exp2 += exp3-exp2-MSVCRT_DBL_MIN_10_EXP; exp2 += exp3-exp2-MSVCRT_DBL_MIN_10_EXP;

View File

@ -1999,8 +1999,11 @@ static void test__strtod(void)
strtod("-1d309", NULL); strtod("-1d309", NULL);
ok(errno == ERANGE, "errno = %x\n", errno); 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); 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) static void test_mbstowcs(void)

View File

@ -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, double CDECL MSVCRT__wcstod_l(const MSVCRT_wchar_t* str, MSVCRT_wchar_t** end,
MSVCRT__locale_t locale) MSVCRT__locale_t locale)
{ {
BOOL found_digit = FALSE, overflow, underflow;
int exp1=0, exp2=0, exp3=0, sign=1; int exp1=0, exp2=0, exp3=0, sign=1;
MSVCRT_pthreadlocinfo locinfo; MSVCRT_pthreadlocinfo locinfo;
unsigned __int64 d=0, hlp; unsigned __int64 d=0, hlp;
BOOL found_digit = FALSE;
unsigned fpcontrol; unsigned fpcontrol;
const MSVCRT_wchar_t *p; const MSVCRT_wchar_t *p;
double ret; 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__EM_OVERFLOW|MSVCRT__EM_UNDERFLOW|MSVCRT__EM_INEXACT|MSVCRT__PC_64,
MSVCRT__MCW_EM | MSVCRT__MCW_PC ); 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 */ /* take the number without exponent and convert it into a double */
ret = MSVCRT_mul_pow10(d, exp1); ret = MSVCRT_mul_pow10(d, exp1);
/* shift the number to the representation where the first non-zero digit is in the ones place */ /* 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)round(log10(ret)) : 0);
exp2 = (ret != 0.0 ? (int)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) */ /* incorporate an additional shift to deal with floating point denormal values (if necessary) */
if(exp3-exp2 < MSVCRT_DBL_MIN_10_EXP) if(exp3-exp2 < MSVCRT_DBL_MIN_10_EXP)
exp2 += exp3-exp2-MSVCRT_DBL_MIN_10_EXP; exp2 += exp3-exp2-MSVCRT_DBL_MIN_10_EXP;