C++Snippets
Jump to navigation
Jump to search
String formatting without buffer overrun
This is a complete small program that shows how to allocate a string buffer with the correct size so that a C string formatting routine like sprintf
can be used without the fear of a buffer overrun.
The example is mainly useful in a C environment - in C++ you should use stringstream
instead of string formatting.
#include <sstream> // for std::stringstream #include <cstdarg> // for variable arguments stuff #include <cstddef> // for nullptr #include <iostream> // for std::cout // ---------------------------------------------------------------------- std::stringstream messageStream(""); // ---------------------------------------------------------------------- // Caller must pass a va_list parameter that has been initialized with // va_start(), and caller must clean up the va_list parameter with va_end(). // This function modifies the va_list parameter. void WriteFormattedStringToStringStreamArglist(const char* formatString, va_list arglist) { // Perform a "probing" call to vsnprintf(). We do this so that the function // tells us how long the resulting string would have been, so that we can // allocate a buffer of the correct length. For this we need a copy of // arglist, the copy must be made while the original arglist is still in // its initialized state. va_list arglistCopy; va_copy(arglistCopy, arglist); int lengthOfFormattedStringWithoutNullTerminator = vsnprintf(nullptr, 0, formatString, arglistCopy); va_end(arglistCopy); if (lengthOfFormattedStringWithoutNullTerminator >= 0) { size_t bufferSize = lengthOfFormattedStringWithoutNullTerminator + 1; char formattedStringBuffer[bufferSize]; // No need to call va_start/va-end - that's the responsibility of the caller vsnprintf(formattedStringBuffer, bufferSize, formatString, arglist); messageStream << formattedStringBuffer; } else { messageStream << "WriteFormattedStringToStringStreamArglist error: vsnprintf encountered encoding error, return value was " << lengthOfFormattedStringWithoutNullTerminator; } } // ---------------------------------------------------------------------- void WriteFormattedStringToStringStream(const char* formatString, ...) { va_list arglist; va_start(arglist, formatString); WriteFormattedStringToStringStreamArglist(formatString, arglist); va_end(arglist); } // ---------------------------------------------------------------------- int main(int argc, char** argv) { const char* formatString = "Hello %s"; const char* valueString = "world"; WriteFormattedStringToStringStream(formatString, valueString); std::cout << messageStream.str() << std::endl; }