From patchwork Mon Jun 19 16:22:42 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 21108 Received: (qmail 98465 invoked by alias); 19 Jun 2017 16:22:43 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 98220 invoked by uid 89); 19 Jun 2017 16:22:42 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, SPF_HELO_PASS, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 spammy= X-HELO: mx1.redhat.com DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 26D9C23E6CE Authentication-Results: ext-mx05.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx05.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=fweimer@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 26D9C23E6CE Date: Mon, 19 Jun 2017 18:22:42 +0200 To: libc-alpha@sourceware.org Subject: [PATCH] vfprintf: Avoid alloca for user-defined format specifier arguments User-Agent: Heirloom mailx 12.5 7/5/10 MIME-Version: 1.0 Message-Id: <20170619162242.63523402AEC3C@oldenburg.str.redhat.com> From: fweimer@redhat.com (Florian Weimer) 2017-06-19 Florian Weimer * stdio-common/vfprintf.c (struct spec_data_args): Define using dynarray. (printf_positional): Use struct spec_data_args instead of alloca. diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c index d58f0ea..0a5e541 100644 --- a/stdio-common/vfprintf.c +++ b/stdio-common/vfprintf.c @@ -1680,6 +1680,15 @@ allocate_user_args_buffer (size_t nargs, const int *args_size, return malloc (size); } +/* Array for storing argument pointers for user-defined format + specifiers. Most user-defined specifiers use a single argument + only, so we override the initial allocation size. */ +#define DYNARRAY_STRUCT spec_data_args +#define DYNARRAY_ELEMENT const void * +#define DYNARRAY_PREFIX spec_data_args_ +#define DYNARRAY_INITIAL_SIZE 2 +#include + 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, @@ -1693,6 +1702,11 @@ printf_positional (_IO_FILE *s, const CHAR_T *format, int readonly_format, struct printf_spec *specs = specsbuf.data; size_t specs_limit = specsbuf.length / sizeof (specs[0]); + /* Pointer argument array, for passing to format specifier + callbacks. */ + struct spec_data_args spec_data_args; + spec_data_args_init (&spec_data_args); + /* Used as a backing store for args_value, args_size, args_type below. */ struct scratch_buffer argsbuf; @@ -1979,17 +1993,24 @@ printf_positional (_IO_FILE *s, const CHAR_T *format, int readonly_format, && __printf_function_table != NULL && __printf_function_table[(size_t) spec] != NULL) { - const void **ptr = alloca (specs[nspecs_done].ndata_args - * sizeof (const void *)); + if (!spec_data_args_resize (&spec_data_args, + specs[nspecs_done].ndata_args)) + { + __set_errno (ENOMEM); + done = -1; + goto all_done; + } /* Fill in an array of pointers to the argument values. */ for (unsigned int i = 0; i < specs[nspecs_done].ndata_args; ++i) - ptr[i] = &args_value[specs[nspecs_done].data_arg + i]; + *spec_data_args_at (&spec_data_args, i) = + &args_value[specs[nspecs_done].data_arg + i]; /* Call the function. */ function_done = __printf_function_table[(size_t) spec] - (s, &specs[nspecs_done].info, ptr); + (s, &specs[nspecs_done].info, + spec_data_args_begin (&spec_data_args)); if (function_done != -2) { @@ -2051,6 +2072,7 @@ printf_positional (_IO_FILE *s, const CHAR_T *format, int readonly_format, free (user_args_buffer); scratch_buffer_free (&argsbuf); scratch_buffer_free (&specsbuf); + spec_data_args_free (&spec_data_args); return done; }