From 980dab90282ab3ca63ac44b174344a6607934fb9 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sat, 20 Jun 2009 14:53:30 +0000 Subject: 2.5: fix for crash in BLI_dynstr_appendf, each vsnprintf call apparently needs its own va_start/va_end. --- source/blender/blenlib/intern/BLI_dynstr.c | 52 +++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 4 deletions(-) (limited to 'source/blender/blenlib') diff --git a/source/blender/blenlib/intern/BLI_dynstr.c b/source/blender/blenlib/intern/BLI_dynstr.c index 04388ea946f..dd10d898a7f 100644 --- a/source/blender/blenlib/intern/BLI_dynstr.c +++ b/source/blender/blenlib/intern/BLI_dynstr.c @@ -92,7 +92,7 @@ void BLI_dynstr_vappendf(DynStr *ds, const char *format, va_list args) if(len == sizeof(fixedmessage)) message= fixedmessage; else - message= MEM_callocN(sizeof(char)*len+1, "BLI_dynstr_appendf"); + message= MEM_callocN(sizeof(char)*(len+1), "BLI_dynstr_appendf"); retval= vsnprintf(message, len, format, args); @@ -132,10 +132,54 @@ void BLI_dynstr_vappendf(DynStr *ds, const char *format, va_list args) void BLI_dynstr_appendf(DynStr *ds, const char *format, ...) { va_list args; + char *message, fixedmessage[256]; + int len= 256, maxlen= 65536, retval; + + /* note that it's tempting to just call BLI_dynstr_vappendf here + * and avoid code duplication, that crashes on some system because + * va_start/va_end have to be called for each vsnprintf call */ - va_start(args, format); - BLI_dynstr_vappendf(ds, format, args); - va_end(args); + while(1) { + if(len == sizeof(fixedmessage)) + message= fixedmessage; + else + message= MEM_callocN(sizeof(char)*(len+1), "BLI_dynstr_appendf"); + + va_start(args, format); + retval= vsnprintf(message, len, format, args); + va_end(args); + + if(retval == -1) { + /* -1 means not enough space, but on windows it may also mean + * there is a formatting error, so we impose a maximum length */ + if(message != fixedmessage) + MEM_freeN(message); + message= NULL; + + len *= 2; + if(len > maxlen) { + fprintf(stderr, "BLI_dynstr_append text too long or format error.\n"); + break; + } + } + else if(retval > len) { + /* in C99 the actual length required is returned */ + if(message != fixedmessage) + MEM_freeN(message); + message= NULL; + + len= retval; + } + else + break; + } + + if(message) { + BLI_dynstr_append(ds, message); + + if(message != fixedmessage) + MEM_freeN(message); + } } int BLI_dynstr_get_len(DynStr *ds) { -- cgit v1.2.3