This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] vfprintf: Allocate the user argument buffer on the heap


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;


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]