[llvm-bugs] [Bug 50916] The libc++ library sstream cannot properly process some limit values.
via llvm-bugs
llvm-bugs at lists.llvm.org
Mon Jun 28 02:34:48 PDT 2021
https://bugs.llvm.org/show_bug.cgi?id=50916
Dimitry Andric <dimitry at andric.com> changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |dimitry at andric.com
Status|NEW |RESOLVED
Resolution|--- |INVALID
--- Comment #1 from Dimitry Andric <dimitry at andric.com> ---
This seems more like a bug in libstdc++, as the string you posted is too small
to be representable in a double.
I.e, on most platforms std::numeric_limits<double>::min() is exactly
0x1.0000000000000000p-1022 (in hex notation), and 2.2250738585072014e-308 in
decimal notation. (Note that the decimal notation is only an approximation, but
16 digits precision is usually enough to be unambiguous.)
So as written, "2.22507e-308" is actually a smaller quantity, and indeed
results in ERANGE if you attempt to convert it with strtod(). For example:
#include <cerrno>
#include <cstdio>
#include <cstdlib>
int main(void)
{
const char str[] = "-2.22507e-308";
char* endptr;
double d = strtod(str, &endptr);
printf("d=%20.16A (%20.16e), endptr-str=%zd, errno=%d\n", d, d, endptr - str,
errno);
return 0;
}
On Linux (x86_64) this shows:
d=-0X1.FFFFC5D02B3A0000P-1023 (-2.2250699999999998e-308), endptr-str=13,
errno=34
On FreeBSD (x86_64) this shows:
d=-0X0.FFFFE2E8159D0000P-1022 (-2.2250699999999998e-308), endptr-str=13,
errno=34
Note that the conversion is not identical, and while *some* value is returned,
the endptr is not at the end of the input string, and errno is ERANGE in both
cases, so the strtod() caller should conclude that the conversion failed.
However, the corresponding libstdc++ code (see
https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libstdc%2B%2B-v3/config/locale/generic/c_locale.cc;h=a6676a7cf510a37dbaf81c6a1c5232c7af9f5008;hb=HEAD#l139
) looks like:
139 __v = strtod(__s, &__sanity);
140
141 // _GLIBCXX_RESOLVE_LIB_DEFECTS
142 // 23. Num_get overflow result.
143 if (__sanity == __s || *__sanity != '\0')
144 {
145 __v = 0.0;
146 __err = ios_base::failbit;
147 }
148 else if (
149 #if __DBL_HAS_INFINITY__
150 __v == numeric_limits<double>::infinity()
151 || __v == -numeric_limits<double>::infinity())
152 #else
153 (__v > 1.0 || __v < -1.0) && errno == ERANGE)
154 #endif
155 {
156 if (__v > 0.0)
157 __v = numeric_limits<double>::max();
158 else
159 __v = -numeric_limits<double>::max();
160 __err = ios_base::failbit;
161 }
You can see that it only checks for ERANGE in case infinity is returned (for
some systems), or when the returned value is larger than 1, in absolute sense.
So this will not detect any underflows.
Note that libstdc++ *may* do this on purpose, for reasons which I am not aware
of. (Maybe to avoid breaking older code?)
The corresponding libc++ code looks like (where __do_strtod is a template
wrapper to call the right strtod() variant):
841 typename remove_reference<decltype(errno)>::type __save_errno =
errno;
842 errno = 0;
843 char *__p2;
844 _Tp __ld = __do_strtod<_Tp>(__a, &__p2);
845 typename remove_reference<decltype(errno)>::type
__current_errno = errno;
846 if (__current_errno == 0)
847 errno = __save_errno;
848 if (__p2 != __a_end)
849 {
850 __err = ios_base::failbit;
851 return 0;
852 }
853 else if (__current_errno == ERANGE)
854 __err = ios_base::failbit;
855 return __ld;
Here, you can see that failbit is set, either if strtod() does not reach the
end of the input string, or if errno is ERANGE. That is, it will detect both
overflows and underflows.
--
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20210628/8a93574e/attachment.html>
More information about the llvm-bugs
mailing list