On Mar 7 11:14, Christopher Faylor wrote:
----- Forwarded message from "Charles L. Werner" -----
#include <stdio.h>
main()
{
double a;
while(1){
printf("input: ");
scanf("%le",&a);
printf("a: %le\n",a);
}
}
input: -.11e+00
a: 1.100000e-01 !akkk
input: -1.1e+00
a: 1.100000e+00 !akkk
Below is a fix for the above problem. The cause is two-fold:
In __svfscanf_r, the expression "-1.1e+00" is copied over to buf, the buffer
used in a later call to strtod. The problem here is that all leading zeros
in the exponent are skipped, not copied. The result here is that the
expression given to _strtod_r has an invalid exponent:
"-1.1e+"
this would usually still give the correct result, but now the second bug
hits the ground. As soon as _strtod_r findes the exponent marker 'e' or
'E', the s00 variable which so far pointed to the beginning of the incoming
string, is changed and set to the address of the 'e' or 'E' character.
Unfortunately, there's no valid exponent, so the 'e' or 'E' character is
the first character which doesn't belong to the number and has to be
returned in *se. That's done by setting s to s00. Given that s00 has
been changed accordingly, that's correct.
But now take a look into the return statement of _strtod_r:
return (sign && (s != s00)) ? -rv.d : rv.d;
Bingo.
The below patch only fixes _strtod_r, since that's sufficient to solve
the problem.
However, a full solution also changes __svfscanf_r so that a 0 exponent
is correctly copied to buf. Right now, I don't see how to do this
elegantly. In theory it requires another value in the `flags' variable
AFAICS.
Corinna
* libc/stdlib/strtod.c (_strtod_r): Never change s00.
Index: libc/stdlib/strtod.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdlib/strtod.c,v
retrieving revision 1.5
diff -u -p -r1.5 strtod.c
--- libc/stdlib/strtod.c 6 Jan 2005 23:31:56 -0000 1.5
+++ libc/stdlib/strtod.c 31 Mar 2005 17:56:33 -0000
@@ -111,7 +111,7 @@ _DEFUN (_strtod_r, (ptr, s00, se),
int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign, e1, esign, i, j,
k, nd, nd0, nf, nz, nz0, sign;
long e;
- _CONST char *s, *s0, *s1;
+ _CONST char *s, *s0, *s1, *s2;
double aadj, aadj1, adj;
long L;
unsigned long z;
@@ -222,7 +222,7 @@ dig_done:
s = s00;
goto ret;
}
- s00 = s;
+ s2 = s;
esign = 0;
switch (c = *++s)
{
@@ -253,7 +253,7 @@ dig_done:
e = 0;
}
else
- s = s00;
+ s = s2;
}
if (!nd)
{