9

In the application that I am working on, the logging facility makes use of sprintf to format the text that gets written to file. So, something like:

char buffer[512];
sprintf(buffer, ... );

This sometimes causes problems when the message that gets sent in becomes too big for the manually allocated buffer.

Is there a way to get sprintf behaviour without having to manually allocate memory like this?

EDIT: while sprintf is a C operation, I'm looking for C++ type solutions (if there are any!) for me to get this sort of behaviour...

5 Answers 5

18

You can use asprintf(3) (note: non-standard) which allocates the buffer for you so you don't need to pre-allocate it.

Sign up to request clarification or add additional context in comments.

3 Comments

Please mention availability of this function for different systems, because it is neither standard C lib nor POSIX.
It is Linux mainly - probably BSD too. There is a vasprintf() too.
Oh yeah, sorry about that... the OP didn't mention which platform so I just threw it out there. It's found on Linux, BSD and Mac OS X... it's a standard part of the gnuc library now.
11

No you can't use sprintf() to allocate enough memory. Alternatives include:

  • use snprintf() to truncate the message - does not fully resolve your problem, but prevent the buffer overflow issue
  • double (or triple or ...) the buffer - unless you're in a constrained environment
  • use C++ std::string and ostringstream - but you'll lose the printf format, you'll have to use the << operator
  • use Boost Format that comes with a printf-like % operator

2 Comments

Note that snprintf() tells you how much space you needed, so you could use it twice if need be, the first time with a static buffer as shown, and the second time with a dynamically allocated buffer.
-1 for the second suggestion (doubling the buffer size. Since you do not know the maximum string length, you cannot guarantee it won't overflow, even if you multiply it by a billion.)
5

I dont also know a version wich avoids allocation, but if C99 sprintfs allows as string the NULL pointer. Not very efficient, but this would give you the complete string (as long as enough memory is available) without risking overflow:

length = snprintf(NULL, ...);
str = malloc(length+1);
snprintf(str, ...);

2 Comments

If you're using C99, you can also just use a variable-length array, so instead of mallocing str, just declare it as "char str[length+1];" after the call to snprintf. No need to deallocate it then, as it's on the stack.
If you're using the MSVC runtime, you'll find that snprintf returns a negative value instead of the required length. so, if you want the required length under MSVC, you'll need to use a different function, _vscprintf [msdn.microsoft.com/en-us/library/w05tbk72.aspx]
3

"the logging facility makes use of sprintf to format the text that gets written to file"

fprintf() does not impose any size limit. If you can write the text directly to file, do so!

I assume there is some intermediate processing step, however. If you know how much space you need, you can use malloc() to allocate that much space.

One technique at times like these is to allocate a reasonable-size buffer (that will be large enough 99% of the time) and if it's not big enough, break the data into chunks that you process one by one.

2 Comments

file access is way slower than memory access. That's one reason why an intermediate sprintf isn't a bad idea.
You can get most of that benefit by buffering the file, where available. There's still call overhead but at least you aren't hitting disk.
1

With the vanilla version of sprintf, there is no way to prevent the data from overwriting the passed in buffer. This is true regardless of wether the memory was manually allocated or allocated on the stack.

In order to prevent the buffer from being overwritten you'll need to use one of the more secure versions of sprintf like sprintf_s (windows only)

http://msdn.microsoft.com/en-us/library/ybk95axf.aspx

1 Comment

It is possible to guard against buffer overflows with vanilla sprintf(), e.g. sprintf(buf, "%.*s", buf_size - 1, input_string); But this only works for known, fixed format strings.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.