vasnprintf: Reduce use of malloc for small format strings.
authorBruno Haible <bruno@clisp.org>
Fri, 4 Feb 2011 18:22:43 +0000 (19:22 +0100)
committerBruno Haible <bruno@clisp.org>
Fri, 4 Feb 2011 18:22:43 +0000 (19:22 +0100)
* lib/printf-args.h (N_DIRECT_ALLOC_ARGUMENTS): New macro.
(arguments): Add room for the first 7 arguments.
* lib/printf-parse.h (N_DIRECT_ALLOC_DIRECTIVES): New macro.
(char_directives, u8_directives, u16_directives, u32_directives): Add
room for the first 7 directives.
* lib/printf-parse.c: Include <string.h>.
(PRINTF_PARSE): Change memory handling code so that it uses the first
7 preallocated elements in an 'arguments' or 'DIRECTIVES' struct.
* lib/vasnprintf.c (VASNPRINTF): Update memory handling code.
Reported by Pádraig Brady <P@draigbrady.com>.

ChangeLog
lib/printf-args.h
lib/printf-parse.c
lib/printf-parse.h
lib/vasnprintf.c

index b0254540a6f5edce3a09dec637e3b61e68580d19..9d9038edeff878df5036ebd3739c61d145aa6c19 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2011-02-04  Bruno Haible  <bruno@clisp.org>
+
+       vasnprintf: Reduce use of malloc for small format strings.
+       * lib/printf-args.h (N_DIRECT_ALLOC_ARGUMENTS): New macro.
+       (arguments): Add room for the first 7 arguments.
+       * lib/printf-parse.h (N_DIRECT_ALLOC_DIRECTIVES): New macro.
+       (char_directives, u8_directives, u16_directives, u32_directives): Add
+       room for the first 7 directives.
+       * lib/printf-parse.c: Include <string.h>.
+       (PRINTF_PARSE): Change memory handling code so that it uses the first
+       7 preallocated elements in an 'arguments' or 'DIRECTIVES' struct.
+       * lib/vasnprintf.c (VASNPRINTF): Update memory handling code.
+       Reported by Pádraig Brady <P@draigbrady.com>.
+
 2011-01-31  Eric Blake  <eblake@redhat.com>
 
        dup2: work around Haiku bug
index cf9bb8173c3d06f66a2b2c2f3ecc01f4c71db379..e03eb6e78aee67a6edbf60e5568ccce65182cd36 100644 (file)
@@ -1,5 +1,5 @@
 /* Decomposed printf argument list.
-   Copyright (C) 1999, 2002-2003, 2006-2007, 2009-2011 Free Software
+   Copyright (C) 1999, 2002-2003, 2006-2007, 2011 Free Software
    Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
@@ -136,10 +136,14 @@ typedef struct
 }
 argument;
 
+/* Number of directly allocated arguments (no malloc() needed).  */
+#define N_DIRECT_ALLOC_ARGUMENTS 7
+
 typedef struct
 {
   size_t count;
   argument *arg;
+  argument direct_alloc_arg[N_DIRECT_ALLOC_ARGUMENTS];
 }
 arguments;
 
index e44a8b2321a5eaaa8c195278a66bc318628e7782..c4e1d37bf513fb552c38b688c6f698e68b9f678c 100644 (file)
@@ -63,6 +63,9 @@
 /* malloc(), realloc(), free().  */
 #include <stdlib.h>
 
+/* memcpy().  */
+#include <string.h>
+
 /* errno.  */
 #include <errno.h>
 
