changeset 4879:9b96adbed643

Avoid alloca with too large size.
author Bruno Haible <bruno@clisp.org>
date Tue, 18 Nov 2003 15:29:47 +0000
parents 21a917d42540
children d838b442a64a
files lib/ChangeLog lib/vasnprintf.c
diffstat 2 files changed, 39 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/lib/ChangeLog
+++ b/lib/ChangeLog
@@ -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
--- a/lib/vasnprintf.c
+++ b/lib/vasnprintf.c
@@ -51,15 +51,6 @@
 /* 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 @@
     }
 
   {
-    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 @@
     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 @@
 		      {
 			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 @@
 	  result = memory;
       }
 
-    freea (buf);
+    if (buf_malloced != NULL)
+      free (buf_malloced);
     CLEANUP ();
     *lengthp = length;
     return result;
@@ -854,7 +868,9 @@
   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;