bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] strtod: work around IRIX 6.5 bug


From: Eric Blake
Subject: [PATCH] strtod: work around IRIX 6.5 bug
Date: Wed, 8 Sep 2010 11:29:21 -0600

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.
* tests/test-strtod.c (main): Add check for "0x1p 2".
Reported by Tom G. Christensen.

Signed-off-by: Eric Blake <address@hidden>
---

> I applied this on top of a fresh gnulib checkout and unfortunately the
> test still fails in the same place.

Ah, because I had a one-line typo:

>> +                  dup[e - s] = '\0';
>> +                  num = underlying_strtod (s, &endbuf);

Should be: num = underlying_strtod (dup, &endbuf);

At any rate, I've now enhanced the testsuite, and verified that strtod
now passes on IRIX 5.3.

 ChangeLog           |    6 ++++++
 lib/strtod.c        |   32 ++++++++++++++++++++++++++++++++
 tests/test-strtod.c |   30 ++++++++++++++++++++++++++++++
 3 files changed, 68 insertions(+), 0 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index d880808..9fb8803 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 2010-09-08  Eric Blake  <address@hidden>

+       strtod: work around IRIX 6.5 bug
+       * lib/strtod.c (strtod): Reparse number on shorter string if
+       exponent parse was invalid.
+       * tests/test-strtod.c (main): Add check for "0x1p 2".
+       Reported by Tom G. Christensen.
+
        getopt: optimize previous patch
        * m4/getopt.m4 (gl_GETOPT_CHECK_HEADERS): Correctly check for
        empty variable.  Speed up awk script.
diff --git a/lib/strtod.c b/lib/strtod.c
index 64b62ff..060dffa 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 (dup, &endbuf);
+                  saved_errno = errno;
+                  free (dup);
+                  errno = saved_errno;
+                }
+              end = e;
+            }
+        }

       s = end;
     }
diff --git a/tests/test-strtod.c b/tests/test-strtod.c
index 694e15d..e1d04af 100644
--- a/tests/test-strtod.c
+++ b/tests/test-strtod.c
@@ -558,6 +558,26 @@ main (void)
     ASSERT (ptr == input + 10);
     ASSERT (errno == ERANGE);
   }
+  {
+    const char input[] = "1E 1000000";
+    char *ptr;
+    double result;
+    errno = 0;
+    result = strtod (input, &ptr);
+    ASSERT (result == 1.0);             /* HP-UX 11.11, IRIX 6.5, OSF/1 4.0 */
+    ASSERT (ptr == input + 1);          /* HP-UX 11.11, IRIX 6.5 */
+    ASSERT (errno == 0);
+  }
+  {
+    const char input[] = "0x1P 1000000";
+    char *ptr;
+    double result;
+    errno = 0;
+    result = strtod (input, &ptr);
+    ASSERT (result == 1.0);             /* NetBSD 3.0, OpenBSD 4.0, AIX 7.1, 
HP-UX 11.11, IRIX 6.5, OSF/1 5.1, Solaris 10, mingw */
+    ASSERT (ptr == input + 3);          /* NetBSD 3.0, OpenBSD 4.0, AIX 7.1, 
HP-UX 11.11, IRIX 6.5, OSF/1 5.1, Solaris 10, mingw */
+    ASSERT (errno == 0);
+  }

   /* Infinity.  */
   {
@@ -831,6 +851,16 @@ main (void)
     ASSERT (ptr == input + 6);          /* NetBSD 3.0, OpenBSD 4.0, AIX 5.1, 
HP-UX 11.11, IRIX 6.5, OSF/1 5.1, Solaris 10, mingw */
     ASSERT (errno == 0);
   }
+  {
+    const char input[] = "0x1p 2";
+    char *ptr;
+    double result;
+    errno = 0;
+    result = strtod (input, &ptr);
+    ASSERT (result == 1.0);             /* NetBSD 3.0, OpenBSD 4.0, AIX 7.1, 
HP-UX 11.11, IRIX 6.5, OSF/1 5.1, Solaris 10, mingw */
+    ASSERT (ptr == input + 3);          /* NetBSD 3.0, OpenBSD 4.0, AIX 7.1, 
HP-UX 11.11, IRIX 6.5, OSF/1 5.1, Solaris 10, mingw */
+    ASSERT (errno == 0);
+  }

   /* Large buffers.  */
   {
-- 
1.7.2.2




reply via email to

[Prev in Thread] Current Thread [Next in Thread]