acfd962
diff -Nrup a/stdlib/Makefile b/stdlib/Makefile
acfd962
--- a/stdlib/Makefile	2012-08-13 13:12:18.000000000 -0600
acfd962
+++ b/stdlib/Makefile	2012-08-15 09:49:09.215666702 -0600
acfd962
@@ -69,7 +69,7 @@ tests		:= tst-strtol tst-strtod testmb t
acfd962
 		   tst-makecontext tst-strtod4 tst-strtod5 tst-qsort2	    \
acfd962
 		   tst-makecontext2 tst-strtod6 tst-unsetenv1		    \
acfd962
 		   tst-makecontext3 bug-getcontext bug-fmtmsg1		    \
acfd962
-		   tst-secure-getenv
acfd962
+		   tst-secure-getenv tst-strtod-overflow
acfd962
 tests-static	:= tst-secure-getenv
acfd962
 
acfd962
 include ../Makeconfig
acfd962
diff -Nrup a/stdlib/strtod_l.c b/stdlib/strtod_l.c
acfd962
--- a/stdlib/strtod_l.c	2012-08-13 13:12:18.000000000 -0600
acfd962
+++ b/stdlib/strtod_l.c	2012-08-15 09:49:09.216666698 -0600
acfd962
@@ -60,6 +60,7 @@ extern unsigned long long int ____strtou
acfd962
 #include <math.h>
acfd962
 #include <stdlib.h>
acfd962
 #include <string.h>
acfd962
+#include <stdint.h>
acfd962
 
acfd962
 /* The gmp headers need some configuration frobs.  */
acfd962
 #define HAVE_ALLOCA 1
