[RFA] strtod: Fix sign bug if exponent is invalid (was Re: [cw@gamma-rs.ch: error in scanf reading %le format and 00 exponent])
Jeff Johnston
jjohnstn@redhat.com
Thu Mar 31 20:59:00 GMT 2005
Corinna Vinschen wrote:
> 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.
>
Thanks for catching this Corinna. Please check it in. There is no need to post
a fix in vfscanf. The reason is that if the exponent is 0, then strtod or
strtold stopping processing at that point is still correct. vscanf has already
preparsed and verified the input string; it does use the endptr so it doesn't
matter that it gets set to the unprocessed exponent.
-- Jeff J.
>
> 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)
> {
>
More information about the Newlib
mailing list