sprintf_s,缓冲区太小

时间:2009-10-01 19:34:06

标签: c error-handling printf tr24731

以下代码会导致错误并导致我的应用程序死亡。这是有道理的,因为缓冲区只有10个字节长,文本长度为22个字节(缓冲区溢出)。

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

如何捕获此错误以便我可以报告而不是崩溃我的应用程序?

修改

阅读下面的评论后,我选择了_snprintf_s。如果它返回-1值,则缓冲区未更新。

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 

6 个答案:

答案 0 :(得分:16)

这是设计的。 sprintf_s以及*_s系列中的其他函数的整个点是捕获缓冲区溢出错误并将其视为先决条件违规。这意味着它们并非真正意味着可以恢复。这只是为了捕获错误 - 如果您知道字符串对于目标缓冲区来说太大,则不应该调用sprintf_s。在这种情况下,首先使用strlen检查并确定是否需要修剪。

答案 1 :(得分:5)

而不是sprintf_s,您可以在Windows上使用snprintf(a.k.a _snprintf

#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 */
}

答案 2 :(得分:5)

这适用于VC ++,甚至比使用snprintf更安全(当然比_snprintf更安全):

void TestString(const char* pEvil)
{
  char buffer[100];
  _snprintf_s(buffer, _TRUNCATE, "Some data: %s\n", pEvil);
}

_TRUNCATE标志表示该字符串应该被截断。在这种形式下,缓冲区的大小实际上并没有传入,(矛盾的是!)是它如此安全的原因。编译器使用模板魔术来推断缓冲区大小,这意味着它不能被错误地指定(一个令人惊讶的常见错误)。这个技术可以应用于创建其他安全的字符串包装器,如我的博客文章中所述: https://randomascii.wordpress.com/2013/04/03/stop-using-strncpy-already/

答案 3 :(得分:0)

来自MSDN:

sprintf_s和sprintf之间的另一个主要区别是sprintf_s采用一个长度参数来指定输出缓冲区的大小(以字符为单位)。如果缓冲区对于正在打印的文本而言太小,则将缓冲区设置为空字符串并调用无效参数处理程序。与snprintf不同,sprintf_s保证缓冲区将以空值终止(除非缓冲区大小为零)。

理想情况下,你所写的内容应该正常工作。

答案 4 :(得分:0)

看起来你正在某种MSVC上写作?

我认为sprintf_s的MSDN文档说它断言死了,所以我不太确定你是否能以编程方式捕获它。

正如LBushkin建议的那样,使用管理字符串的类会更好。

答案 5 :(得分:0)

请参阅TR24731的第6.6.1节,这是Microsoft实施的功能的ISO C Committee版本。它提供了set_constraint_handler()abort_constraint_handler()ignore_constraint_handler()函数。

Pavel Minaev的评论暗示微软的实施不符合TR24731提案(这是'2型技术报告'),因此您可能无法进行干预,或者您可能需要做一些不同的事情从TR表明应该做什么。为此,仔细检查MSDN。