为什么strcpy_s比strcpy更安全?

时间:2019-12-08 20:43:58

标签: c string strcpy

当我尝试使用strcpy函数时,Visual Studio给我一个错误

error C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.

在在线搜索并从StackOverflow获得许多答案之后,摘要表明,将大字符串复制到较短的字符串中,strcpy_sstrcpy更安全。 因此,我尝试了以下代码来处理较短的字符串:

char a[50] = "void";
char b[3];
strcpy_s(b, sizeof(a), a);
printf("String = %s", b);

代码成功编译。但是,仍然存在运行时错误: enter image description here

那么scrcpy_s的安全性如何? 我是否理解安全性概念错了?

3 个答案:

答案 0 :(得分:4)

为什么strcpy_s()“更安全”?好吧,实际上涉及很多。 (请注意,此答案将忽略已发布代码中的任何特定代码问题。)

首先,当MSVC告诉您“ strcpy()之类的标准功能已被“弃用”时,充其量Microsoft并不完整。最糟糕的是,Microsoft完全是在骗你。在此处将您想要的动机归因于Microsoft,但是strcpy()和MSVC称为“不推荐使用”的许多其他功能是标准C函数,并且除Microsoft以外,其他任何人都绝不推荐使用这些功能。因此,当MSVC警告您要求的功能要在任何符合标准的C编译器中实现(大多数功能然后按要求流入C ++ ...)时,它将忽略“由Microsoft”部分。

Microsoft“有帮助”地建议您使用的“安全”功能-例如strcpy_s()将是标准的,因为它们是C标准的可选附件K的一部分,如果Microsoft按照标准实施了这些功能。标准。

N1967 - Field Experience With Annex K — Bounds Checking Interfaces

  

Microsoft Visual Studio实现了API的早期版本。但是,实现不完整,既不符合C11也不符合原始的TR 24731-1。例如,它不提供set_constraint_handler_s函数,而是定义了一个具有类似行为但签名稍有不同且不兼容的_invalid_parameter_handler _set_invalid_parameter_handler(_invalid_parameter_handler)函数。它还没有定义abort_handler_signore_handler_s函数,memset_s函数(不属于TR的一部分)或RSIZE_MAX宏。 Microsoft实施也不会将重叠的源序列和目标序列视为运行时约束冲突,而是在这种情况下具有未定义的行为。

     

由于与规范的众多差异,Microsoft实现不能被认为是合规的或可移植的。

除了一些特定情况(其中strcpy()是一种情况)之外,微软版本的附件K的“更安全”范围检查功能是否更安全还有待商bat。 Per N1967(轰炸我):

  

建议的技术勘误

     

尽管自原始提案以来已有十多年,距ISO / IEC TR 24731-1:2007批准以来已有近十年,距将边界检查接口引入C标准至今已有近五年,但尚无可行的标准。实现已经出现。这些API一直存在争议,实施者的要求继续遭到实施者的拒绝。

     

Bounds检查界面的设计虽然用心良苦,但却有太多问题需要纠正。 与使用现有方法或现代技术相比,使用API​​会导致质量降低,软件安全性降低。更有效,侵入性更低的方法已变得司空见惯,并经常受到用户和安全专家的青睐。

     

因此,我们建议将附件K从C标准的下一个修订版本中删除,或者不推荐使用,然后删除。

但是请注意,在strcpy()的情况下,strcpy_s()实际上更类似于strncpy(),因为strcpy()只是一个沼泽标准的C字符串函数,不会进行边界检查,但是strncpy()是一个错误的函数,因为它将完全填充其目标缓冲区,从源字符串中的数据开始,并用'\0' char填充整个目标缓冲区价值观。 除非源字符串填充了整个目标缓冲区,否则strncpy()不会以'\0' char值终止它。

我将重复以下内容:strncpy()不保证副本的正确终止。

很难比“ strncpy()”更“安全”。在这种情况下,strcpy_s()不会像strncpy()那样违反principle of least astonishment。我称之为“更安全”。

但是使用strcpy_s()-和所有其他“建议的”功能-会使您的代码事实上无法移植,因为Microsoft是唯一的重要实现任何形式的附件K的边界检查功能。

答案 1 :(得分:-1)

C的标头定义为:

errno_t strcpy_s(char *dest,rsize_t dest_size,const char *src)

您的示例的调用应为:

#include <stdlib.h>

char a[50] = "void";
char b[3];
strcpy_s(b, sizeof(b), a);
printf("String = %s", b);

答案 2 :(得分:-1)

strcpy_s需要目标的大小,小于示例中的源。

strcpy_s(b, sizeof(b), a);

将是要走的路。

关于安全概念,现在已经进行了许多检查,并且有更好的处理错误的方法。

在您的示例中,如果您使用strcpy,则会触发缓冲区溢出。其他功能,例如strncpy或strlcpy,将复制前三个字符而没有任何空字节终止符,这反过来又会触发缓冲区溢出(这次是读取)。