vfprintf: Use struct scratch_buffer for positional arguments allocation

This commit is contained in:
Florian Weimer 2017-06-29 09:37:04 +02:00
parent cd00e12d31
commit 12d5853e22
2 changed files with 34 additions and 40 deletions

View File

@ -1,3 +1,9 @@
2017-06-29 Florian Weimer <fweimer@redhat.com>
* stdio-common/vfprintf.c (printf_positional): Use struct
scratch_buffer to allocate backing storage for the args_value,
args_size, args_type arrays.
2017-06-29 Florian Weimer <fweimer@redhat.com> 2017-06-29 Florian Weimer <fweimer@redhat.com>
* stdio-common/_i18n_number.h (_i18n_number_rewrite): Use struct * stdio-common/_i18n_number.h (_i18n_number_rewrite): Use struct

View File

@ -1708,15 +1708,17 @@ printf_positional (_IO_FILE *s, const CHAR_T *format, int readonly_format,
CHAR_T *work_buffer, int save_errno, CHAR_T *work_buffer, int save_errno,
const char *grouping, THOUSANDS_SEP_T thousands_sep) const char *grouping, THOUSANDS_SEP_T thousands_sep)
{ {
/* For the argument descriptions, which may be allocated on the heap. */
void *args_malloced = NULL;
/* For positional argument handling. */ /* For positional argument handling. */
struct scratch_buffer specsbuf; struct scratch_buffer specsbuf;
scratch_buffer_init (&specsbuf); scratch_buffer_init (&specsbuf);
struct printf_spec *specs = specsbuf.data; struct printf_spec *specs = specsbuf.data;
size_t specs_limit = specsbuf.length / sizeof (specs[0]); size_t specs_limit = specsbuf.length / sizeof (specs[0]);
/* Used as a backing store for args_value, args_size, args_type
below. */
struct scratch_buffer argsbuf;
scratch_buffer_init (&argsbuf);
/* 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;
@ -1725,10 +1727,6 @@ printf_positional (_IO_FILE *s, const CHAR_T *format, int readonly_format,
determine the size of the array needed to store the argument determine the size of the array needed to store the argument
attributes. */ attributes. */
size_t nargs = 0; size_t nargs = 0;
size_t bytes_per_arg;
union printf_arg *args_value;
int *args_size;
int *args_type;
/* Positional parameters refer to arguments directly. This could /* Positional parameters refer to arguments directly. This could
also determine the maximum number of arguments. Track the also determine the maximum number of arguments. Track the
@ -1778,38 +1776,29 @@ printf_positional (_IO_FILE *s, const CHAR_T *format, int readonly_format,
/* Determine the number of arguments the format string consumes. */ /* Determine the number of arguments the format string consumes. */
nargs = MAX (nargs, max_ref_arg); nargs = MAX (nargs, max_ref_arg);
/* Calculate total size needed to represent a single argument across
all three argument-related arrays. */
bytes_per_arg = (sizeof (*args_value) + sizeof (*args_size)
+ sizeof (*args_type));
/* Check for potential integer overflow. */ union printf_arg *args_value;
if (__glibc_unlikely (nargs > INT_MAX / bytes_per_arg)) int *args_size;
{ int *args_type;
__set_errno (EOVERFLOW); {
done = -1; /* Calculate total size needed to represent a single argument
goto all_done; across all three argument-related arrays. */
} size_t bytes_per_arg
= sizeof (*args_value) + sizeof (*args_size) + sizeof (*args_type);
/* Allocate memory for all three argument arrays. */ if (!scratch_buffer_set_array_size (&argsbuf, nargs, bytes_per_arg))
if (__libc_use_alloca (nargs * bytes_per_arg)) {
args_value = alloca (nargs * bytes_per_arg); done = -1;
else goto all_done;
{ }
args_value = args_malloced = malloc (nargs * bytes_per_arg); args_value = argsbuf.data;
if (args_value == NULL) /* Set up the remaining two arrays to each point past the end of
{ the prior array, since space for all three has been allocated
done = -1; now. */
goto all_done; args_size = &args_value[nargs].pa_int;
} args_type = &args_size[nargs];
} memset (args_type, s->_flags2 & _IO_FLAGS2_FORTIFY ? '\xff' : '\0',
nargs * sizeof (*args_type));
/* Set up the remaining two arrays to each point past the end of the }
prior array, since space for all three has been allocated now. */
args_size = &args_value[nargs].pa_int;
args_type = &args_size[nargs];
memset (args_type, s->_flags2 & _IO_FLAGS2_FORTIFY ? '\xff' : '\0',
nargs * sizeof (*args_type));
/* XXX Could do sanity check here: If any element in ARGS_TYPE is /* XXX Could do sanity check here: If any element in ARGS_TYPE is
still zero after this loop, format is invalid. For now we still zero after this loop, format is invalid. For now we
@ -2075,10 +2064,9 @@ 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 (args_malloced != NULL))
free (args_malloced);
if (__glibc_unlikely (workstart != NULL)) if (__glibc_unlikely (workstart != NULL))
free (workstart); free (workstart);
scratch_buffer_free (&argsbuf);
scratch_buffer_free (&specsbuf); scratch_buffer_free (&specsbuf);
return done; return done;
} }