From edf38838fe0e409455ad2fe03bedaf06571d95bb Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Tue, 23 Jul 2024 12:40:33 +0200 Subject: [PATCH] strtof: Revisit underflow behaviour. * doc/posix-functions/strtof.texi: Mention the macOS bug. Mention the mingw overflow bug. Mention the underflow bugs on Cygwin 2.9 and mingw. Mention that gradual underflow does not count as an error on Cygwin 2.9, mingw, MSVC. * m4/strtof.m4 (gl_FUNC_STRTOF): Test against the mingw overflow bug. * tests/test-strtof.h (test_function): Add a gradual underflow test. Check the sign in case of flush-to-zero underflow. --- ChangeLog | 11 +++++++++ doc/posix-functions/strtof.texi | 22 +++++++++++++++++- m4/strtof.m4 | 15 +++++++++++-- tests/test-strtof.h | 40 +++++++++++++++++++++++++++------ 4 files changed, 78 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index f1e93da002..3da7b01049 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2024-07-23 Bruno Haible + + strtof: Revisit underflow behaviour. + * doc/posix-functions/strtof.texi: Mention the macOS bug. Mention the + mingw overflow bug. Mention the underflow bugs on Cygwin 2.9 and mingw. + Mention that gradual underflow does not count as an error on Cygwin 2.9, + mingw, MSVC. + * m4/strtof.m4 (gl_FUNC_STRTOF): Test against the mingw overflow bug. + * tests/test-strtof.h (test_function): Add a gradual underflow test. + Check the sign in case of flush-to-zero underflow. + 2024-07-23 Bruno Haible strtof, strtod, strtold: Fix underflow behaviour of system function. diff --git a/doc/posix-functions/strtof.texi b/doc/posix-functions/strtof.texi index b7bf64e934..cffe033cf0 100644 --- a/doc/posix-functions/strtof.texi +++ b/doc/posix-functions/strtof.texi @@ -19,7 +19,22 @@ glibc 2.4, Mac OS X 10.5, FreeBSD 6.2. @item This function fails to parse @samp{NaN()} on some platforms: -glibc-2.5, FreeBSD 6.2. +glibc 2.5, FreeBSD 6.2. + +@item +This function misparses @samp{nan(} on some platforms: +macOS 10.6.6. + +@item +This function fails to set @code{errno} upon overflow on some platforms: +mingw 5.0. + +@item +@c The term "underflow", as defined by ISO C23 § 7.12.1.(6), includes both +@c "gradual underflow" (result is a denormalized number) and "flush-to-zero +@c underflow" (result is zero). +This function fails to set @code{errno} upon underflow on some platforms: +Cygwin 2.9, mingw 5.0. @end itemize Portability problems not fixed by Gnulib: @@ -39,6 +54,11 @@ This function fails to correctly parse very long strings on some platforms: Mac OS X 10.5, FreeBSD 6.2, NetBSD 5.0, Cygwin, mingw, MSVC 14. +@item +This function fails to set @code{errno} upon gradual underflow (resulting +in a denormalized number) on some platforms: +MSVC 14. + @item The replacement function does not always return correctly rounded results. @end itemize diff --git a/m4/strtof.m4 b/m4/strtof.m4 index e37310ebde..71516f1bf6 100644 --- a/m4/strtof.m4 +++ b/m4/strtof.m4 @@ -1,5 +1,5 @@ # strtof.m4 -# serial 3 +# serial 4 dnl Copyright (C) 2002-2003, 2006-2024 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -83,6 +83,17 @@ numeric_equal (float x, float y) if (value != HUGE_VAL || term != (string + 3) || errno) result |= 8; } + { + /* In mingw 5.0 without __USE_MINGW_ANSI_STDIO and __USE_MINGW_STRTOX, + strtof does not set errno upon overflow. */ + const char *string = "1e50"; + char *term; + float value; + errno = 0; + value = strtof (string, &term); + if (value != HUGE_VAL || term != (string + 4) || errno != ERANGE) + result |= 8; + } { /* glibc 2.7 and cygwin 1.5.24 misparse "nan()". */ const char *string = "nan()"; @@ -92,7 +103,7 @@ numeric_equal (float x, float y) result |= 16; } { - /* darwin 10.6.1 misparses "nan(". */ + /* Darwin 10.6.1 (macOS 10.6.6) misparses "nan(". */ const char *string = "nan("; char *term; float value = strtof (string, &term); diff --git a/tests/test-strtof.h b/tests/test-strtof.h index 1a7588f608..2ac6b898da 100644 --- a/tests/test-strtof.h +++ b/tests/test-strtof.h @@ -481,7 +481,7 @@ test_function (float (*my_strtof) (const char *, char **)) ASSERT (errno == 0); } - /* Overflow/underflow. */ + /* Overflow. */ { const char input[] = "1E1000000"; char *ptr; @@ -502,6 +502,34 @@ test_function (float (*my_strtof) (const char *, char **)) ASSERT (ptr == input + 10); ASSERT (errno == ERANGE); } + + /* Gradual underflow, resulting in a denormalized number. */ + { + const char input[] = "1e-40"; + char *ptr; + float result; + errno = 0; + result = my_strtof (input, &ptr); + ASSERT (0.0f < result && result <= FLT_MIN); + ASSERT (ptr == input + 5); +#if !defined _MSC_VER + ASSERT (errno == ERANGE); +#endif + } + { + const char input[] = "-1e-40"; + char *ptr; + float result; + errno = 0; + result = my_strtof (input, &ptr); + ASSERT (-FLT_MIN <= result && result < 0.0f); + ASSERT (ptr == input + 6); +#if !defined _MSC_VER + ASSERT (errno == ERANGE); +#endif + } + + /* Flush-to-zero underflow. */ { const char input[] = "1E-100000"; char *ptr; @@ -520,16 +548,14 @@ test_function (float (*my_strtof) (const char *, char **)) errno = 0; result = my_strtof (input, &ptr); ASSERT (-FLT_MIN <= result && result <= 0.0f); -#if 0 - /* FIXME - this is glibc bug 5995; POSIX allows returning positive - 0 on negative underflow, even though quality of implementation - demands preserving the sign. Disable this test until fixed - glibc is more prevalent. */ + /* Negative underflow. Expect a negative sign, although POSIX allows +0.0f. + See also . */ ASSERT (!!signbit (result) == !!signbit (minus_zerof)); /* glibc-2.3.6, mingw */ -#endif ASSERT (ptr == input + 10); ASSERT (errno == ERANGE); } + + /* Space before the exponent. */ { const char input[] = "1E 1000000"; char *ptr; -- 2.39.5