vsprintf with string arguments containing '%' character
I'm sure this must have been discussed before here, but I can't find a solution... I have a logging function which take variable args and writes them to a log file and/or console. This has worked fine for ages, but now some string parameters passed in can contain '%' characters which causes the output buffer passed to vsprintf to be corrupted.
Example:
void trace_to_log(char* format, ...)
{
va_list arg_ptr;
char buffer[4096];
va_start (arg_ptr, format);
vsprintf (buffer, format, arg_ptr);
va_end (arg_ptr);
// Write buffer to file and/or console
...
}
void f()
{
trace_to_log("%s", "%40");
}
I know that to print a '%' character it needs to passed in as '%%' but the problem is I don't have control over the many places in the code such a string could be passed in. I need some way of making the logging function safe. Maybe do my own parsing for %s formats and check the input strings and double up any '%' chars? Any advice appreciated.
Thanks
Re: vsprintf with string arguments containing '%' character
Quote:
Originally Posted by
moshady
I'm sure this must have been discussed before here, but I can't find a solution... I have a logging function which take variable args and writes them to a log file and/or console. This has worked fine for ages, but now some string parameters passed in can contain '%' characters which causes the output buffer passed to vsprintf to be corrupted.
That is not the only cause for possible corruption. If the buffer is more than 4,095 characters, you have a memory overwrite. A logging routine has to be fail-safe, and yours is not for several reasons.
I have had this happen to code I had to maintain so many times in my career. A buffer size is guessed to be big enough, and then some logging string is more than that amount, and you have a customer not even able to log anything due to a crash when logging.
Quote:
Maybe do my own parsing for %s formats and check the input strings and double up any '%' chars?
Are you coding in C++? If so, I would suggest you bite the bullet and use ostringstreams, or the boost format class to write to logs. What if your parser has a bug or misses some %s format specifier for some reason? You'll need a logger for the logger.
Here is boost format:
http://www.boost.org/doc/libs/1_47_0...mat/index.html
Regards,
Paul McKenzie
Re: vsprintf with string arguments containing '%' character
The example given by the OP does definitely not do any harm, IMHO. vsprintf only has to scan the format string, not the argument. In this case, it would expect a string and put "%40" into the buffer.
I do agree with Paul that there is another cause for the problem.
Re: vsprintf with string arguments containing '%' character
Quote:
Originally Posted by
Richard.J
The example given by the OP does definitely not do any harm, IMHO. vsprintf only has to scan the format string, not the argument. In this case, it would expect a string and put "%40" into the buffer.
Yes, you're right, unless the user has to also specify the format string along with the argument list.
In that case, the logger has another potential problem -- the one calling the logger has to supply arguments that match the format specifier, or else the program has undefined behaviour. Using vsprintf(), there is no check for arguments, no check for invalid types, etc..
Quote:
I do agree with Paul that there is another cause for the problem.
Probably what I stated above, or a 4095 buffer overrun. The buffer overrun can happen easily if the user has specified %s, and they are passing an array of char that isn't really null-terminated.
In any event, using a fixed buffer size, plus using C-style, non-type safe way to log things will (not maybe, but will) break down at some point.
Regards,
Paul McKenzie
Re: vsprintf with string arguments containing '%' character
I now understand the problem. In trying to simplify things to post here, I over-simplified and lost the problem.
Essentially the problem was that the variadic logging function itself called another variadic function, just passing in the formatted buffer as a single parameter. That function itself called a variant of vsprintf and of course now we have a format string with % chars in it, but no supporting parameters, so it all goes wrong from there.
Just to clear up a point raised above regarding the buffer of 4096 - that was just a simplification in the example code posted. The real code uses either _vscprintf to calculate the buffer size required and/or vsnprintf to limit the number of characters formatted.