fix obstack printf being limited to 1024 bytes
authorMatthias Braun <matze@braunis.de>
Tue, 4 May 2010 10:30:06 +0000 (10:30 +0000)
committerMatthias Braun <matze@braunis.de>
Tue, 4 May 2010 10:30:06 +0000 (10:30 +0000)
[r27474]

ir/obstack/obstack_printf.c

index 65f06dc..1b432e2 100644 (file)
@@ -1,5 +1,6 @@
 #include <stdarg.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include "obstack.h"
 
 #ifdef _WIN32
@@ -8,14 +9,42 @@
 
 int obstack_printf(struct obstack *obst, const char *fmt, ...)
 {
-  char buf[1024];
-  va_list ap;
-  int len;
+       char  buf[128];
+       char *buffer = buf;
+       va_list ap;
+       int len;
 
-  va_start(ap, fmt);
-  len = vsnprintf(buf, sizeof(buf), fmt, ap);
-  obstack_grow(obst, buf, len);
-  va_end(ap);
+       va_start(ap, fmt);
+       len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
+       va_end(ap);
+       if (len < 0 || len >= (int) sizeof(buffer)) {
+               size_t size   = len >= 0 ? (size_t) len : sizeof(buffer) * 2;
+               char  *buffer = malloc(size);
+               do {
+                       if (buffer == NULL)
+                               return -1;
 
-  return len;
+                       va_start(ap, fmt);
+                       len = vsnprintf(buffer, size, fmt, ap);
+                       va_end(ap);
+
+                       /* snprintf should return -1 only in the error case, but older
+                        * glibcs and probably other systems are buggy in this respect and
+                        * return -1 if the buffer was too small. We only abort for LARGE
+                        * unrealistic buffer sizes here */
+                       if (len < 0) {
+                               if (size > 65536)
+                                       return -1;
+                               size *= 2;
+                               buffer = realloc(buffer, size);
+                       } else if (len >= (int) size) {
+                               /* this should not happen if snprintf works correctly */
+                               abort();
+                       }
+               } while (len < 0);
+               free(buffer);
+       }
+       obstack_grow(obst, buffer, len);
+
+       return len;
 }