changeset 9834:b4f1e5627265

Fix buffer overrun.
author Bruno Haible <bruno@clisp.org>
date Sun, 30 Mar 2008 18:29:39 +0200
parents 48eddbd8edd5
children 69955b112e2e
files ChangeLog lib/vasnprintf.c
diffstat 2 files changed, 68 insertions(+), 60 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2008-03-30  Bruno Haible  <bruno@clisp.org>
+
+	Fix buffer overrun.
+	* lib/vasnprintf.c (VASNPRINTF): If !USE_SNPRINTF && pad_ourselves:
+	Don't consider the width for tmp_length. Check count against tmp_length
+	before doing the padding. Ensure enough allocation during padding.
+
 2008-03-30  Eric Blake  <ebb9@byu.net>
 
 	strtod touchups.
--- a/lib/vasnprintf.c
+++ b/lib/vasnprintf.c
@@ -3656,6 +3656,44 @@
 		  }
 #endif
 
+		/* Decide whether to handle the precision ourselves.  */
+#if NEED_PRINTF_UNBOUNDED_PRECISION
+		switch (dp->conversion)
+		  {
+		  case 'd': case 'i': case 'u':
+		  case 'o':
+		  case 'x': case 'X': case 'p':
+		    prec_ourselves = has_precision && (precision > 0);
+		    break;
+		  default:
+		    prec_ourselves = 0;
+		    break;
+		  }
+#endif
+
+		/* Decide whether to perform the padding ourselves.  */
+#if !NEED_PRINTF_FLAG_LEFTADJUST && (!DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION)
+		switch (dp->conversion)
+		  {
+# if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO
+		  /* If we need conversion from TCHAR_T[] to DCHAR_T[], we need
+		     to perform the padding after this conversion.  Functions
+		     with unistdio extensions perform the padding based on
+		     character count rather than element count.  */
+		  case 'c': case 's':
+# endif
+# if NEED_PRINTF_FLAG_ZERO
+		  case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
+		  case 'a': case 'A':
+# endif
+		    pad_ourselves = 1;
+		    break;
+		  default:
+		    pad_ourselves = prec_ourselves;
+		    break;
+		  }
+#endif
+
 #if !USE_SNPRINTF
 		/* Allocate a temporary buffer of sufficient size for calling
 		   sprintf.  */
@@ -3832,18 +3870,22 @@
 		      abort ();
 		    }
 
+		  if (!pad_ourselves)
+		    {
 # if ENABLE_UNISTDIO
-		  /* Padding considers the number of characters, therefore the
-		     number of elements after padding may be
-		       > max (tmp_length, width)
-		     but is certainly
-		       <= tmp_length + width.  */
-		  tmp_length = xsum (tmp_length, width);
+		      /* Padding considers the number of characters, therefore
+			 the number of elements after padding may be
+			   > max (tmp_length, width)
+			 but is certainly
+			   <= tmp_length + width.  */
+		      tmp_length = xsum (tmp_length, width);
 # else
-		  /* Padding considers the number of elements, says POSIX.  */
-		  if (tmp_length < width)
-		    tmp_length = width;
+		      /* Padding considers the number of elements,
+			 says POSIX.  */
+		      if (tmp_length < width)
+			tmp_length = width;
 # endif
+		    }
 
 		  tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */
 		}
@@ -3864,44 +3906,6 @@
 		  }
 #endif
 
-		/* Decide whether to handle the precision ourselves.  */
-#if NEED_PRINTF_UNBOUNDED_PRECISION
-		switch (dp->conversion)
-		  {
-		  case 'd': case 'i': case 'u':
-		  case 'o':
-		  case 'x': case 'X': case 'p':
-		    prec_ourselves = has_precision && (precision > 0);
-		    break;
-		  default:
-		    prec_ourselves = 0;
-		    break;
-		  }
-#endif
-
-		/* Decide whether to perform the padding ourselves.  */
-#if !NEED_PRINTF_FLAG_LEFTADJUST && (!DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION)
-		switch (dp->conversion)
-		  {
-# if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO
-		  /* If we need conversion from TCHAR_T[] to DCHAR_T[], we need
-		     to perform the padding after this conversion.  Functions
-		     with unistdio extensions perform the padding based on
-		     character count rather than element count.  */
-		  case 'c': case 's':
-# endif
-# if NEED_PRINTF_FLAG_ZERO
-		  case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
-		  case 'a': case 'A':
-# endif
-		    pad_ourselves = 1;
-		    break;
-		  default:
-		    pad_ourselves = prec_ourselves;
-		    break;
-		  }
-#endif
-
 		/* Construct the format string for calling snprintf or
 		   sprintf.  */
 		fbp = buf;
@@ -4398,14 +4402,14 @@
 		      }
 #endif
 
-#if !DCHAR_IS_TCHAR
-# if !USE_SNPRINTF
+#if !USE_SNPRINTF
 		    if (count >= tmp_length)
 		      /* tmp_length was incorrectly calculated - fix the
 			 code above!  */
 		      abort ();
-# endif
-
+#endif
+
+#if !DCHAR_IS_TCHAR
 		    /* Convert from TCHAR_T[] to DCHAR_T[].  */
 		    if (dp->conversion == 'c' || dp->conversion == 's')
 		      {
@@ -4523,7 +4527,7 @@
 			if (w < width)
 			  {
 			    size_t pad = width - w;
-# if USE_SNPRINTF
+
 			    /* Make room for the result.  */
 			    if (xsum (count, pad) > allocated - length)
 			      {
@@ -4533,12 +4537,16 @@
 				  xmax (xsum3 (length, count, pad),
 					xtimes (allocated, 2));
 
+# if USE_SNPRINTF
 				length += count;
 				ENSURE_ALLOCATION (n);
 				length -= count;
+# else
+				ENSURE_ALLOCATION (n);
+# endif
 			      }
 			    /* Here count + pad <= allocated - length.  */
-# endif
+
 			    {
 # if !DCHAR_IS_TCHAR || USE_SNPRINTF
 			      DCHAR_T * const rp = result + length;
@@ -4599,13 +4607,6 @@
 		      }
 #endif
 
-#if DCHAR_IS_TCHAR && !USE_SNPRINTF
-		    if (count >= tmp_length)
-		      /* tmp_length was incorrectly calculated - fix the
-			 code above!  */
-		      abort ();
-#endif
-
 		    /* Here still count <= allocated - length.  */
 
 #if !DCHAR_IS_TCHAR || USE_SNPRINTF