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@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();