tags:

views:

1535

answers:

5

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...

+3  A: 

"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.

Artelius
file access is way slower than memory access. That's one reason why an intermediate sprintf isn't a bad idea.
xtofl
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.
Steve Jessop
+1  A: 

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

JaredPar
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.
finnw
+10  A: 

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
philippe
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.
Jonathan Leffler
-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.)
finnw
+16  A: 

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

Jason Coco
Upvoted - asprintf() is handy if your system has it.
Sherm Pendley
Please mention availability of this function for different systems, because it is neither standard C lib nor POSIX.
qrdl
It is Linux mainly - probably BSD too. There is a vasprintf() too.
Jonathan Leffler
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.
Jason Coco
+3  A: 

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, ...);
flolo
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.
Ben Combee
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 [http://msdn.microsoft.com/en-us/library/w05tbk72.aspx]
Hasturkun