On Apr 7 13:40, Ken Brown wrote:
$ cat strtod_test.c
#include <stdio.h>
#include <stdlib.h>
#include <fenv.h>
int
main ()
{
/* The following number comes from /usr/share/asymptote/ode.asy. */
const char *str = "121645100408832000.0";
char *ptr;
feenableexcept (FE_INVALID);
strtod (str, &ptr);
/* If there was an exception, the following will not get executed. */
printf ("No exception.\n");
}
$ gcc strtod_test.c
$ ./a
Floating point exception (core dumped)
[The above was on x86. On x86_64 there's simply no output.]
I have no idea what's special about the number 121645100408832000.0, but the
problem goes away if, for example, I replace the leading 1 by 2.
GDB shows that the exception occurs in newlib/libc/stdlib/strtod.c
line 1189, in this statment, which looks rather inconspicious at
first glance:
L = (Long)aadj;
L is of type Long == int32_t, aadj is of type double. The
value of aadj at this time is 2529648000.0 == 0x96c75d80 which
appears to be perfectly valid for a 32 bit int.
However, on 64 bit for example the assembler statement generating the FP
exception is
cvttsd2si %xmm0,%eax
It is documented that this statemnt may raise FE_INVALID or FE_INEXACT
exceptions. The problem is that the generated 32 bit value is a
negative signed int value, while the source operand is positive. So the
conversion is, in fact, invalid.
I applied a fix to newlib's strtod, to always use 64 bit ints in this
place. This fixes the problem and no exception is raised.