sprintf_s,缓冲区太小

Ste*_*rst 10 c error-handling printf tr24731

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

char buffer[10];    
int length = sprintf_s( buffer, 10, "1234567890.1234567890." ); 
Run Code Online (Sandbox Code Playgroud)

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

编辑:

阅读下面的评论后,我选择_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 
Run Code Online (Sandbox Code Playgroud)

Pav*_*aev 16

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


Man*_*agu 5

而不是sprintf_s,你可以使用snprintf(也就是_snprintf在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 */
}
Run Code Online (Sandbox Code Playgroud)

  • 还有一个snprintf_s. (4认同)
  • 注意:作为安全问题,如果没有足够的空间,缓冲区的内容可能不会被终止. (2认同)
  • @Managu:如果MS声称符合C99 - 它没有 - 那个断言将是假的; 除非字符串的长度为0,否则C99标准要求snprintf()为null终止字符串.第7.19.6.5节:如果n为零,则不写入任何内容...否则,将丢弃n-1之外的输出字符而不是写入数组,并在实际写入数组的字符末尾写入空字符.如果在重叠的对象之间进行复制,则行为未定义. (2认同)
  • @Managu请编辑您的答案以删除使用_snprintf的建议.这是一个非常危险的建议. (2认同)

Bru*_*son 5

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

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

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

  • 我没有忘记一个论点——代码可以编译并且是完全安全的。您需要重新阅读文档。我正在使用 _snprintf_s 的模板重写,告诉编译器推断缓冲区大小。我见过数百个地方,程序员明确地传递了缓冲区大小,并且传递了*错误的*大小。只有让编译器推断缓冲区大小才能避免这个严重的错误。我在解决方案中链接的文章中提到了这种技术。强力推荐。 (2认同)