From a928bbfaac6e790ebd33bb804fa54b78ed052b10 Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Wed, 24 Jun 2015 15:53:03 +0200 Subject: [PATCH] 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. --- common/richio.cpp | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/common/richio.cpp b/common/richio.cpp index 344becbbff..286825a81f 100644 --- a/common/richio.cpp +++ b/common/richio.cpp @@ -3,7 +3,7 @@ * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2007-2011 SoftPLC Corporation, Dick Hollenbeck - * 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 * 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 ) { 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 ); 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. - len = vsnprintf( &buf[0], len+1, format, ap ); + len = vsnprintf( &buf[0], len+1, format, tmp ); result->append( &buf[0], &buf[0] + len ); } + va_end( tmp ); // Release the temporary va_list, initialised from ap + 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 ) { + // 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 ); + if( ret >= (int) buffer.size() ) { - buffer.resize( ret + 2000 ); - ret = vsnprintf( &buffer[0], buffer.size(), fmt, ap ); + buffer.resize( ret + 1000 ); + ret = vsnprintf( &buffer[0], buffer.size(), fmt, tmp ); } + va_end( tmp ); // Release the temporary va_list, initialised from ap + if( ret > 0 ) write( &buffer[0], ret );