From: Christoph Mallon Date: Tue, 4 May 2010 11:53:26 +0000 (+0000) Subject: Fix obstack_printf() (slightly broken in r27474). X-Git-Url: http://nsz.repo.hu/git/?a=commitdiff_plain;h=53c740e61018fc1172d2c290a486251efd4e906b;p=libfirm Fix obstack_printf() (slightly broken in r27474). [r27476] --- diff --git a/ir/obstack/obstack_printf.c b/ir/obstack/obstack_printf.c index 1b432e2ec..ab494bb99 100644 --- a/ir/obstack/obstack_printf.c +++ b/ir/obstack/obstack_printf.c @@ -9,42 +9,40 @@ int obstack_printf(struct obstack *obst, const char *fmt, ...) { - char buf[128]; - char *buffer = buf; + char buf[128]; + char *buffer = buf; + size_t size = lengthof(buf); va_list ap; - int len; + int len; - 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; - - va_start(ap, fmt); - len = vsnprintf(buffer, size, fmt, ap); - va_end(ap); + for (;;) { + va_start(ap, fmt); + len = vsnprintf(buffer, sizeof(buffer), 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); + /* 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 (buffer != buf) + free(buffer); + if (size > 65536) + return -1; + size *= 2; + } else if ((size_t)len >= size) { + /* If we come here more than once, vsnprintf() returned garbage */ + assert(buffer == buf); + size = (size_t)len + 1; + } else { + break; + } + buffer = malloc(buffer, size); } + obstack_grow(obst, buffer, len); + if (buffer != buf) + free(buffer); return len; }