summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Linus Torvalds <torvalds@linux-foundation.org>2014-03-08 15:54:50 -0800
committerGravatar Dirk Hohndel <dirk@hohndel.org>2014-03-08 16:32:31 -0800
commit989c8f011011aaa2167a7c04ad309030d282e1da (patch)
tree586d9a1b2dacad363b0fdb1c844da8d1743b0bae
parentcc3a184adfcf08744de1caf930430300656349a2 (diff)
downloadsubsurface-989c8f011011aaa2167a7c04ad309030d282e1da.tar.gz
Fix totally broken put_vformat() implementation
I'm ashamed. put_vbuffer() worked perfectly fine for the normal case when everything fit in our simple buffer on-stack, but the fallback case was broken in so many ways that I'm just going to go sit in a corner and cry myself to sleep. And dammit, I _knew_ how to do it right. I knew you had to do a "va_copy()" and couldn't just keep re-using 'args'. I've done this before. But I half-arsed it, and nobody ever noticed, because you wouldn't do C style format strings for big strings. "128 bytes is enough for everybody". And as penance for this idiocy, I just spent too much time trying to figure out what was wrong in my git loading code when my debug printouts caused SIGSEGV's. Sigh. Anyway, now it should hopefully be correct, and the code is smarter about things too, not having that extra buffer since we already *have* a buffer in the "struct membuffer" we are working with. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
-rw-r--r--membuffer.c34
1 files changed, 21 insertions, 13 deletions
diff --git a/membuffer.c b/membuffer.c
index a222af60b..9d3167293 100644
--- a/membuffer.c
+++ b/membuffer.c
@@ -76,20 +76,28 @@ void put_string(struct membuffer *b, const char *str)
void put_vformat(struct membuffer *b, const char *fmt, va_list args)
{
- /* Handle the common case on the stack */
- char buffer[128], *p;
- int len;
-
- len = vsnprintf(buffer, sizeof(buffer), fmt, args);
- if (len <= sizeof(buffer)) {
- put_bytes(b, buffer, len);
- return;
- }
+ int room = 128;
+
+ for (;;) {
+ int len;
+ va_list copy;
+ char *target;
+
+ make_room(b, room);
+ room = b->alloc - b->len;
+ target = b->buffer + b->len;
- p = malloc(len);
- len = vsnprintf(p, len, fmt, args);
- put_bytes(b, p, len);
- free(p);
+ va_copy(copy, args);
+ len = vsnprintf(target, room, fmt, copy);
+ va_end(copy);
+
+ if (len < room) {
+ b->len += len;
+ return;
+ }
+
+ room = len+1;
+ }
}
void put_format(struct membuffer *b, const char *fmt, ...)