Avoid alloca with too large size.
authorBruno Haible <bruno@clisp.org>
Tue, 18 Nov 2003 15:29:47 +0000 (15:29 +0000)
committerBruno Haible <bruno@clisp.org>
Tue, 18 Nov 2003 15:29:47 +0000 (15:29 +0000)
lib/ChangeLog
lib/vasnprintf.c

index 10019b5e0fbfc290941ef0e2c31bbfa06ae252ed..660724800008d312ff042d4fcc9a2d61e14d23e9 100644 (file)
@@ -1,3 +1,10 @@
+2003-11-17  Bruno Haible  <bruno@clisp.org>
+
+       * vasnprintf.c (alloca): Remove fallback definition.
+       (freea): Remove definition.
+       (VASNPRINTF): Use alloca only for small sizes, say <= 4000 bytes.
+       Reported by Paul Eggert.
+
 2003-11-17  Jim Meyering  <jim@meyering.net>
 
        On systems without utime and without a utimes function capable of
index 380170deef91bdb15ace9894f17134242e127c8f..e40994d0c8164229952cda37248b721507098cdc 100644 (file)
 /* Checked size_t computations.  */
 #include "xsize.h"
 
-/* For those losing systems which don't have 'alloca' we have to add
-   some additional code emulating it.  */
-#ifdef HAVE_ALLOCA
-# define freea(p) /* nothing */
-#else
-# define alloca(n) malloc (n)
-# define freea(p) free (p)
-#endif
-
 #ifdef HAVE_WCHAR_T
 # ifdef HAVE_WCSLEN
 #  define local_wcslen wcslen
@@ -139,10 +130,9 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar
     }
 
   {
-    size_t buf_neededlength =
-      xsum4 (7, d.max_width_length, d.max_precision_length, 6);
-    CHAR_T *buf =
-      (CHAR_T *) alloca (xtimes (buf_neededlength, sizeof (CHAR_T)));
+    size_t buf_neededlength;
+    CHAR_T *buf;
+    CHAR_T *buf_malloced;
     const CHAR_T *cp;
     size_t i;
     DIRECTIVE *dp;
@@ -151,6 +141,28 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar
     size_t allocated;
     size_t length;
 
+    /* Allocate a small buffer that will hold a directive passed to
+       sprintf or snprintf.  */
+    buf_neededlength =
+      xsum4 (7, d.max_width_length, d.max_precision_length, 6);
+#if HAVE_ALLOCA
+    if (buf_neededlength < 4000 / sizeof (CHAR_T))
+      {
+       buf = (CHAR_T *) alloca (buf_neededlength * sizeof (CHAR_T));
+       buf_malloced = NULL;
+      }
+    else
+#endif
+      {
+       size_t buf_memsize = xtimes (buf_neededlength, sizeof (CHAR_T));
+       if (size_overflow_p (buf_memsize))
+         goto out_of_memory_1;
+       buf = (CHAR_T *) malloc (buf_memsize);
+       if (buf == NULL)
+         goto out_of_memory_1;
+       buf_malloced = buf;
+      }
+
     if (resultbuf != NULL)
       {
        result = resultbuf;
@@ -788,7 +800,8 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar
                      {
                        if (!(result == resultbuf || result == NULL))
                          free (result);
-                       freea (buf);
+                       if (buf_malloced != NULL)
+                         free (buf_malloced);
                        CLEANUP ();
                        errno = EINVAL;
                        return NULL;
@@ -846,7 +859,8 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar
          result = memory;
       }
 
-    freea (buf);
+    if (buf_malloced != NULL)
+      free (buf_malloced);
     CLEANUP ();
     *lengthp = length;
     return result;
@@ -854,7 +868,9 @@ VASNPRINTF (CHAR_T *resultbuf, size_t *lengthp, const CHAR_T *format, va_list ar
   out_of_memory:
     if (!(result == resultbuf || result == NULL))
       free (result);
-    freea (buf);
+    if (buf_malloced != NULL)
+      free (buf_malloced);
+  out_of_memory_1:
     CLEANUP ();
     errno = ENOMEM;
     return NULL;