Fix issue in richio.cpp, when printing strings with a size > 500 chars.

This was due to an use of twice the same va_list by 2 calls to vsnprintf, but the first call can change the va_list.
This commit is contained in:
jean-pierre charras 2015-06-24 15:53:03 +02:00
parent a8bffb862c
commit a928bbfaac
1 changed files with 24 additions and 4 deletions

View File

@ -3,7 +3,7 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2007-2011 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com> * Copyright (C) 2007-2011 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2007 KiCad Developers, see change_log.txt for contributors. * Copyright (C) 2015 KiCad Developers, see change_log.txt for contributors.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -43,6 +43,14 @@
static int vprint( std::string* result, const char* format, va_list ap ) static int vprint( std::string* result, const char* format, va_list ap )
{ {
char msg[512]; char msg[512];
// This function can call vsnprintf twice.
// But internally, vsnprintf retrieves arguments from the va_list identified by arg as if
// va_arg was used on it, and thus the state of the va_list is likely to be altered by the call.
// see: www.cplusplus.com/reference/cstdio/vsnprintf
// we make a copy of va_list ap for the second call, if happens
va_list tmp;
va_copy( tmp, ap );
size_t len = vsnprintf( msg, sizeof(msg), format, ap ); size_t len = vsnprintf( msg, sizeof(msg), format, ap );
if( len < sizeof(msg) ) // the output fit into msg if( len < sizeof(msg) ) // the output fit into msg
@ -58,11 +66,13 @@ static int vprint( std::string* result, const char* format, va_list ap )
buf.reserve( len+1 ); // reserve(), not resize() which writes. +1 for trailing nul. buf.reserve( len+1 ); // reserve(), not resize() which writes. +1 for trailing nul.
len = vsnprintf( &buf[0], len+1, format, ap ); len = vsnprintf( &buf[0], len+1, format, tmp );
result->append( &buf[0], &buf[0] + len ); result->append( &buf[0], &buf[0] + len );
} }
va_end( tmp ); // Release the temporary va_list, initialised from ap
return len; return len;
} }
@ -397,13 +407,23 @@ const char* OUTPUTFORMATTER::GetQuoteChar( const char* wrapee )
int OUTPUTFORMATTER::vprint( const char* fmt, va_list ap ) throw( IO_ERROR ) int OUTPUTFORMATTER::vprint( const char* fmt, va_list ap ) throw( IO_ERROR )
{ {
// This function can call vsnprintf twice.
// But internally, vsnprintf retrieves arguments from the va_list identified by arg as if
// va_arg was used on it, and thus the state of the va_list is likely to be altered by the call.
// see: www.cplusplus.com/reference/cstdio/vsnprintf
// we make a copy of va_list ap for the second call, if happens
va_list tmp;
va_copy( tmp, ap );
int ret = vsnprintf( &buffer[0], buffer.size(), fmt, ap ); int ret = vsnprintf( &buffer[0], buffer.size(), fmt, ap );
if( ret >= (int) buffer.size() ) if( ret >= (int) buffer.size() )
{ {
buffer.resize( ret + 2000 ); buffer.resize( ret + 1000 );
ret = vsnprintf( &buffer[0], buffer.size(), fmt, ap ); ret = vsnprintf( &buffer[0], buffer.size(), fmt, tmp );
} }
va_end( tmp ); // Release the temporary va_list, initialised from ap
if( ret > 0 ) if( ret > 0 )
write( &buffer[0], ret ); write( &buffer[0], ret );