为什么strncpy被标记为不安全?

6

我收到了一个警告:

warning C4996: 'strncpy': This function or variable may be unsafe. Consider using  strncpy_s instead.
To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
F:\vuStudio\VC\include\string.h(188) : see declaration of 'strncpy'

我在stackoverflow.com上读到,strcpy不安全,应该使用strncpy代替。但是现在为什么我会收到警告说strncpy不安全?

我调用的方式如下:

strncpy(this->title, title.c_str(), sizeof(this->title));

请参考https://dev59.com/mVTTa4cB1Zd3GeqPsXFs。虽然不完全相同,但那里的信息可以回答您的问题。简而言之,如果您使用`strncpy`函数,需要确保目标字符串以空字符结尾;而`strncpy_s`函数则会自动为您添加空字符。 - davmac
你的示例本身并不安全:如果 title.c_str() 的长度超过了 sizeof(this->title),那么 this->title 数组将不会被空终止,并且如果您稍后尝试使用它,可能会导致随机崩溃。请使用 strncpy(this->title, title.c_str(), sizeof(this->title)-1); this->title[sizeof(this->title)-1] = '\0'; 来解决这个问题。 - pqnet
2
你想将这个问题标记为C吗? - Bartek Banachewicz
根据C11规范,您不必执行第二行: this->title[sizeof(this->title)-1] = '\0'; 这是多余的,因为它已经被处理了,即如果'\0'未作为strncpy_s的一部分复制,则dest [4TH_ARGUMENT_SIZE]将填充为'\0'。 - Preetham Nanjappa
3个回答

9

strncpy存在一些危险的怪癖。

首先,它会将目标缓冲区在复制结束后清零,这可能会令人惊讶。

其次,如果目标缓冲区空间不足,它不会对目标缓冲区进行空终止处理。

第三,如果截断了字符串,它“基本上可以正常工作”。这会阻碍错误处理(截断的字符串通常比无用还糟糕,但乍一看并不会比无用更糟糕)。

strncpy_s需要输入长度(或显式截断请求),如果没有足够的空间来进行空终止处理,则会报错(只在输出中写入零长度字符串)。有时提供输入长度可能效率低下(并且对其某些更改不是必需的),但它确保了一个空终止的输出缓冲区(只要它不是nullptr或零长度),即使在错误情况下也是如此。我不确定它是否会在复制的字符串后面清零。

这种行为可以防止或减轻字符串代码中的一些常见的围栏错误。


4
Visual Studio编译器有其自己的实现strncpy,使用gcc或clang不会收到此警告。使用strncpy更加安全和可移植(因为strncpy_s不是标准)。

如果您不关心可移植性,strncpy_s确实更安全,因为它具有额外的长度检查(但是就像strncpy一样,如果您传递了错误的参数,它也无法帮助您)。


-1

str函数的“n”变体(如strncmp,strncpy等)是“安全”的选择,因为它们都限制了使用的字符串缓冲区的大小。 “旧”的str函数(不是“n”变体,如strcpy)都容易出现许多编程错误和内存攻击(偏移一个,堆覆盖等)。


2
那并没有回答问题。 - Bartek Banachewicz
在我看来,问题的答案已经在gcc的警告中了。这是关于为什么gcc会说“请参见'strncpy'的声明”的解释。 - Stefano Falsetto

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接