This is the mail archive of the newlib@sources.redhat.com mailing list for the newlib project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFA] strtod: Fix sign bug if exponent is invalid (was Re: [cw@gamma-rs.ch: error in scanf reading %le format and 00 exponent])


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)
     {

-- 
Corinna Vinschen
Cygwin Project Co-Leader
Red Hat, Inc.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]