GNU C Library master sources branch master updated. glibc-2.22-386-g95e8397

fw@sourceware.org fw@sourceware.org
Thu Oct 15 15:24:00 GMT 2015


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".

The branch, master has been updated
       via  95e83974812f5c6de0483690ef47787965bb817a (commit)
      from  b994fd793799590f70ceb9a96f135bc2390bb4f3 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=95e83974812f5c6de0483690ef47787965bb817a

commit 95e83974812f5c6de0483690ef47787965bb817a
Author: Florian Weimer <fweimer@redhat.com>
Date:   Thu Oct 15 16:37:48 2015 +0200

    vfscanf: Use struct scratch_buffer instead of extend_alloca
    
    A custom character buffer is added in this commit, in the form of
    struct char_buffer.  The char_buffer_add function replaces the
    ADDW macro (which has grown with each successive security fix).
    The char_buffer_add slow path is moved out-of-line, reducing
    code size.
    
    	* stdio-common/vfscanf.c (MEMCPY): Remove macro.
    	(struct char_buffer): New type.
    	(char_buffer_start, char_buffer_size, char_buffer_error)
    	(char_buffer_rewind, char_buffer_add): New functions.
    	(ADDW): Remove macro, replaced by the char_buffer_add function.
    	(_IO_vfscanf_internal): Rewrite using struct char_buffer instead
    	of extend_alloca.  Make control flow more explicit.

diff --git a/ChangeLog b/ChangeLog
index 63701d1..b759929 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2015-10-15  Florian Weimer  <fweimer@redhat.com>
+
+	* stdio-common/vfscanf.c (MEMCPY): Remove macro.
+	(struct char_buffer): New type.
+	(char_buffer_start, char_buffer_size, char_buffer_error)
+	(char_buffer_rewind, char_buffer_add): New functions.
+	(ADDW): Remove macro, replaced by the char_buffer_add function.
+	(_IO_vfscanf_internal): Rewrite using struct char_buffer instead
+	of extend_alloca.  Make control flow more explicit.
+
 2015-10-15  H.J. Lu  <hongjiu.lu@intel.com>
 
 	[BZ #19137]
diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf.c
index 9d9ff20..1382eb5 100644
--- a/stdio-common/vfscanf.c
+++ b/stdio-common/vfscanf.c
@@ -29,6 +29,7 @@
 #include <wctype.h>
 #include <libc-lock.h>
 #include <locale/localeinfo.h>
+#include <scratch_buffer.h>
 
 #ifdef	__GNUC__
 # define HAVE_LONGLONG
@@ -87,7 +88,6 @@
 				    ? ++read_in				      \
 				    : (size_t) (inchar_errno = errno)), c))
 
-# define MEMCPY(d, s, n) __wmemcpy (d, s, n)
 # define ISSPACE(Ch)	  iswspace (Ch)
 # define ISDIGIT(Ch)	  iswdigit (Ch)
 # define ISXDIGIT(Ch)	  iswxdigit (Ch)
@@ -118,7 +118,6 @@
 			    (void) (c != EOF				      \
 				    ? ++read_in				      \
 				    : (size_t) (inchar_errno = errno)), c))
-# define MEMCPY(d, s, n) memcpy (d, s, n)
 # define ISSPACE(Ch)	  __isspace_l (Ch, loc)
 # define ISDIGIT(Ch)	  __isdigit_l (Ch, loc)
 # define ISXDIGIT(Ch)	  __isxdigit_l (Ch, loc)
@@ -192,6 +191,78 @@ struct ptrs_to_free
   char **ptrs[32];
 };
 