@@ -80,23 +83,20 @@ STATIC
 int
 PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
 {
-  const CHAR_T *cp = format;            /* pointer into format */
+  const CHAR_T *cp = format;    /* pointer into format */
   size_t arg_posn = 0;          /* number of regular arguments consumed */
-  size_t d_allocated;                   /* allocated elements of d->dir */
-  size_t a_allocated;                   /* allocated elements of a->arg */
+  size_t d_allocated;           /* allocated elements of d->dir */
+  size_t a_allocated;           /* allocated elements of a->arg */
   size_t max_width_length = 0;
   size_t max_precision_length = 0;
 
   d->count = 0;
-  d_allocated = 1;
-  d->dir = (DIRECTIVE *) malloc (d_allocated * sizeof (DIRECTIVE));
-  if (d->dir == NULL)
-    /* Out of memory.  */
-    goto out_of_memory_1;
+  d_allocated = N_DIRECT_ALLOC_DIRECTIVES;
+  d->dir = d->direct_alloc_dir;
 
   a->count = 0;
-  a_allocated = 0;
-  a->arg = NULL;
+  a_allocated = N_DIRECT_ALLOC_ARGUMENTS;
+  a->arg = a->direct_alloc_arg;
 
 #define REGISTER_ARG(_index_,_type_) \
   {                                                                     \
@@ -113,12 +113,14 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
         if (size_overflow_p (memory_size))                              \
           /* Overflow, would lead to out of memory.  */                 \
           goto out_of_memory;                                           \
-        memory = (argument *) (a->arg                                   \
+        memory = (argument *) (a->arg != a->direct_alloc_arg            \
                                ? realloc (a->arg, memory_size)          \
                                : malloc (memory_size));                 \
         if (memory == NULL)                                             \
           /* Out of memory.  */                                         \
           goto out_of_memory;                                           \
+        if (a->arg == a->direct_alloc_arg)                              \
+          memcpy (memory, a->arg, a->count * sizeof (argument));        \
         a->arg = memory;                                                \
       }                                                                 \
     while (a->count <= n)                                               \
@@ -588,10 +590,14 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
               if (size_overflow_p (memory_size))
                 /* Overflow, would lead to out of memory.  */
                 goto out_of_memory;
-              memory = (DIRECTIVE *) realloc (d->dir, memory_size);
+              memory = (DIRECTIVE *) (d->dir != d->direct_alloc_dir
+                                      ? realloc (d->dir, memory_size)
+                                      : malloc (memory_size));
               if (memory == NULL)
                 /* Out of memory.  */
                 goto out_of_memory;
+              if (d->dir == d->direct_alloc_dir)
+                memcpy (memory, d->dir, d->count * sizeof (DIRECTIVE));
               d->dir = memory;
             }
         }
@@ -610,19 +616,18 @@ PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
   return 0;
 
 error:
-  if (a->arg)
+  if (a->arg != a->direct_alloc_arg)
     free (a->arg);
-  if (d->dir)
+  if (d->dir != d->direct_alloc_dir)
     free (d->dir);
   errno = EINVAL;
   return -1;
 
 out_of_memory:
-  if (a->arg)
+  if (a->arg != a->direct_alloc_arg)
     free (a->arg);
-  if (d->dir)
+  if (d->dir != d->direct_alloc_dir)
     free (d->dir);
-out_of_memory_1:
   errno = ENOMEM;
   return -1;
 }
index bb16df2d081ec891a85ece7897d0a5c745b60a0a..c819f944ab53ae6a6507314882f5bcd5c0307590 100644 (file)
@@ -1,5 +1,5 @@
 /* Parse printf format string.
-   Copyright (C) 1999, 2002-2003, 2005, 2007, 2009-2011 Free Software
+   Copyright (C) 1999, 2002-2003, 2005, 2007, 2010-2011 Free Software
    Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
@@ -47,6 +47,9 @@
 /* xxx_directive: A parsed directive.
    xxx_directives: A parsed format string.  */
 
+/* Number of directly allocated directives (no malloc() needed).  */
+#define N_DIRECT_ALLOC_DIRECTIVES 7
+
 /* A parsed directive.  */
 typedef struct
 {
@@ -71,6 +74,7 @@ typedef struct
   char_directive *dir;
   size_t max_width_length;
   size_t max_precision_length;
+  char_directive direct_alloc_dir[N_DIRECT_ALLOC_DIRECTIVES];
 }
 char_directives;
 
@@ -100,6 +104,7 @@ typedef struct
   u8_directive *dir;
   size_t max_width_length;
   size_t max_precision_length;
+  u8_directive direct_alloc_dir[N_DIRECT_ALLOC_DIRECTIVES];
 }
 u8_directives;
 
@@ -127,6 +132,7 @@ typedef struct
   u16_directive *dir;
   size_t max_width_length;
   size_t max_precision_length;
+  u16_directive direct_alloc_dir[N_DIRECT_ALLOC_DIRECTIVES];
 }
 u16_directives;
 
@@ -154,6 +160,7 @@ typedef struct
   u32_directive *dir;
   size_t max_width_length;
   size_t max_precision_length;
+  u32_directive direct_alloc_dir[N_DIRECT_ALLOC_DIRECTIVES];
 }
 u32_directives;
 
index 13b60c44a037cbbe1b108b43d0469153eb598fdc..8f07308781530bb94a8b474ecfa0990d354cf9a8 100644 (file)
@@ -1753,8 +1753,9 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
     return NULL;
 
 #define CLEANUP() \
-  free (d.dir);                                                         \
-  if (a.arg)                                                            \
+  if (d.dir != d.direct_alloc_dir)                                      \
+    free (d.dir);                                                       \
+  if (a.arg != a.direct_alloc_arg)                                      \
     free (a.arg);
 
   if (PRINTF_FETCHARGS (args, &a) < 0)