Subject: Re: bug#8545: issues with recent doprnt-related changes

From: Paul Eggert <[email-masked]>
Date: Wed, 27 Apr 2011 20:11:52 -0700

On 04/27/11 18:32, Juanma Barranquero wrote:

> A cursory look suggests that fmt == format_end + 1 is possible

Thanks, I had missed that possibility.  (Evidently your cursory looks
are better than mine. :-)  A possible patch is below.

> would it be undefined behavior,
> as long as the pointer has not been dereferenced?

Yes.  A portable C program is not allowed to create a pointer that
doesn't point to an object, with the two exceptions of a null pointer
and a pointer to the address immediately after an object.  On
some architectures, attempting to point to random addresses can cause
exceptions or other undefined behavior.

=== modified file 'src/doprnt.c'
--- src/doprnt.c	2011-04-27 23:04:20 +0000
+++ src/doprnt.c	2011-04-28 03:00:59 +0000
@@ -194,22 +194,21 @@ doprnt (char *buffer, register size_t bu
 		     This might be a field width or a precision; e.g.
 		     %1.1000f and %1000.1f both might need 1000+ bytes.
 		     Parse the width or precision, checking for overflow.  */
-		  size_t n = *fmt - '0';
-		  while (fmt < format_end
-			 && '0' <= fmt[1] && fmt[1] <= '9')
+		  size_t n = *fmt++ - '0';
+		  while (fmt < format_end && '0' <= *fmt && *fmt <= '9')
 		    {
 		      if (n >= SIZE_MAX / 10
 			  || n * 10 > SIZE_MAX - (fmt[1] - '0'))
 			error ("Format width or precision too large");
-		      n = n * 10 + fmt[1] - '0';
-		      *string++ = *++fmt;
+		      n = n * 10 + *fmt - '0';
+		      *string++ = *fmt++;
 		    }
 
 		  if (size_bound < n)
 		    size_bound = n;
 		}
 	      else if (*fmt == '-' || *fmt == ' ' || *fmt == '.' || *fmt == '+')
-		;
+		fmt++;
 	      else if (*fmt == 'l')
 		{
 		  long_flag = 1 + (fmt + 1 < format_end && fmt[1] == 'l');
@@ -218,10 +217,7 @@ doprnt (char *buffer, register size_t bu
 		}
 	      else
 		break;
-	      fmt++;
 	    }
-	  if (fmt > format_end)
-	    fmt = format_end;
 	  *string = 0;
 
 	  /* Make the size bound large enough to handle floating point formats