+struct char_buffer {
+  CHAR_T *current;
+  CHAR_T *end;
+  struct scratch_buffer scratch;
+};
+
+/* Returns a pointer to the first CHAR_T object in the buffer.  Only
+   valid if char_buffer_add (BUFFER, CH) has been called and
+   char_buffer_error (BUFFER) is false.  */
+static inline CHAR_T *
+char_buffer_start (const struct char_buffer *buffer)
+{
+  return (CHAR_T *) buffer->scratch.data;
+}
+
+/* Returns the number of CHAR_T objects in the buffer.  Only valid if
+   char_buffer_error (BUFFER) is false.  */
+static inline size_t
+char_buffer_size (const struct char_buffer *buffer)
+{
+  return buffer->current - char_buffer_start (buffer);
+}
+
+/* Reinitializes BUFFER->current and BUFFER->end to cover the entire
+   scratch buffer.  */
+static inline void
+char_buffer_rewind (struct char_buffer *buffer)
+{
+  buffer->current = char_buffer_start (buffer);
+  buffer->end = buffer->current + buffer->scratch.length / sizeof (CHAR_T);
+}
+
+/* Returns true if a previous call to char_buffer_add (BUFFER, CH)
+   failed.  */
+static inline bool
+char_buffer_error (const struct char_buffer *buffer)
+{
+  return __glibc_unlikely (buffer->current == NULL);
+}
+
+/* Slow path for char_buffer_add.  */
+static void
+char_buffer_add_slow (struct char_buffer *buffer, CHAR_T ch)
+{
+  if (char_buffer_error (buffer))
+    return;
+  size_t offset = buffer->end - (CHAR_T *) buffer->scratch.data;
+  if (!scratch_buffer_grow_preserve (&buffer->scratch))
+    {
+      buffer->current = NULL;
+      buffer->end = NULL;
+      return;
+    }
+  char_buffer_rewind (buffer);
+  buffer->current += offset;
+  *buffer->current++ = ch;
+}
+
+/* Adds CH to BUFFER.  This function does not report any errors, check
+   for them with char_buffer_error.  */
+static inline void
+char_buffer_add (struct char_buffer *buffer, CHAR_T ch)
+  __attribute__ ((always_inline));
+static inline void
+char_buffer_add (struct char_buffer *buffer, CHAR_T ch)
+{
+  if (__glibc_unlikely (buffer->current == buffer->end))
+    char_buffer_add_slow (buffer, ch);
+  else
+    *buffer->current++ = ch;
+}
+
 /* Read formatted input from S according to the format string
    FORMAT, using the argument list in ARG.
    Return the number of assignments made, or -1 for an input error.  */
@@ -262,46 +333,8 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
   int skip_space = 0;
   /* Workspace.  */
   CHAR_T *tw;			/* Temporary pointer.  */
-  CHAR_T *wp = NULL;		/* Workspace.  */
-  size_t wpmax = 0;		/* Maximal size of workspace.  */
-  size_t wpsize;		/* Currently used bytes in workspace.  */
-  bool use_malloc = false;
-#define ADDW(Ch)							    \
-  do									    \
-    {									    \
-      if (__glibc_unlikely (wpsize == wpmax))				      \
-	{								    \
-	  CHAR_T *old = wp;						    \
-	  bool fits = __glibc_likely (wpmax <= SIZE_MAX / sizeof (CHAR_T) / 2); \
-	  size_t wpneed = MAX (UCHAR_MAX + 1, 2 * wpmax);		    \
-	  size_t newsize = fits ? wpneed * sizeof (CHAR_T) : SIZE_MAX;	    \
-	  if (!__libc_use_alloca (newsize))				    \
-	    {								    \
-	      wp = realloc (use_malloc ? wp : NULL, newsize);		    \
-	      if (wp == NULL)						    \
-		{							    \
-		  if (use_malloc)					    \
-		    free (old);						    \
-		  done = EOF;						    \
-		  goto errout;						    \
-		}							    \
-	      if (! use_malloc)						    \
-		MEMCPY (wp, old, wpsize);				    \
-	      wpmax = wpneed;						    \
-	      use_malloc = true;					    \
-	    }								    \
-	  else								    \
-	    {								    \
-	      size_t s = wpmax * sizeof (CHAR_T);			    \
-	      wp = (CHAR_T *) extend_alloca (wp, s, newsize);		    \
-	      wpmax = s / sizeof (CHAR_T);				    \
-	      if (old != NULL)						    \
-		MEMCPY (wp, old, wpsize);				    \
-	    }								    \
-	}								    \
-      wp[wpsize++] = (Ch);						    \
-    }									    \
-  while (0)
+  struct char_buffer charbuf;
+  scratch_buffer_init (&charbuf.scratch);
 
 #ifdef __va_copy
   __va_copy (arg, argptr);
