From db8ad8fac3ebdb6c68964f4d24185c2bd2c83342 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Sat, 17 Oct 2015 12:05:12 +0200 Subject: vfprintf: Rewrite printf_positional to use struct scratch_buffer --- ChangeLog | 5 +++++ stdio-common/vfprintf.c | 50 ++++++++++--------------------------------------- 2 files changed, 15 insertions(+), 40 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0f5fbc7dae..123f34cf8d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2015-10-17 Florian Weimer + + * stdio-common/vfprintf.c (printf_positional): Rewrite to use + struct scratch_buffer instead of extend_alloca. + 2015-10-17 Florian Weimer * sysdeps/unix/sysv/linux/kernel-features.h diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c index 5e408d2961..ae01452954 100644 --- a/stdio-common/vfprintf.c +++ b/stdio-common/vfprintf.c @@ -29,6 +29,7 @@ #include <_itoa.h> #include #include +#include /* This code is shared between the standard stdio implementation found 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; /* For positional argument handling. */ - struct printf_spec *specs; - - /* Track if we malloced the SPECS array and thus must free it. */ - bool specs_malloced = false; + struct scratch_buffer specsbuf; + scratch_buffer_init (&specsbuf); + struct printf_spec *specs = specsbuf.data; + size_t specs_limit = specsbuf.length / sizeof (specs[0]); /* Array with information about the needed arguments. This has to be dynamically extensible. */ 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 determine the size of the array needed to store the argument 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'); f = specs[nspecs++].next_fmt) { - if (nspecs * sizeof (*specs) >= nspecs_size) + if (nspecs == specs_limit) { - /* Extend the array of format specifiers. */ - if (nspecs_size * 2 < nspecs_size) + if (!scratch_buffer_grow_preserve (&specsbuf)) { - __set_errno (ENOMEM); done = -1; goto all_done; } - struct printf_spec *old = specs; - if (__libc_use_alloca (2 * nspecs_size)) - 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; + specs = specsbuf.data; + specs_limit = specsbuf.length / sizeof (specs[0]); } /* 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); } all_done: - if (__glibc_unlikely (specs_malloced)) - free (specs); if (__glibc_unlikely (args_malloced != NULL)) free (args_malloced); if (__glibc_unlikely (workstart != NULL)) free (workstart); + scratch_buffer_free (&specsbuf); return done; } -- cgit v1.2.3