about summary refs log tree commit diff
path: root/stdio-common/printf-parsemb.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2012-04-02 14:31:19 -0700
committerDavid S. Miller <davem@davemloft.net>2012-04-02 14:31:19 -0700
commit135ffda8b84226a91c6062db69a61975b2f11cb6 (patch)
tree5aa71e41591bc7246f36bb55fbf7dc7daaefd9d1 /stdio-common/printf-parsemb.c
parent302cadd343d26cfa9b043c213c2a38de259464d8 (diff)
downloadglibc-135ffda8b84226a91c6062db69a61975b2f11cb6.tar.gz
glibc-135ffda8b84226a91c6062db69a61975b2f11cb6.tar.xz
glibc-135ffda8b84226a91c6062db69a61975b2f11cb6.zip
Tighten up vfprintf width, precision, and total length overflow handling.
	With help from Paul Eggert, Carlos O'Donell, and Roland McGrath.
	* stdio-common/printf-parse.h (read_int): Change return type to
	'int', return -1 on INT_MAX overflow.
	* stdio-common/vfprintf.c (vfprintf): Validate width and precision
	against overflow of INT_MAX.  Set errno to EOVERFLOW when 'done'
	overflows INT_MAX.  Check for overflow of in-format-string precision
	values properly.  Use EOVERFLOW rather than ERANGE throughout.  Use
	SIZE_MAX not INT_MAX for integer overflow test.
	* stdio-common/printf-parsemb.c: If read_int signals an overflow,
	skip the construct in the format string but do not record anything.
	* stdio-common/bug22.c: Adjust to test both width/prevision
	INT_MAX overflow as well as total length INT_MAX overflow.  Check
	explicitly for proper errno values.
Diffstat (limited to 'stdio-common/printf-parsemb.c')
-rw-r--r--stdio-common/printf-parsemb.c42
1 files changed, 30 insertions, 12 deletions
diff --git a/stdio-common/printf-parsemb.c b/stdio-common/printf-parsemb.c
index 2bdb5e65ab..a45ac74e06 100644
--- a/stdio-common/printf-parsemb.c
+++ b/stdio-common/printf-parsemb.c
@@ -87,12 +87,15 @@ __parse_one_specmb (const UCHAR_T *format, size_t posn,
 
       n = read_int (&format);
 
-      if (n > 0 && *format == L_('$'))
+      if (n != 0 && *format == L_('$'))
 	/* Is positional parameter.  */
 	{
 	  ++format;		/* Skip the '$'.  */
-	  spec->data_arg = n - 1;
-	  *max_ref_arg = MAX (*max_ref_arg, n);
+	  if (n != -1)
+	    {
+	      spec->data_arg = n - 1;
+	      *max_ref_arg = MAX (*max_ref_arg, n);
+	    }
 	}
       else
 	/* Oops; that was actually the width and/or 0 padding flag.
@@ -160,10 +163,13 @@ __parse_one_specmb (const UCHAR_T *format, size_t posn,
 	  /* The width argument might be found in a positional parameter.  */
 	  n = read_int (&format);
 
-	  if (n > 0 && *format == L_('$'))
+	  if (n != 0 && *format == L_('$'))
 	    {
-	      spec->width_arg = n - 1;
-	      *max_ref_arg = MAX (*max_ref_arg, n);
+	      if (n != -1)
+		{
+		  spec->width_arg = n - 1;
+		  *max_ref_arg = MAX (*max_ref_arg, n);
+		}
 	      ++format;		/* Skip '$'.  */
 	    }
 	}
@@ -177,9 +183,13 @@ __parse_one_specmb (const UCHAR_T *format, size_t posn,
 	}
     }
   else if (ISDIGIT (*format))
-    /* Constant width specification.  */
-    spec->info.width = read_int (&format);
+    {
+      int n = read_int (&format);
 
+      /* Constant width specification.  */
+      if (n != -1)
+	spec->info.width = n;
+    }
   /* Get the precision.  */
   spec->prec_arg = -1;
   /* -1 means none given; 0 means explicit 0.  */
@@ -196,10 +206,13 @@ __parse_one_specmb (const UCHAR_T *format, size_t posn,
 	    {
 	      n = read_int (&format);
 
-	      if (n > 0 && *format == L_('$'))
+	      if (n != 0 && *format == L_('$'))
 		{
-		  spec->prec_arg = n - 1;
-		  *max_ref_arg = MAX (*max_ref_arg, n);
+		  if (n != -1)
+		    {
+		      spec->prec_arg = n - 1;
+		      *max_ref_arg = MAX (*max_ref_arg, n);
+		    }
 		  ++format;
 		}
 	    }
@@ -213,7 +226,12 @@ __parse_one_specmb (const UCHAR_T *format, size_t posn,
 	    }
 	}
       else if (ISDIGIT (*format))
-	spec->info.prec = read_int (&format);
+	{
+	  int n = read_int (&format);
+
+	  if (n != -1)
+	    spec->info.prec = n;
+	}
       else
 	/* "%.?" is treated like "%.0?".  */
 	spec->info.prec = 0;