@@ -449,7 +482,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
       argpos = 0;
 
       /* Prepare temporary buffer.  */
-      wpsize = 0;
+      char_buffer_rewind (&charbuf);
 
       /* Check for a positional parameter specification.  */
       if (ISDIGIT ((UCHAR_T) *f))
@@ -1374,7 +1407,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 	  /* Check for a sign.  */
 	  if (c == L_('-') || c == L_('+'))
 	    {
-	      ADDW (c);
+	      char_buffer_add (&charbuf, c);
 	      if (width > 0)
 		--width;
 	      c = inchar ();
@@ -1386,7 +1419,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 	      if (width > 0)
 		--width;
 
-	      ADDW (c);
+	      char_buffer_add (&charbuf, c);
 	      c = inchar ();
 
 	      if (width != 0 && TOLOWER (c) == L_('x'))
@@ -1641,7 +1674,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 
 		      while ((unsigned char) *cmpp == c && avail >= 0)
 			{
-			  ADDW (c);
+			  char_buffer_add (&charbuf, c);
 			  if (*++cmpp == '\0')
 			    break;
 			  else
@@ -1652,12 +1685,19 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 			    }
 			}
 
+		      if (char_buffer_error (&charbuf))
+			{
+			  __set_errno (ENOMEM);
+			  done = EOF;
+			  goto errout;
+			}
+
 		      if (*cmpp != '\0')
 			{
 			  /* We are pushing all read characters back.  */
 			  if (cmpp > thousands)
 			    {
-			      wpsize -= cmpp - thousands;
+			      charbuf.current -= cmpp - thousands;
 			      ungetc (c, s);
 			      while (--cmpp > thousands)
 				ungetc_not_eof ((unsigned char) *cmpp, s);
@@ -1670,14 +1710,14 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 			width = avail;
 
 		      /* The last thousands character will be added back by
-			 the ADDW below.  */
-			--wpsize;
+			 the char_buffer_add below.  */
+			--charbuf.current;
 #endif
 		    }
 		  else
 		    break;
 
-		  ADDW (c);
+		  char_buffer_add (&charbuf, c);
 		  if (width > 0)
 		    --width;
 
@@ -1707,7 +1747,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 
 			while ((unsigned char) *cmpp == c && avail >= 0)
 			  {
-			    ADDW (c);
+			    char_buffer_add (&charbuf, c);
 			    if (*++cmpp == '\0')
 			      break;
 			    else
@@ -1718,12 +1758,19 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 			      }
 			  }
 
+			if (char_buffer_error (&charbuf))
+			  {
+			    __set_errno (ENOMEM);
+			    done = EOF;
+			    goto errout;
+			  }
+
 			if (*cmpp != '\0')
 			  {
 			    /* We are pushing all read characters back.  */
 			    if (cmpp > thousands)
 			      {
-				wpsize -= cmpp - thousands;
+				charbuf.current -= cmpp - thousands;
 				ungetc (c, s);
 				while (--cmpp > thousands)
 				  ungetc_not_eof ((unsigned char) *cmpp, s);
@@ -1736,26 +1783,35 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 			  width = avail;
 
 			/* The last thousands character will be added back by
-			   the ADDW below.  */
-			--wpsize;
+			   the char_buffer_add below.  */
+			--charbuf.current;
 #endif
 		      }
 		    else
 		      break;
 		  }
