diff options
author | Florian Weimer <fweimer@redhat.com> | 2015-10-15 16:37:48 +0200 |
---|---|---|
committer | Florian Weimer <fweimer@redhat.com> | 2015-10-15 17:18:51 +0200 |
commit | 95e83974812f5c6de0483690ef47787965bb817a (patch) | |
tree | c86080b681b554ae4466370a385b4fe23237e8fd /stdio-common/vfscanf.c | |
parent | b994fd793799590f70ceb9a96f135bc2390bb4f3 (diff) | |
download | glibc-95e83974812f5c6de0483690ef47787965bb817a.tar.gz glibc-95e83974812f5c6de0483690ef47787965bb817a.tar.xz glibc-95e83974812f5c6de0483690ef47787965bb817a.zip |
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.
Diffstat (limited to 'stdio-common/vfscanf.c')
-rw-r--r-- | stdio-common/vfscanf.c | 356 |
1 files changed, 231 insertions, 125 deletions
diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf.c index 9d9ff2094c..1382eb513d 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; |