10

以下代码会导致错误并终止我的应用程序。这是有道理的,因为缓冲区只有 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 
4

6 回答 6

17

这是设计使然。的全部要点sprintf_s和该系列的其他功能*_s是捕获缓冲区溢出错误并将其视为前提条件违规。这意味着它们并不是真正可以恢复的。这仅用于捕获错误 -sprintf_s如果您知道字符串对于目标缓冲区而言可能太大,则不应调用。在这种情况下,请先使用strlen先检查并决定是否需要修剪。

于 2009-10-01T19:49:19.343 回答
8

而不是sprintf_s,您可以使用(在 Windows 上snprintf又名)。_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 */
}
于 2009-10-01T20:06:55.890 回答
6

这适用于 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/

于 2014-11-22T00:41:25.100 回答
0

来自 MSDN:

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

因此,理想情况下,您所写的内容应该可以正常工作。

于 2009-10-01T19:43:55.883 回答
0

看起来你正在写某种类型的 MSVC?

我认为 sprintf_s 的 MSDN 文档说它断言死亡,所以我不太确定你是否可以通过编程方式捕捉到它。

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

于 2009-10-01T19:44:47.753 回答
0

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

Pavel Minaev 的评论表明,Microsoft 实施不遵守 TR24731 提案(这是“类型 2 技术报告”),因此您可能无法干预,或者您可能必须做一些与TR 表示应该做。为此,请仔细检查 MSDN。

于 2009-10-01T20:00:11.310 回答