-		ADDW (c);
+		char_buffer_add (&charbuf, c);
 		if (width > 0)
 		  --width;
 
 		c = inchar ();
 	      }
 
-	  if (wpsize == 0
-	      || (wpsize == 1 && (wp[0] == L_('+') || wp[0] == L_('-'))))
+	  if (char_buffer_error (&charbuf))
+	    {
+	      __set_errno (ENOMEM);
+	      done = EOF;
+	      goto errout;
+	    }
+
+	  if (char_buffer_size (&charbuf) == 0
+	      || (char_buffer_size (&charbuf) == 1
+		  && (char_buffer_start (&charbuf)[0] == L_('+')
+		      || char_buffer_start (&charbuf)[0] == L_('-'))))
 	    {
 	      /* There was no number.  If we are supposed to read a pointer
 		 we must recognize "(nil)" as well.  */
-	      if (__builtin_expect (wpsize == 0
+	      if (__builtin_expect (char_buffer_size (&charbuf) == 0
 				    && (flags & READ_POINTER)
 				    && (width < 0 || width >= 5)
 				    && c == '('
@@ -1765,7 +1821,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 				    && inchar () == L_(')'), 1))
 		/* We must produce the value of a NULL pointer.  A single
 		   '0' digit is enough.  */
-		ADDW (L_('0'));
+		  char_buffer_add (&charbuf, L_('0'));
 	      else
 		{
 		  /* The last read character is not part of the number
@@ -1780,22 +1836,32 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 	    ungetc (c, s);
 
 	  /* Convert the number.  */
-	  ADDW (L_('\0'));
+	  char_buffer_add (&charbuf, L_('\0'));
+	  if (char_buffer_error (&charbuf))
+	    {
+	      __set_errno (ENOMEM);
+	      done = EOF;
+	      goto errout;
+	    }
 	  if (need_longlong && (flags & LONGDBL))
 	    {
 	      if (flags & NUMBER_SIGNED)
-		num.q = __strtoll_internal (wp, &tw, base, flags & GROUP);
+		num.q = __strtoll_internal
+		  (char_buffer_start (&charbuf), &tw, base, flags & GROUP);
 	      else
-		num.uq = __strtoull_internal (wp, &tw, base, flags & GROUP);
+		num.uq = __strtoull_internal
+		  (char_buffer_start (&charbuf), &tw, base, flags & GROUP);
 	    }
 	  else
 	    {
 	      if (flags & NUMBER_SIGNED)
-		num.l = __strtol_internal (wp, &tw, base, flags & GROUP);
+		num.l = __strtol_internal
+		  (char_buffer_start (&charbuf), &tw, base, flags & GROUP);
 	      else
-		num.ul = __strtoul_internal (wp, &tw, base, flags & GROUP);
+		num.ul = __strtoul_internal
+		  (char_buffer_start (&charbuf), &tw, base, flags & GROUP);
 	    }
-	  if (__glibc_unlikely (wp == tw))
+	  if (__glibc_unlikely (char_buffer_start (&charbuf) == tw))
 	    conv_error ();
 
 	  if (!(flags & SUPPRESS))
@@ -1864,42 +1930,42 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 	  if (TOLOWER (c) == L_('n'))
 	    {
 	      /* Maybe "nan".  */
-	      ADDW (c);
+	      char_buffer_add (&charbuf, c);
 	      if (__builtin_expect (width == 0
 				    || inchar () == EOF
 				    || TOLOWER (c) != L_('a'), 0))
 		conv_error ();
 	      if (width > 0)
 		--width;
-	      ADDW (c);
+	      char_buffer_add (&charbuf, c);
 	      if (__builtin_expect (width == 0
 				    || inchar () == EOF
 				    || TOLOWER (c) != L_('n'), 0))
 		conv_error ();
 	      if (width > 0)
 		--width;
-	      ADDW (c);
+	      char_buffer_add (&charbuf, c);
 	      /* It is "nan".  */
 	      goto scan_float;
 	    }
 	  else if (TOLOWER (c) == L_('i'))
 	    {
 	      /* Maybe "inf" or "infinity".  */
-	      ADDW (c);
+	      char_buffer_add (&charbuf, c);
 	      if (__builtin_expect (width == 0
 				    || inchar () == EOF
 				    || TOLOWER (c) != L_('n'), 0))
 		conv_error ();
 	      if (width > 0)
 		--width;
-	      ADDW (c);
+	      char_buffer_add (&charbuf, c);
 	      if (__builtin_expect (width == 0
 				    || inchar () == EOF
 				    || TOLOWER (c) != L_('f'), 0))
 		conv_error ();
 	      if (width > 0)
 		--width;
-	      ADDW (c);
+	      char_buffer_add (&charbuf, c);
 	      /* It is as least "inf".  */
 	      if (width != 0 && inchar () != EOF)
 		{
@@ -1908,35 +1974,35 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 		      if (width > 0)
 			--width;
 		      /* Now we have to read the rest as well.  */
-		      ADDW (c);
+		      char_buffer_add (&charbuf, c);
 		      if (__builtin_expect (width == 0
 					    || inchar () == EOF
 					    || TOLOWER (c) != L_('n'), 0))
 			conv_error ();
 		      if (width > 0)
 			--width;
-		      ADDW (c);
+		      char_buffer_add (&charbuf, c);
 		      if (__builtin_expect (width == 0
 					    || inchar () == EOF
 					    || TOLOWER (c) != L_('i'), 0))
 			conv_error ();
 		      if (width > 0)
 			--width;
-		      ADDW (c);
+		      char_buffer_add (&charbuf, c);
 		      if (__builtin_expect (width == 0
 					    || inchar () == EOF
 					    || TOLOWER (c) != L_('t'), 0))
 			conv_error ();
 		      if (width > 0)
 			--width;
-		      ADDW (c);
+		      char_buffer_add (&charbuf, c);
 		      if (__builtin_expect (width == 0
 					    || inchar () == EOF
 					    || TOLOWER (c) != L_('y'), 0))
 			conv_error ();
 		      if (width > 0)
 			--width;
-		      ADDW (c);
+		      char_buffer_add (&charbuf, c);
 		    }
 		  else
 		    /* Never mind.  */
@@ -1948,14 +2014,14 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 	  exp_char = L_('e');
 	  if (width != 0 && c == L_('0'))
 	    {
-	      ADDW (c);
+	      char_buffer_add (&charbuf, c);
 	      c = inchar ();
 	      if (width > 0)
 		--width;
 	      if (width != 0 && TOLOWER (c) == L_('x'))
 		{
 		  /* It is a number in hexadecimal format.  */
-		  ADDW (c);
+		  char_buffer_add (&charbuf, c);
 
 		  flags |= HEXA_FLOAT;
 		  exp_char = L_('p');
@@ -1972,23 +2038,29 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 
 	  while (1)
 	    {
+	      if (char_buffer_error (&charbuf))
+		{
+		  __set_errno (ENOMEM);
+		  done = EOF;
+		  goto errout;
+		}
 	      if (ISDIGIT (c))
 		{
-		  ADDW (c);
+		  char_buffer_add (&charbuf, c);
 		  got_digit = 1;
 		}
 	      else if (!got_e && (flags & HEXA_FLOAT) && ISXDIGIT (c))
 		{
-		  ADDW (c);
+		  char_buffer_add (&charbuf, c);
 		  got_digit = 1;
 		}
-	      else if (got_e && wp[wpsize - 1] == exp_char
+	      else if (got_e && charbuf.current[-1] == exp_char
 		       && (c == L_('-') || c == L_('+')))
-		ADDW (c);
+		char_buffer_add (&charbuf, c);
 	      else if (got_digit && !got_e
 		       && (CHAR_T) TOLOWER (c) == exp_char)
 		{
-		  ADDW (exp_char);
+		  char_buffer_add (&charbuf, exp_char);
 		  got_e = got_dot = 1;
 		}
 	      else
@@ -1996,11 +2068,11 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 #ifdef COMPILE_WSCANF
 		  if (! got_dot && c == decimal)
 		    {
-		      ADDW (c);
+		      char_buffer_add (&charbuf, c);
 		      got_dot = 1;
 		    }
 		  else if ((flags & GROUP) != 0 && ! got_dot && c == thousands)
-		    ADDW (c);
+		    char_buffer_add (&charbuf, c);
 		  else
 		    {
 		      /* The last read character is not part of the number
@@ -2029,7 +2101,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 		    {
 		      /* Add all the characters.  */
 		      for (cmpp = decimal; *cmpp != '\0'; ++cmpp)
-			ADDW ((unsigned char) *cmpp);
+			char_buffer_add (&charbuf, (unsigned char) *cmpp);
 		      if (width > 0)
 			width = avail;
 		      got_dot = 1;
@@ -2066,7 +2138,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 			{
 			  /* Add all the characters.  */
 			  for (cmpp = thousands; *cmpp != '\0'; ++cmpp)
-			    ADDW ((unsigned char) *cmpp);
+			    char_buffer_add (&charbuf, (unsigned char) *cmpp);
 			  if (width > 0)
 			    width = avail;
 			}
@@ -2088,13 +2160,20 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 		--width;
 	    }
 
+	  if (char_buffer_error (&charbuf))
+	    {
+	      __set_errno (ENOMEM);
+	      done = EOF;
+	      goto errout;
+	    }
+
 	  wctrans_t map;
 	  if (__builtin_expect ((flags & I18N) != 0, 0)
 	      /* Hexadecimal floats make no sense, fixing localized
 		 digits with ASCII letters.  */
 	      && !(flags & HEXA_FLOAT)
 	      /* Minimum requirement.  */
-	      && (wpsize == 0 || got_dot)
+	      && (char_buffer_size (&charbuf) == 0 || got_dot)
 	      && (map = __wctrans ("to_inpunct")) != NULL)
 	    {
 	      /* Reget the first character.  */
@@ -2113,20 +2192,23 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 		 for localized FP numbers, then we may have localized
 		 digits.  Note, we test GOT_DOT above.  */
 #ifdef COMPILE_WSCANF
-	      if (wpsize == 0 || (wpsize == 1 && wcdigits[11] == decimal))
+	      if (char_buffer_size (&charbuf) == 0
+		  || (char_buffer_size (&charbuf) == 1
+		      && wcdigits[11] == decimal))
 #else
 	      char mbdigits[12][MB_LEN_MAX + 1];
 
 	      mbstate_t state;
 	      memset (&state, '\0', sizeof (state));
 
-	      bool match_so_far = wpsize == 0;
+	      bool match_so_far = char_buffer_size (&charbuf) == 0;
 	      size_t mblen = __wcrtomb (mbdigits[11], wcdigits[11], &state);
 	      if (mblen != (size_t) -1)
 		{
 		  mbdigits[11][mblen] = '\0';
-		  match_so_far |= (wpsize == strlen (decimal)
-				   && strcmp (decimal, mbdigits[11]) == 0);
+		  match_so_far |=
+		    (char_buffer_size (&charbuf) == strlen (decimal)
+		     && strcmp (decimal, mbdigits[11]) == 0);
 		}
 	      else
 		{
@@ -2135,7 +2217,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 		     from a file.  */
 		  if (decimal_len <= MB_LEN_MAX)
 		    {
-		      match_so_far |= wpsize == decimal_len;
+		      match_so_far |= char_buffer_size (&charbuf) == decimal_len;
 		      memcpy (mbdigits[11], decimal, decimal_len + 1);
 		    }
 		  else
@@ -2190,13 +2272,19 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 		     conversion is done correctly. */
 		  while (1)
 		    {
-		      if (got_e && wp[wpsize - 1] == exp_char
+		      if (char_buffer_error (&charbuf))
+			{
+			  __set_errno (ENOMEM);
+			  done = EOF;
+			  goto errout;
+			}
+		      if (got_e && charbuf.current[-1] == exp_char
 			  && (c == L_('-') || c == L_('+')))
-			ADDW (c);
-		      else if (wpsize > 0 && !got_e
+			char_buffer_add (&charbuf, c);
+		      else if (char_buffer_size (&charbuf) > 0 && !got_e
 			       && (CHAR_T) TOLOWER (c) == exp_char)
 			{
-			  ADDW (exp_char);
+			  char_buffer_add (&charbuf, exp_char);
 			  got_e = got_dot = 1;
 			}
 		      else
@@ -2210,15 +2298,15 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 			      if (c == wcdigits[n])
 				{
 				  if (n < 10)
-				    ADDW (L_('0') + n);
+				    char_buffer_add (&charbuf, L_('0') + n);
 				  else if (n == 11 && !got_dot)
 				    {
-				      ADDW (decimal);
+				      char_buffer_add (&charbuf, decimal);
 				      got_dot = 1;
 				    }
 				  else if (n == 10 && have_locthousands
 					   && ! got_dot)
-				    ADDW (thousands);
+				    char_buffer_add (&charbuf, thousands);
 				  else
 				    /* The last read character is not part
 				       of the number anymore.  */
@@ -2245,13 +2333,14 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 				    width = avail;
 
 				  if (n < 10)
-				    ADDW (L_('0') + n);
+				    char_buffer_add (&charbuf, L_('0') + n);
 				  else if (n == 11 && !got_dot)
 				    {
 				      /* Add all the characters.  */
 				      for (cmpp = decimal; *cmpp != '\0';
 					   ++cmpp)
-					ADDW ((unsigned char) *cmpp);
+					char_buffer_add (&charbuf,
+							 (unsigned char) *cmpp);
 
 				      got_dot = 1;
 				    }
@@ -2261,7 +2350,8 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 				      /* Add all the characters.  */
 				      for (cmpp = thousands; *cmpp != '\0';
 					   ++cmpp)
-					ADDW ((unsigned char) *cmpp);
+					char_buffer_add (&charbuf,
+							 (unsigned char) *cmpp);
 				    }
 				  else
 				    /* The last read character is not part
@@ -2305,36 +2395,53 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 #endif
 	    }
 
+	  if (char_buffer_error (&charbuf))
+	    {
+	      __set_errno (ENOMEM);
+	      done = EOF;
+	      goto errout;
+	    }
+
 	  /* Have we read any character?  If we try to read a number
 	     in hexadecimal notation and we have read only the `0x'
 	     prefix this is an error.  */
-	  if (__builtin_expect (wpsize == 0
-				|| ((flags & HEXA_FLOAT) && wpsize == 2), 0))
+	  if (__glibc_unlikely (char_buffer_size (&charbuf) == 0
+				|| ((flags & HEXA_FLOAT)
+				    && char_buffer_size (&charbuf) == 2)))
 	    conv_error ();
 
 	scan_float:
 	  /* Convert the number.  */
-	  ADDW (L_('\0'));
+	  char_buffer_add (&charbuf, L_('\0'));
+	  if (char_buffer_error (&charbuf))
+	    {
+	      __set_errno (ENOMEM);
+	      done = EOF;
+	      goto errout;
+	    }
 	  if ((flags & LONGDBL) && !__ldbl_is_dbl)
 	    {
-	      long double d = __strtold_internal (wp, &tw, flags & GROUP);
-	      if (!(flags & SUPPRESS) && tw != wp)
+	      long double d = __strtold_internal
+		(char_buffer_start (&charbuf), &tw, flags & GROUP);
+	      if (!(flags & SUPPRESS) && tw != char_buffer_start (&charbuf))
 		*ARG (long double *) = negative ? -d : d;
 	    }
 	  else if (flags & (LONG | LONGDBL))
 	    {
-	      double d = __strtod_internal (wp, &tw, flags & GROUP);
-	      if (!(flags & SUPPRESS) && tw != wp)
+	      double d = __strtod_internal
+		(char_buffer_start (&charbuf), &tw, flags & GROUP);
+	      if (!(flags & SUPPRESS) && tw != char_buffer_start (&charbuf))
 		*ARG (double *) = negative ? -d : d;
 	    }
 	  else
 	    {
-	      float d = __strtof_internal (wp, &tw, flags & GROUP);
-	      if (!(flags & SUPPRESS) && tw != wp)
+	      float d = __strtof_internal
+		(char_buffer_start (&charbuf), &tw, flags & GROUP);
+	      if (!(flags & SUPPRESS) && tw != char_buffer_start (&charbuf))
 		*ARG (float *) = negative ? -d : d;
 	    }
 
-	  if (__glibc_unlikely (tw == wp))
+	  if (__glibc_unlikely (tw == char_buffer_start (&charbuf)))
 	    conv_error ();
 
 	  if (!(flags & SUPPRESS))
@@ -2380,12 +2487,13 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 #else
 	  /* Fill WP with byte flags indexed by character.
 	     We will use this flag map for matching input characters.  */
-	  if (wpmax < UCHAR_MAX + 1)
+	  if (!scratch_buffer_set_array_size
+	      (&charbuf.scratch, UCHAR_MAX + 1, 1))
 	    {
-	      wpmax = UCHAR_MAX + 1;
-	      wp = (char *) alloca (wpmax);
+	      done = EOF;
+	      goto errout;
 	    }
-	  memset (wp, '\0', UCHAR_MAX + 1);
+	  memset (charbuf.scratch.data, '\0', UCHAR_MAX + 1);
 
 	  fc = *f;
 	  if (fc == ']' || fc == '-')
@@ -2393,7 +2501,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 	      /* If ] or - appears before any char in the set, it is not
 		 the terminator or separator, but the first char in the
 		 set.  */
-	      wp[fc] = 1;
+	      ((char *)charbuf.scratch.data)[fc] = 1;
 	      ++f;
 	    }
 
@@ -2404,11 +2512,11 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 		/* Add all characters from the one before the '-'
 		   up to (but not including) the next format char.  */
 		for (fc = (unsigned char) f[-2]; fc < (unsigned char) *f; ++fc)
-		  wp[fc] = 1;
+		  ((char *)charbuf.scratch.data)[fc] = 1;
 	      }
 	    else
 	      /* Add the character to the flag map.  */
-	      wp[fc] = 1;
+	      ((char *)charbuf.scratch.data)[fc] = 1;
 
 	  if (__glibc_unlikely (fc == '\0'))
 	    conv_error();
@@ -2537,7 +2645,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 
 	      do
 		{
-		  if (wp[c] == not_in)
+		  if (((char *) charbuf.scratch.data)[c] == not_in)
 		    {
 		      ungetc_not_eof (c, s);
 		      break;
@@ -2765,7 +2873,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 #else
 	      do
 		{
-		  if (wp[c] == not_in)
+		  if (((char *) charbuf.scratch.data)[c] == not_in)
 		    {
 		      ungetc_not_eof (c, s);
 		      break;
@@ -2905,9 +3013,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
   /* Unlock stream.  */
   UNLOCK_STREAM (s);
 
-  if (use_malloc)
-    free (wp);
-
+  scratch_buffer_free (&charbuf.scratch);
   if (errp != NULL)
     *errp |= errval;
 

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog              |   10 ++
 stdio-common/vfscanf.c |  356 +++++++++++++++++++++++++++++++-----------------
 2 files changed, 241 insertions(+), 125 deletions(-)


hooks/post-receive
-- 
GNU C Library master sources



More information about the Glibc-cvs mailing list