views:

2268

answers:

6

The following code causes an error and kills my application. It makes sense as the buffer is only 10 bytes long and the text is 22 bytes long (buffer overflow).

char buffer[10];    
int length = sprintf_s( buffer, 10, "1234567890.1234567890." );

How do I catch this error so I can report it instead of crashing my application?

Edit:

After reading the comments below I went with _snprintf_s. If it returns a -1 value then the buffer was not updated.

length = _snprintf_s( buffer, 10, 9, "123456789" );
printf( "1) Length=%d\n", length ); // Length == 9

length = _snprintf_s( buffer, 10, 9, "1234567890.1234567890." );
printf( "2) Length=%d\n", length ); // Length == -1

length = _snprintf_s( buffer, 10, 10, "1234567890.1234567890." );
printf( "3) Length=%d\n", length ); // Crash, it needs room for the NULL char
A: 

I wonder if the numbers in your string are confusing the function thinking it's a format string. What happens if you do (buffer, 10, "%s", "1234567890.1234567890.") ?

Joe
The same problem remains,
Steven smethurst
A: 

From MSDN:

The other main difference between sprintf_s and sprintf is that sprintf_s takes a length parameter specifying the size of the output buffer in characters. If the buffer is too small for the text being printed then the buffer is set to an empty string and the invalid parameter handler is invoked. Unlike snprintf, sprintf_s guarantees that the buffer will be null-terminated (unless the buffer size is zero).

So ideally what you've written should work correctly.

Ashwin
The default "invalid parameter handler" terminates the process.
Pavel Minaev
true, but it is easy to install one that does not, which results in sprintf_s returning -1 if the buffer is too small
stijn
A: 

Looks like you're writing on MSVC of some sort?

I think the MSDN docs for sprintf_s says that it assert dies, so I'm not too sure if you can programmatically catch that.

As LBushkin suggested, you're much better off using classes that manage the strings.

Calyth
+7  A: 

It's by design. The entire point of sprintf_s, and other functions from the *_s family, is to catch buffer overrun errors and treat them as precondition violations. This means that they're not really meant to be recoverable. This is designed to catch errors only - you shouldn't ever call sprintf_s if you know the string can be too large for a destination buffer. In that case, use strlen first to check and decide whether you need to trim.

Pavel Minaev
A: 

See section 6.6.1 of TR24731 which is the ISO C Committee version of the functionality implemented by Microsoft. It provides functions set_constraint_handler(), abort_constraint_handler() and ignore_constraint_handler() functions.

There are comments from Pavel Minaev suggesting that the Microsoft implementation does not adhere to the TR24731 proposal (which is a 'Type 2 Tech Report'), so you may not be able to intervene, or you may have to do something different from what the TR indicates should be done. For that, scrutinize MSDN.

Jonathan Leffler
Unfortunately, MSVC does not implement TR24731 fully - in particular, it does not implement specifically the functions that you reference (also, their names also end with `_s` - i.e. `set_constraint_handler_s`).
Pavel Minaev
But according to http://msdn.microsoft.com/en-us/library/ksazx244%28VS.80%29.aspx there is a function _set_invalid_parameter_handler() function that can be used to change the default behaviour of aborting the program.
Jonathan Leffler
+1  A: 

Instead of sprintf_s, you could use snprintf (a.k.a _snprintf on windows).

#ifdef WIN32
#define snprintf _snprintf
#endif

char buffer[10];    
int length = snprintf( buffer, 10, "1234567890.1234567890." );
// unix snprintf returns length output would actually require;
// windows _snprintf returns actual output length if output fits, else negative
if (length >= sizeof(buffer) || length<0) 
{
    /* error handling */
}
Managu
There's also a snprintf_s.
Joe
Note: as a matter of security, if there's not enough room, the contents of buffer might not be null terminated.
Managu
@Managu: if MS claimed conformance to C99 - which it doesn't - that assertion would be bogus; the C99 standard requires snprintf() to null terminate the string unless the length of the string is 0. Section 7.19.6.5: If n is zero, nothing is written... Otherwise, output characters beyond the n-1st arediscarded rather than being written to the array, and a null character is written at the endof the characters actually written into the array. If copying takes place between objectsthat overlap, the behavior is undefined.
Jonathan Leffler
@Jonathan Leffler: cool, didn't know that.
Managu