This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH] vfprintf: Allocate the user argument buffer on the heap
- From: fweimer at redhat dot com (Florian Weimer)
- To: libc-alpha at sourceware dot org
- Date: Mon, 19 Jun 2017 18:20:16 +0200
- Subject: [PATCH] vfprintf: Allocate the user argument buffer on the heap
- Authentication-results: sourceware.org; auth=none
- Authentication-results: ext-mx02.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com
- Authentication-results: ext-mx02.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=fweimer at redhat dot com
- Dkim-filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 080F080C15
- Dmarc-filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 080F080C15
2017-06-19 Florian Weimer <fweimer@redhat.com>
* stdio-common/vfprintf.c (allocate_user_args_buffer): New
function.
(printf_positional): Call it.
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
index e0c6edf..b15c5d0 100644
--- a/stdio-common/vfprintf.c
+++ b/stdio-common/vfprintf.c
@@ -1618,6 +1618,26 @@ do_positional:
return done;
}
+
+
+/* Called from printf_positional to determine the size of the user
+ argument area and allocate it, after discovering that one is
+ needed. This function returns NULL on allocation failure. */
+static void *
+allocate_user_args_buffer (size_t nargs, const int *args_size,
+ const int *args_type)
+{
+ assert (__printf_va_arg_table != NULL);
+ size_t size = 0;
+ for (size_t i = 0; i < nargs; ++i)
+ if ((args_type[i] & PA_FLAG_MASK) == 0
+ && args_type[i] >= PA_LAST
+ && __printf_va_arg_table[args_type[i] - PA_LAST] != NULL)
+ size += roundup (args_size[i], _Alignof (max_align_t));
+ assert (size > 0);
+ return malloc (size);
+}
+
static int
printf_positional (_IO_FILE *s, const CHAR_T *format, int readonly_format,
va_list ap, va_list *ap_savep, int done, int nspecs_done,
@@ -1636,6 +1656,12 @@ printf_positional (_IO_FILE *s, const CHAR_T *format, int readonly_format,
struct scratch_buffer argsbuf;
scratch_buffer_init (&argsbuf);
+ /* Allocation area for user argument data. Lazily allocated by
+ allocate_user_args_buffer. */
+ void *user_args_buffer = NULL;
+ /* Upcoming allocation within user_args_buffer. */
+ void *user_args_buffer_next = NULL;
+
/* Array with information about the needed arguments. This has to
be dynamically extensible. */
size_t nspecs = 0;
@@ -1796,7 +1822,34 @@ printf_positional (_IO_FILE *s, const CHAR_T *format, int readonly_format,
else if (__glibc_unlikely (__printf_va_arg_table != NULL)
&& __printf_va_arg_table[args_type[cnt] - PA_LAST] != NULL)
{
- args_value[cnt].pa_user = alloca (args_size[cnt]);
+ /* Allocate from user_args_buffer. */
+ size_t allocation_size = args_size[cnt];
+ void *allocation;
+ if (allocation_size == 0)
+ /* Nothing to allocate. */
+ allocation = NULL;
+ else
+ {
+ if (user_args_buffer == NULL)
+ {
+ /* First user argument. Allocate the complete
+ buffer. */
+ user_args_buffer = allocate_user_args_buffer
+ (nargs, args_size, args_type);
+ if (user_args_buffer == NULL)
+ {
+ done = -1;
+ goto all_done;
+ }
+ user_args_buffer_next = user_args_buffer;
+ }
+ allocation = user_args_buffer_next;
+ user_args_buffer_next
+ += roundup (allocation_size, _Alignof (max_align_t));
+ }
+ /* Install the allocated pointer and use the callback to
+ extract the argument. */
+ args_value[cnt].pa_user = allocation;
(*__printf_va_arg_table[args_type[cnt] - PA_LAST])
(args_value[cnt].pa_user, ap_savep);
}
@@ -1953,6 +2006,7 @@ printf_positional (_IO_FILE *s, const CHAR_T *format, int readonly_format,
- specs[nspecs_done].end_of_fmt);
}
all_done:
+ free (user_args_buffer);
scratch_buffer_free (&argsbuf);
scratch_buffer_free (&specsbuf);
return done;