为什么strcpy_s比strcpy更安全?

为什么strcpy_s比strcpy更安全?,c,string,strcpy,C,String,Strcpy,当我试图使用strcpy函数时,VisualStudio会给我一个错误 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函数时,VisualStudio会给我一个错误

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\u s
strcpy
更安全。 因此,我尝试了以下代码来处理较短的字符串:

char a[50] = "void";
char b[3];
strcpy_s(b, sizeof(a), a);
printf("String = %s", b);
代码复制成功。但是,仍然存在一个运行时错误:

那么,
scrcpy\u s
是如何安全的呢?
我对安全概念的理解有误吗?

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);
#包括
字符a[50]=“无效”;
charb[3];
strcpy_s(b,尺寸f(b),a);
printf(“字符串=%s”,b);

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);
#包括
字符a[50]=“无效”;
charb[3];
strcpy_s(b,尺寸f(b),a);
printf(“字符串=%s”,b);

strcpy\u需要目标的大小,该大小小于示例中的源

strcpy_s(b, sizeof(b), a);
这是最好的选择

至于安全概念,现在已经做了很多检查,并且有更好的方法来处理错误


在您的示例中,如果您使用strcpy,就会触发缓冲区溢出。其他函数,如strncpy或strlcpy,会在没有任何空字节终止符的情况下复制前3个字符,这反过来会触发缓冲区溢出(这次在读取中)。

strcpy需要目标的大小,该大小小于示例中的源

strcpy_s(b, sizeof(b), a);
这是最好的选择

至于安全概念,现在已经做了很多检查,并且有更好的方法来处理错误

在您的示例中,如果您使用strcpy,就会触发缓冲区溢出。其他函数,如strncpy或strlcpy,会在没有任何空字节终止符的情况下复制前3个字符,这反过来会触发缓冲区溢出(这次在读取时)。

为什么
strcpy_()
更安全?事实上,这很复杂。(请注意,此答案会忽略已发布代码中的任何特定代码问题。)

首先,当MSVC告诉您诸如
strcpy()
之类的标准函数被“弃用”时,微软充其量是不完整的。最糟糕的情况是,微软完全在对你撒谎。在这里,您可以将任何动机归于Microsoft,但是
strcpy()
和MSVC称为“已弃用”的许多其他函数都是标准的C函数,除Microsoft以外的任何人都不会弃用它们。因此,当MSVC警告您,在任何一致的C编译器中实现一个函数<强>要求的/StUng>(大多数都是按需求流到C++中)时,它忽略了“微软”部分。 Microsoft建议您使用的“更安全”的函数(如
strcpy_s()
)将是标准的,因为它们是C标准的可选附录K的一部分,如果Microsoft按照标准实施的话

Microsoft Visual Studio实现了API的早期版本。但是,实施不完整,既不符合C11,也不符合原始TR 24731-1。例如,它不提供
set\u constraint\u handler\s
函数,而是定义一个
\u invalid\u parameter\u handler\u set\u invalid\u parameter\u handler(\u invalid\u parameter\u handler)
函数,该函数具有类似的行为,但签名略有不同且不兼容。它也不定义
abort\u handler\s
ignore\u handler\s
函数、
memset\s
函数(不属于TR的一部分)或
RSIZE\u MAX
宏。Microsoft实现也不会将重叠的源和目标序列视为违反运行时约束,而是在这种情况下具有未定义的行为

由于与规范存在大量偏差,Microsoft实施不能被视为符合要求或可移植

除了一些特定的情况(strcpy()就是其中之一),微软版本的附录K的“更安全的”边界检查函数是否更安全还有争议。(加粗):

建议的技术勘误表

尽管从最初的提案开始已有十多年的时间,从批准ISO/IEC TR 24731-1:2007开始已有近十年的时间,从将边界检查接口引入C标准开始已有近五年的时间,但还没有出现可行的一致性实现。API仍然存在争议,实施者继续拒绝实施请求

边界检查接口的设计虽然用意良好,但存在太多无法纠正的问题与依赖现有方法或现代技术相比,使用API会导致质量更差、安全性更低的软件。更有效、侵入性更小的方法已经司空见惯,用户和安全专家通常都更喜欢这些方法

因此,我们建议将附录K从下一版本的C标准中删除,或弃用,然后删除

但是请注意,在
strcpy()
的情况下,
strcpy\u()
实际上更类似于
strncpy()
,因为
strcpy()
只是一个bog标准的C字符串函数,不进行边界检查,但是
strncpy()
是一个反常的函数,因为它将完全填充其目标缓冲区,从源字符串的数据开始,用
'\0'
char
值填充整个目标缓冲区除非源字符串填满整个目标缓冲区,否则在这种情况下,
strncpy()
不会使用
'\0'
char
值终止它。

我重复一遍:
strncpy()
不能保证正确终止副本。

很难不比这更“安全”