From patchwork Mon Jun 19 16:20:16 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 21105 Received: (qmail 88584 invoked by alias); 19 Jun 2017 16:20:16 -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 88552 invoked by uid 89); 19 Jun 2017 16:20:15 -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=discovering, Upcoming, Hx-languages-length:3049 X-HELO: mx1.redhat.com DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 080F080C15 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@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 080F080C15 Date: Mon, 19 Jun 2017 18:20:16 +0200 To: libc-alpha@sourceware.org Subject: [PATCH] vfprintf: Allocate the user argument buffer on the heap User-Agent: Heirloom mailx 12.5 7/5/10 MIME-Version: 1.0 Message-Id: <20170619162016.3F506402AEC0E@oldenburg.str.redhat.com> From: fweimer@redhat.com (Florian Weimer) 2017-06-19 Florian Weimer * 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;