fopen_s怎么能比开口更安全

How can fopen_s be more safe than fopen?

本文关键字:安全 怎么能 fopen      更新时间:2023-10-16

我正在为Windows平台编写遗留代码。当我在 VS2013 中编译代码时,它会给出以下警告:

错误 C4996:"fopen":此函数或变量可能不安全。请考虑改用fopen_s。要禁用弃用,请使用_CRT_SECURE_NO_WARNINGS。有关详细信息,请参阅联机帮助。

它还会对sprintf发出环境警告.我知道sprintf_s比 sprintf 更安全,因为缓冲区溢出。

但是怎么能fopen_s比fopen更安全,没有缓冲区溢出的机会,因为fopen不接受缓冲区。任何人都可以提供fopen不安全的案例,而fopen_s是安全的吗?

在这种情况下

s并不代表"安全",它代表"增强的安全性"。对于fopen_s,在尝试打开文件之前会检查参数的有效性。

使用 fopen ,您可以为文件名传递 NULL 指针,所有内容很可能会崩溃。 fopen_s没有这个问题(a)。

请记住,这些边界检查接口(如fopen_s)是 ISO 标准的可选部分,详见附录 K(无论如何,与 C11 相同)。实现不需要提供它们,老实说,fopen ,以及许多其他所谓的不安全功能,如果您知道自己作为编码人员在做什么,那么它们是完全安全的。

有趣的是,fopen_s会为你捕获 NULL 指针,但不会捕获无效指针,因此它的安全性增强而不是安全 - 如果您传递无效但非 NULL 指针,您仍然会造成一些损害。

其他强制您提供目标缓冲区大小的"安全"函数也只有在您传递正确的大小时才是安全的。传递太大的东西,所有的赌注都落空了。


(a)C11 K.3.5.2.1 The fopen_s function

errno_t fopen_s (
    FILE * restrict * restrict streamptr,
    const char * restrict      filename,
    const char * restrict      mode);

运行时约束

streamptr、文件名或模式都不应为空指针。

如果存在运行时约束冲突,fopen_s不会尝试打开文件。此外,如果 streamptr 不是空指针,fopen_s 将 *streamptr 设置为空指针。

将其与 C11 7.20.5.3 The fopen function 形成对比, 声明文件名和模式必须都指向字符串,但不指定如果提供 NULL 指针会发生什么(大多数实现可能会因空指针取消引用而崩溃)。

> 当 VS2005 问世时,我认为他们的"让我们制作专有函数而不是给人们snprintf()"只是Microsoft走得太远,因为如果传递 NULL 指针,两者都会(默认情况下)引发 win32 异常(尽管fopen会引发STATUS_ACCESS_VIOLATIONfopen_s会引发STATUS_INVALID_PARAMETER)。这意味着两者都会导致程序立即崩溃,除非添加特定于 Win32 的代码来处理异常。

但是,在CRT源代码中窥视确实揭示了一个小差异:fopen使用的共享标志是完全允许的,而fopen_s使用的共享标志禁止其他进程打开文件进行写入。这样,fopen_s更安全,因为这意味着文件不会在您的进程脚下更改。