1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-08-05 19:35:52 +03:00

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); /* Calculate total size needed to represent a single argument
done = -1; across all three argument-related arrays. */
goto all_done; size_t bytes_per_arg
} = sizeof (*args_value) + sizeof (*args_size) + sizeof (*args_type);
if (!scratch_buffer_set_array_size (&argsbuf, nargs, bytes_per_arg))
/* Allocate memory for all three argument arrays. */
if (__libc_use_alloca (nargs * bytes_per_arg))
args_value = alloca (nargs * bytes_per_arg);
else
{
args_value = args_malloced = malloc (nargs * bytes_per_arg);
if (args_value == NULL)
{ {
done = -1; done = -1;
goto all_done; goto all_done;
} }
} args_value = argsbuf.data;
/* Set up the remaining two arrays to each point past the end of
/* Set up the remaining two arrays to each point past the end of the the prior array, since space for all three has been allocated
prior array, since space for all three has been allocated now. */ now. */
args_size = &args_value[nargs].pa_int; args_size = &args_value[nargs].pa_int;
args_type = &args_size[nargs]; args_type = &args_size[nargs];
memset (args_type, s->_flags2 & _IO_FLAGS2_FORTIFY ? '\xff' : '\0', memset (args_type, s->_flags2 & _IO_FLAGS2_FORTIFY ? '\xff' : '\0',
nargs * sizeof (*args_type)); 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;
} }