acfd962
@@ -174,19 +175,19 @@ extern const mp_limb_t _tens_in_limb[MAX
acfd962
 /* Return a floating point number of the needed type according to the given
acfd962
    multi-precision number after possible rounding.  */
acfd962
 static FLOAT
acfd962
-round_and_return (mp_limb_t *retval, int exponent, int negative,
acfd962
+round_and_return (mp_limb_t *retval, intmax_t exponent, int negative,
acfd962
 		  mp_limb_t round_limb, mp_size_t round_bit, int more_bits)
acfd962
 {
acfd962
   if (exponent < MIN_EXP - 1)
acfd962
     {
acfd962
-      mp_size_t shift = MIN_EXP - 1 - exponent;
acfd962
-
acfd962
-      if (shift > MANT_DIG)
acfd962
+      if (exponent < MIN_EXP - 1 - MANT_DIG)
acfd962
 	{
acfd962
 	  __set_errno (ERANGE);
acfd962
 	  return 0.0;
acfd962
 	}
acfd962
 
acfd962
+      mp_size_t shift = MIN_EXP - 1 - exponent;
acfd962
+
acfd962
       more_bits |= (round_limb & ((((mp_limb_t) 1) << round_bit) - 1)) != 0;
acfd962
       if (shift == MANT_DIG)
acfd962
 	/* This is a special case to handle the very seldom case where
acfd962
@@ -233,6 +234,9 @@ round_and_return (mp_limb_t *retval, int
acfd962
       __set_errno (ERANGE);
acfd962
     }
acfd962
 
acfd962
+  if (exponent > MAX_EXP)
acfd962
+    goto overflow;
acfd962
+
acfd962
   if ((round_limb & (((mp_limb_t) 1) << round_bit)) != 0
acfd962
       && (more_bits || (retval[0] & 1) != 0
acfd962
 	  || (round_limb & ((((mp_limb_t) 1) << round_bit) - 1)) != 0))
acfd962
@@ -258,6 +262,7 @@ round_and_return (mp_limb_t *retval, int
acfd962
     }
acfd962
 
acfd962
   if (exponent > MAX_EXP)
acfd962
+  overflow:
acfd962
     return negative ? -FLOAT_HUGE_VAL : FLOAT_HUGE_VAL;
acfd962
 
acfd962
   return MPN2FLOAT (retval, exponent, negative);
acfd962
@@ -271,7 +276,7 @@ round_and_return (mp_limb_t *retval, int
acfd962
    factor for the resulting number (see code) multiply by it.  */
acfd962
 static const STRING_TYPE *
acfd962
 str_to_mpn (const STRING_TYPE *str, int digcnt, mp_limb_t *n, mp_size_t *nsize,
acfd962
-	    int *exponent
acfd962
+	    intmax_t *exponent
acfd962
 #ifndef USE_WIDE_CHAR
acfd962
 	    , const char *decimal, size_t decimal_len, const char *thousands
acfd962
 #endif
acfd962
@@ -335,7 +340,7 @@ str_to_mpn (const STRING_TYPE *str, int
acfd962
     }
acfd962
   while (--digcnt > 0);
acfd962
 
acfd962
-  if (*exponent > 0 && cnt + *exponent <= MAX_DIG_PER_LIMB)
acfd962
+  if (*exponent > 0 && *exponent <= MAX_DIG_PER_LIMB - cnt)
acfd962
     {
acfd962
       low *= _tens_in_limb[*exponent];
acfd962
       start = _tens_in_limb[cnt + *exponent];
acfd962
@@ -413,7 +418,7 @@ ____STRTOF_INTERNAL (nptr, endptr, group
acfd962
 {
acfd962
   int negative;			/* The sign of the number.  */
acfd962
   MPN_VAR (num);		/* MP representation of the number.  */
acfd962
-  int exponent;			/* Exponent of the number.  */
acfd962
+  intmax_t exponent;		/* Exponent of the number.  */
acfd962
 
acfd962
   /* Numbers starting `0X' or `0x' have to be processed with base 16.  */
acfd962
   int base = 10;
acfd962
@@ -435,7 +440,7 @@ ____STRTOF_INTERNAL (nptr, endptr, group
acfd962
   /* Points at the character following the integer and fractional digits.  */
acfd962
   const STRING_TYPE *expp;
acfd962
   /* Total number of digit and number of digits in integer part.  */
acfd962
-  int dig_no, int_no, lead_zero;
acfd962
+  size_t dig_no, int_no, lead_zero;
acfd962
   /* Contains the last character read.  */
acfd962
   CHAR_TYPE c;
acfd962
 
acfd962
@@ -767,7 +772,7 @@ ____STRTOF_INTERNAL (nptr, endptr, group
acfd962
      are all or any is really a fractional digit will be decided
acfd962
      later.  */
acfd962
   int_no = dig_no;
acfd962
-  lead_zero = int_no == 0 ? -1 : 0;
acfd962
+  lead_zero = int_no == 0 ? (size_t) -1 : 0;
acfd962
 
acfd962
   /* Read the fractional digits.  A special case are the 'american
acfd962
      style' numbers like `16.' i.e. with decimal point but without
acfd962
@@ -789,12 +794,13 @@ ____STRTOF_INTERNAL (nptr, endptr, group
acfd962
 	     (base == 16 && ({ CHAR_TYPE lo = TOLOWER (c);
acfd962
 			       lo >= L_('a') && lo <= L_('f'); })))
acfd962
 	{
acfd962
-	  if (c != L_('0') && lead_zero == -1)
acfd962
+	  if (c != L_('0') && lead_zero == (size_t) -1)
acfd962
 	    lead_zero = dig_no - int_no;
acfd962
 	  ++dig_no;
acfd962
 	  c = *++cp;
acfd962
 	}
acfd962
     }
acfd962
+  assert (dig_no <= (uintmax_t) INTMAX_MAX);
acfd962
 
acfd962
   /* Remember start of exponent (if any).  */
acfd962
   expp = cp;
acfd962
@@ -817,24 +823,80 @@ ____STRTOF_INTERNAL (nptr, endptr, group
acfd962
 
acfd962
       if (c >= L_('0') && c <= L_('9'))
acfd962
 	{
acfd962
-	  int exp_limit;
acfd962
+	  intmax_t exp_limit;
acfd962
 
acfd962
 	  /* Get the exponent limit. */
acfd962
 	  if (base == 16)
acfd962
-	    exp_limit = (exp_negative ?
acfd962
-			 -MIN_EXP + MANT_DIG + 4 * int_no :
acfd962
-			 MAX_EXP - 4 * int_no + 4 * lead_zero + 3);
acfd962
+	    {
acfd962
+	      if (exp_negative)
acfd962
+		{
acfd962
+		  assert (int_no <= (uintmax_t) (INTMAX_MAX
acfd962
+						 + MIN_EXP - MANT_DIG) / 4);
acfd962
+		  exp_limit = -MIN_EXP + MANT_DIG + 4 * (intmax_t) int_no;
acfd962
+		}
acfd962
+	      else
acfd962
+		{
acfd962
+		  if (int_no)
acfd962
+		    {
acfd962
+		      assert (lead_zero == 0
acfd962
+			      && int_no <= (uintmax_t) INTMAX_MAX / 4);
acfd962
+		      exp_limit = MAX_EXP - 4 * (intmax_t) int_no + 3;
acfd962
+		    }
acfd962
+		  else if (lead_zero == (size_t) -1)
acfd962
+		    {
acfd962
+		      /* The number is zero and this limit is
acfd962
+			 arbitrary.  */
acfd962
+		      exp_limit = MAX_EXP + 3;
acfd962
+		    }
acfd962
+		  else
acfd962
+		    {
acfd962
+		      assert (lead_zero
acfd962
+			      <= (uintmax_t) (INTMAX_MAX - MAX_EXP - 3) / 4);
acfd962
+		      exp_limit = (MAX_EXP
acfd962
+				   + 4 * (intmax_t) lead_zero
acfd962
+				   + 3);
acfd962
+		    }
acfd962
+		}
acfd962
+	    }
acfd962
 	  else
acfd962
-	    exp_limit = (exp_negative ?
acfd962
-			 -MIN_10_EXP + MANT_DIG + int_no :
acfd962
-			 MAX_10_EXP - int_no + lead_zero + 1);
acfd962
+	    {
acfd962
+	      if (exp_negative)
acfd962
+		{
acfd962
+		  assert (int_no
acfd962
+			  <= (uintmax_t) (INTMAX_MAX + MIN_10_EXP - MANT_DIG));
acfd962
+		  exp_limit = -MIN_10_EXP + MANT_DIG + (intmax_t) int_no;
acfd962
+		}
acfd962
+	      else
acfd962
+		{
acfd962
+		  if (int_no)
acfd962
+		    {
acfd962
+		      assert (lead_zero == 0
acfd962
+			      && int_no <= (uintmax_t) INTMAX_MAX);
acfd962
+		      exp_limit = MAX_10_EXP - (intmax_t) int_no + 1;
acfd962
+		    }
acfd962
+		  else if (lead_zero == (size_t) -1)
acfd962
+		    {
acfd962
+		      /* The number is zero and this limit is
acfd962
+			 arbitrary.  */
acfd962
+		      exp_limit = MAX_10_EXP + 1;
acfd962
+		    }
acfd962
+		  else
acfd962
+		    {
acfd962
+		      assert (lead_zero
acfd962
+			      <= (uintmax_t) (INTMAX_MAX - MAX_10_EXP - 1));
acfd962
+		      exp_limit = MAX_10_EXP + (intmax_t) lead_zero + 1;
acfd962
+		    }
acfd962
+		}
acfd962
+	    }
acfd962
+
acfd962
+	  if (exp_limit < 0)
acfd962
+	    exp_limit = 0;
acfd962
 
acfd962
 	  do
acfd962
 	    {
acfd962
-	      exponent *= 10;
acfd962
-	      exponent += c - L_('0');
acfd962
-
acfd962
-	      if (__builtin_expect (exponent > exp_limit, 0))
acfd962
+	      if (__builtin_expect ((exponent > exp_limit / 10
acfd962
+				     || (exponent == exp_limit / 10
acfd962
+					 && c - L_('0') > exp_limit % 10)), 0))
acfd962
 		/* The exponent is too large/small to represent a valid
acfd962
 		   number.  */
acfd962
 		{
acfd962
@@ -843,7 +905,7 @@ ____STRTOF_INTERNAL (nptr, endptr, group
acfd962
 		  /* We have to take care for special situation: a joker
acfd962
 		     might have written "0.0e100000" which is in fact
acfd962
 		     zero.  */
acfd962
-		  if (lead_zero == -1)
acfd962
+		  if (lead_zero == (size_t) -1)
acfd962
 		    result = negative ? -0.0 : 0.0;
acfd962
 		  else
acfd962
 		    {
acfd962
@@ -862,6 +924,9 @@ ____STRTOF_INTERNAL (nptr, endptr, group
acfd962
 		  /* NOTREACHED */
acfd962
 		}
acfd962
 
acfd962
+	      exponent *= 10;
acfd962
+	      exponent += c - L_('0');
acfd962
+
acfd962
 	      c = *++cp;
acfd962
 	    }
acfd962
 	  while (c >= L_('0') && c <= L_('9'));
acfd962
@@ -930,7 +995,14 @@ ____STRTOF_INTERNAL (nptr, endptr, group
acfd962
 	}
acfd962
 #endif
acfd962
       startp += lead_zero + decimal_len;
acfd962
-      exponent -= base == 16 ? 4 * lead_zero : lead_zero;
acfd962
+      assert (lead_zero <= (base == 16
acfd962
+			    ? (uintmax_t) INTMAX_MAX / 4
acfd962
+			    : (uintmax_t) INTMAX_MAX));
acfd962
+      assert (lead_zero <= (base == 16
acfd962
+			    ? ((uintmax_t) exponent
acfd962
+			       - (uintmax_t) INTMAX_MIN) / 4
acfd962
+			    : ((uintmax_t) exponent - (uintmax_t) INTMAX_MIN)));
acfd962
+      exponent -= base == 16 ? 4 * (intmax_t) lead_zero : (intmax_t) lead_zero;
acfd962
       dig_no -= lead_zero;
acfd962
     }
acfd962
 
acfd962
@@ -972,7 +1044,10 @@ ____STRTOF_INTERNAL (nptr, endptr, group
acfd962
 	}
acfd962
 
acfd962
       /* Adjust the exponent for the bits we are shifting in.  */
acfd962
-      exponent += bits - 1 + (int_no - 1) * 4;
acfd962
+      assert (int_no <= (uintmax_t) (exponent < 0
acfd962
+				     ? (INTMAX_MAX - bits + 1) / 4
acfd962
+				     : (INTMAX_MAX - exponent - bits + 1) / 4));
acfd962
+      exponent += bits - 1 + ((intmax_t) int_no - 1) * 4;
acfd962
 
acfd962
       while (--dig_no > 0 && idx >= 0)
acfd962
 	{
acfd962
@@ -1024,13 +1099,15 @@ ____STRTOF_INTERNAL (nptr, endptr, group
acfd962
      really integer digits or belong to the fractional part; i.e. we normalize
acfd962
      123e-2 to 1.23.  */
acfd962
   {
acfd962
-    register int incr = (exponent < 0 ? MAX (-int_no, exponent)
acfd962
-			 : MIN (dig_no - int_no, exponent));
acfd962
+    register intmax_t incr = (exponent < 0
acfd962
+			      ? MAX (-(intmax_t) int_no, exponent)
acfd962
+			      : MIN ((intmax_t) dig_no - (intmax_t) int_no,
acfd962
+				     exponent));
acfd962
     int_no += incr;
acfd962
     exponent -= incr;
acfd962
   }
acfd962
 
acfd962
-  if (__builtin_expect (int_no + exponent > MAX_10_EXP + 1, 0))
acfd962
+  if (__builtin_expect (exponent > MAX_10_EXP + 1 - (intmax_t) int_no, 0))
acfd962
     {
acfd962
       __set_errno (ERANGE);
acfd962
       return negative ? -FLOAT_HUGE_VAL : FLOAT_HUGE_VAL;
acfd962
@@ -1215,7 +1292,7 @@ ____STRTOF_INTERNAL (nptr, endptr, group
acfd962
        digits we should have enough bits for the result.  The remaining
acfd962
        decimal digits give us the information that more bits are following.
acfd962
        This can be used while rounding.  (Two added as a safety margin.)  */
acfd962
-    if (dig_no - int_no > (MANT_DIG - bits + 2) / 3 + 2)
acfd962
+    if ((intmax_t) dig_no > (intmax_t) int_no + (MANT_DIG - bits + 2) / 3 + 2)
acfd962
       {
acfd962
 	dig_no = int_no + (MANT_DIG - bits + 2) / 3 + 2;
acfd962
 	more_bits = 1;
acfd962
@@ -1223,7 +1300,7 @@ ____STRTOF_INTERNAL (nptr, endptr, group
acfd962
     else
acfd962
       more_bits = 0;
acfd962
 
acfd962
-    neg_exp = dig_no - int_no - exponent;
acfd962
+    neg_exp = (intmax_t) dig_no - (intmax_t) int_no - exponent;
acfd962
 
acfd962
     /* Construct the denominator.  */
acfd962
     densize = 0;
acfd962
diff -Nrup a/stdlib/tst-strtod-overflow.c b/stdlib/tst-strtod-overflow.c
acfd962
--- a/stdlib/tst-strtod-overflow.c	1969-12-31 17:00:00.000000000 -0700
acfd962
+++ b/stdlib/tst-strtod-overflow.c	2012-08-15 09:49:09.221666678 -0600
acfd962
@@ -0,0 +1,48 @@
acfd962
+/* Test for integer/buffer overflow in strtod.
acfd962
+   Copyright (C) 2012 Free Software Foundation, Inc.
acfd962
+   This file is part of the GNU C Library.
acfd962
+
acfd962
+   The GNU C Library is free software; you can redistribute it and/or
acfd962
+   modify it under the terms of the GNU Lesser General Public
acfd962
+   License as published by the Free Software Foundation; either
acfd962
+   version 2.1 of the License, or (at your option) any later version.
acfd962
+
acfd962
+   The GNU C Library is distributed in the hope that it will be useful,
acfd962
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
acfd962
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
acfd962
+   Lesser General Public License for more details.
acfd962
+
acfd962
+   You should have received a copy of the GNU Lesser General Public
acfd962
+   License along with the GNU C Library; if not, see
acfd962
+   <http://www.gnu.org/licenses/>.  */
acfd962
+
acfd962
+#include <stdio.h>
acfd962
+#include <stdlib.h>
acfd962
+#include <string.h>
acfd962
+
acfd962
+#define EXPONENT "e-2147483649"
acfd962
+#define SIZE 214748364
acfd962
+
acfd962
+static int
acfd962
+do_test (void)
acfd962
+{
acfd962
+  char *p = malloc (1 + SIZE + sizeof (EXPONENT));
acfd962
+  if (p == NULL)
acfd962
+    {
acfd962
+      puts ("malloc failed, cannot test for overflow");
acfd962
+      return 0;
acfd962
+    }
acfd962
+  p[0] = '1';
acfd962
+  memset (p + 1, '0', SIZE);
acfd962
+  memcpy (p + 1 + SIZE, EXPONENT, sizeof (EXPONENT));
acfd962
+  double d = strtod (p, NULL);
acfd962
+  if (d != 0)
acfd962
+    {
acfd962
+      printf ("strtod returned wrong value: %a\n", d);
acfd962
+      return 1;
acfd962
+    }
acfd962
+  return 0;
acfd962
+}
acfd962
+
acfd962
+#define TEST_FUNCTION do_test ()
acfd962
+#include "../test-skeleton.c"