c - 为什么 strcpy_s 比 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_s
比strcpy
将大字符串复制到较短的字符串更安全。因此,我尝试了以下代码来处理较短的字符串:
char a[50] = "void";
char b[3];
strcpy_s(b, sizeof(a), a);
printf("String = %s", b);
那么,怎样scrcpy_s
才算安全?我对安全概念的理解有误吗?
解决方案
为什么strcpy_s()
“更安全”?嗯,它实际上是相当复杂的。(请注意,此答案忽略了已发布代码中的任何特定代码问题。)
首先,当 MSVC 告诉您诸如strcpy()
“已弃用”之类的标准功能时,微软充其量是不完整的。在最坏的情况下,微软是在对你撒谎。在这里将您想要的任何动机归因于 Microsoft,但是strcpy()
MSVC 称为“已弃用”的许多其他函数是标准 C 函数,并且它们肯定不会被 Microsoft 以外的任何人弃用。因此,当 MSVC 警告您需要在任何符合 C 编译器中实现的函数(其中大部分然后按要求流入 C++ ......)时,它会省略“由 Microsoft”部分。
微软“有帮助”建议您使用的“更安全”功能 - 例如strcpy_s()
标准功能,因为它们是 C 标准的可选附件 K 的一部分,如果微软按照标准实施它们。
Microsoft Visual Studio 实现了 API 的早期版本。但是,实现不完整,既不符合 C11 也不符合原始 TR 24731-1。例如,它不提供
set_constraint_handler_s
函数,而是定义了一个_invalid_parameter_handler _set_invalid_parameter_handler(_invalid_parameter_handler)
具有相似行为但略有不同且不兼容的签名的函数。它也没有定义abort_handler_s
andignore_handler_s
函数、memset_s
函数(不是 TR 的一部分)或RSIZE_MAX
宏。Microsoft 实现也不会将重叠的源序列和目标序列视为违反运行时约束,而是在这种情况下具有未定义的行为。由于与规范存在大量偏差,因此不能将 Microsoft 实施视为符合标准或可移植的。
除了一些特定情况(其中strcpy()
一个)之外,Microsoft 版本的 Annex K 的“更安全”的边界检查功能是否更安全还有待商榷。 根据 N1967(加粗矿):
建议的技术勘误
尽管距离最初的提案已有十多年,距离 ISO/IEC TR 24731-1:2007 的批准已有近十年,距离将边界检查接口引入 C 标准已有近五年,但还没有出现可行的符合要求的实现. API 继续存在争议,实施请求继续被实施者拒绝。
Bounds 检查接口的设计虽然是出于好意,但存在太多需要纠正的问题。与依赖现有方法或现代技术相比,使用 API 会导致软件质量更差、安全性更低。更有效且侵入性更小的方法已变得司空见惯,并且经常受到用户和安全专家的青睐。
因此,我们建议附录 K 要么从 C 标准的下一个修订版中删除,要么弃用然后删除。
但是请注意,在 的情况下strcpy()
,strcpy_s()
实际上更类似于不做边界检查的沼泽标准 C 字符串函数,而是strncpy()
一个反常的函数,因为它将完全填充其目标缓冲区,从数据开始从源字符串,并用值填充整个目标缓冲区。 除非源字符串填满整个目标缓冲区,在这种情况下不会用值终止它。strcpy()
strncpy()
'\0'
char
strncpy()
'\0'
char
我再重复一遍: strncpy()
不保证正确终止的副本。
很难不比strncpy()
. 在这种情况下,不会像这样strcpy_s()
做那样违反最小惊讶原则strncpy()
。我称之为“更安全”。
但是使用strcpy_s()
- 以及所有其他“建议的”功能 - 使您的代码事实上不可移植,因为 Microsoft 是任何形式的附件 K 边界检查功能的唯一重要实现。
推荐阅读
- php - UPS 费率 API 未获取地面/第二天/隔夜的值
- office365 - 保持 web 前景添加始终显示
- sql-server - 如何将 csv 文件从一台 linux 服务器导入到另一台服务器(mssql 服务器)
- python - 为数据框中的每一行绘制图表并保存为 jpg 格式?
- python - 删除具有一定百分比 0 的 pandas 的列和行
- php - 由于两个表之间的外键约束而无法登录
- node.js - node_module 和 aws lambda 函数
- cordova - Ionic-4 轮选择器/选择器按钮 css 自定义
- angular - 如何在没有角度材料日期选择器的情况下使用
- apache-kafka - kafka在消费消息时崩溃