IRIX mis-parses "1e 1" as 10.0 and "" instead of 1.0 and "e 1". Because the original parse may differ from the reparse in terms of whether the value overflows, we have to do an errno dance.
* lib/strtod.c (strtod): Reparse number on shorter string if exponent parse was invalid. Reported by Tom G. Christensen. Signed-off-by: Eric Blake <[email protected]> --- >> Building with MIPSpro works but there are testsuite failures: >> $ ./test-strtod >> test-strtod.c:377: assertion failed >> Abort (core dumped) > >Phooey - a regression. This is already a known bug ("1E 2" is >mistakenly treated as 100.0 instead of 1.0 on HP-UX 11.11, IRIX 6.5, >and OSF/1 4.0, per the comments on that line); so our rewrite to call >the native strtod under the hood of rpl_strtod is not working around >this particular bug. This should do it. I've compile-tested it, but without an actual platform exhibiting the failure, there may still be a tweak or two needed. Hmm - the testsuite lacks any tests for "0x1p 1" not consuming the "p 1". I wonder if AIX is buggy in that regards; and if so, the errno dance needs to be extended to 0x handling. I guess I'd better do a followup that enhances the testsuite, yet again. ChangeLog | 7 +++++++ lib/strtod.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 0 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2955f2f..395191a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2010-09-01 Eric Blake <[email protected]> + + strtod: work around IRIX 6.5 bug + * lib/strtod.c (strtod): Reparse number on shorter string if + exponent parse was invalid. + Reported by Tom G. Christensen. + 2010-08-31 Eric Blake <[email protected]> and Jim Meyering <[email protected]> diff --git a/lib/strtod.c b/lib/strtod.c index 64b62ff..944f6cd 100644 --- a/lib/strtod.c +++ b/lib/strtod.c @@ -24,6 +24,7 @@ #include <limits.h> #include <math.h> #include <stdbool.h> +#include <string.h> #include "c-ctype.h" @@ -202,6 +203,7 @@ strtod (const char *nptr, char **endptr) const char *s = nptr; const char *end; char *endbuf; + int saved_errno; /* Eat whitespace. */ while (locale_isspace (*s)) @@ -212,6 +214,7 @@ strtod (const char *nptr, char **endptr) if (*s == '-' || *s == '+') ++s; + saved_errno = errno; num = underlying_strtod (s, &endbuf); end = endbuf; @@ -239,6 +242,35 @@ strtod (const char *nptr, char **endptr) end = p; } } + else + { + /* If "1e 1" was misparsed as 10.0 instead of 1.0, re-do the + underlying strtod on a copy of the original string + truncated to avoid the bug. */ + const char *e = s + 1; + while (e < end && c_tolower (*e) != 'e') + e++; + if (e < end && ! c_isdigit (e[1 + (e[1] == '-' || e[1] == '+')])) + { + char *dup = strdup (s); + errno = saved_errno; + if (!dup) + { + /* Not really our day, is it. Rounding errors are + better than outright failure. */ + num = parse_number (s, 10, 10, 1, 'e', &endbuf); + } + else + { + dup[e - s] = '\0'; + num = underlying_strtod (s, &endbuf); + saved_errno = errno; + free (dup); + errno = saved_errno; + } + end = e; + } + } s = end; } -- 1.7.2.2
