1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-07-30 22:43:12 +03:00

vfprintf: Rewrite printf_positional to use struct scratch_buffer

This commit is contained in:
Florian Weimer
2015-10-17 12:05:12 +02:00
parent 52fb79d6cd
commit db8ad8fac3
2 changed files with 15 additions and 40 deletions

View File

@ -1,3 +1,8 @@
2015-10-17 Florian Weimer <fweimer@redhat.com>
* stdio-common/vfprintf.c (printf_positional): Rewrite to use
struct scratch_buffer instead of extend_alloca.
2015-10-17 Florian Weimer <fweimer@redhat.com> 2015-10-17 Florian Weimer <fweimer@redhat.com>
* sysdeps/unix/sysv/linux/kernel-features.h * sysdeps/unix/sysv/linux/kernel-features.h

View File

@ -29,6 +29,7 @@
#include <_itoa.h> #include <_itoa.h>
#include <locale/localeinfo.h> #include <locale/localeinfo.h>
#include <stdio.h> #include <stdio.h>
#include <scratch_buffer.h>
/* This code is shared between the standard stdio implementation found /* This code is shared between the standard stdio implementation found
in GNU C library and the libio implementation originally found in in GNU C library and the libio implementation originally found in
@ -1698,18 +1699,15 @@ printf_positional (_IO_FILE *s, const CHAR_T *format, int readonly_format,
void *args_malloced = NULL; void *args_malloced = NULL;
/* For positional argument handling. */ /* For positional argument handling. */
struct printf_spec *specs; struct scratch_buffer specsbuf;
scratch_buffer_init (&specsbuf);
/* Track if we malloced the SPECS array and thus must free it. */ struct printf_spec *specs = specsbuf.data;
bool specs_malloced = false; size_t specs_limit = specsbuf.length / sizeof (specs[0]);
/* Array with information about the needed arguments. This has to /* Array with information about the needed arguments. This has to
be dynamically extensible. */ be dynamically extensible. */
size_t nspecs = 0; size_t nspecs = 0;
/* A more or less arbitrary start value. */
size_t nspecs_size = 32 * sizeof (struct printf_spec);
specs = alloca (nspecs_size);
/* The number of arguments the format string requests. This will /* The number of arguments the format string requests. This will
determine the size of the array needed to store the argument determine the size of the array needed to store the argument
attributes. */ attributes. */
@ -1746,42 +1744,15 @@ printf_positional (_IO_FILE *s, const CHAR_T *format, int readonly_format,
for (const UCHAR_T *f = lead_str_end; *f != L_('\0'); for (const UCHAR_T *f = lead_str_end; *f != L_('\0');
f = specs[nspecs++].next_fmt) f = specs[nspecs++].next_fmt)
{ {
if (nspecs * sizeof (*specs) >= nspecs_size) if (nspecs == specs_limit)
{ {
/* Extend the array of format specifiers. */ if (!scratch_buffer_grow_preserve (&specsbuf))
if (nspecs_size * 2 < nspecs_size)
{ {
__set_errno (ENOMEM);
done = -1; done = -1;
goto all_done; goto all_done;
} }
struct printf_spec *old = specs; specs = specsbuf.data;
if (__libc_use_alloca (2 * nspecs_size)) specs_limit = specsbuf.length / sizeof (specs[0]);
specs = extend_alloca (specs, nspecs_size, 2 * nspecs_size);
else
{
nspecs_size *= 2;
specs = malloc (nspecs_size);
if (specs == NULL)
{
__set_errno (ENOMEM);
specs = old;
done = -1;
goto all_done;
}
}
/* Copy the old array's elements to the new space. */
memmove (specs, old, nspecs * sizeof (*specs));
/* If we had previously malloc'd space for SPECS, then
release it after the copy is complete. */
if (specs_malloced)
free (old);
/* Now set SPECS_MALLOCED if needed. */
if (!__libc_use_alloca (nspecs_size))
specs_malloced = true;
} }
/* Parse the format specifier. */ /* Parse the format specifier. */
@ -2091,12 +2062,11 @@ printf_positional (_IO_FILE *s, const CHAR_T *format, int readonly_format,
- specs[nspecs_done].end_of_fmt); - specs[nspecs_done].end_of_fmt);
} }
all_done: all_done:
if (__glibc_unlikely (specs_malloced))
free (specs);
if (__glibc_unlikely (args_malloced != NULL)) if (__glibc_unlikely (args_malloced != NULL))
free (args_malloced); free (args_malloced);
if (__glibc_unlikely (workstart != NULL)) if (__glibc_unlikely (workstart != NULL))
free (workstart); free (workstart);
scratch_buffer_free (&specsbuf);
return done; return done;
} }