]> sourceware.org Git - glibc.git/commitdiff
vfscanf: Use struct scratch_buffer instead of extend_alloca
authorFlorian Weimer <fweimer@redhat.com>
Thu, 15 Oct 2015 14:37:48 +0000 (16:37 +0200)
committerFlorian Weimer <fweimer@redhat.com>
Thu, 15 Oct 2015 15:18:51 +0000 (17:18 +0200)
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.

ChangeLog
stdio-common/vfscanf.c

index 63701d1bd2d3ef758b782c6d891b6d18713704a6..b759929bf900774055bdae817e515ae60dafc68e 100644 (file)
--- 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]
index 9d9ff2094c2f3c3b2901606ce7b38a37ed2b5e85..1382eb513d1ba0c5f34acfeef9b7524011806f01 100644 (file)
@@ -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)
                            (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;
 
This page took 0.114208 seconds and 5 git commands to generate.