24

我之前询问过的关于所谓的安全库弃用的问题中,我发现自己同样对为什么fopen()应该弃用感到困惑。

该函数接受两个 C 字符串,并返回一个 FILE* ptr,或在失败时返回 NULL。线程安全问题/字符串溢出问题在哪里?或者是别的什么?

提前致谢

4

6 回答 6

46

可以使用fopen(). 说真的,在这里不要理会微软,他们背离了 ISO 标准,对程序员造成了真正的伤害。他们似乎认为编写代码的人不知何故是脑残,不知道如何在调用库函数之前检查参数。

如果有人不愿意学习 C 编程的复杂性,他们真的没有生意去做。他们应该转向更安全的语言。

这似乎只是微软对开发人员锁定供应商的又一次尝试(尽管他们不是唯一尝试这样做的人,所以我没有特别谴责他们)。我通常会添加:

#define _CRT_SECURE_NO_WARNINGS

(或"-D"命令行上的变体)到我的大多数项目,以确保我在编写完全有效的合法 C 代码时不会被编译器打扰。

微软在函数中提供了额外的fopen_s()功能(例如文件编码)以及改变返回的方式。这对于 Windows 程序员来说可能会更好,但会使代码本质上不可移植。

如果您只打算为 Windows 编写代码,请务必使用它。我自己更喜欢在任何地方编译和运行我的代码的能力(尽可能少的改变)。


从 C11 开始,这些安全功能现在是标准的一部分,尽管是可选的。查看附件 K 了解完整详情。

于 2009-05-25T13:06:10.040 回答
20

有一份官方 ISO/IEC JTC1/SC22/WG14(C 语言)技术报告TR24731-1(边界检查接口)及其基本原理,请访问:

还有针对 TR24731-2(动态分配功能)的工作。

陈述的理由fopen_s()是:

6.5.2 文件访问功能

创建文件时,fopen_sfreopen_s函数通过设置文件保护和以独占访问方式打开文件来保护文件免受未经授权的访问,从而提高安全性。

规范说:

6.5.2.1 fopen_s 函数

概要

#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
errno_t fopen_s(FILE * restrict * restrict streamptr,
                const char * restrict filename,
                const char * restrict mode);

运行时约束

streamptrfilename或中的任何一个都不mode是空指针。

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

描述

fopen_s函数打开名称为 指向的字符串的文件 filename,并将流与它相关联。

模式字符串应与fopen的描述相同,此外,以字符 'w' 或 'a' 开头的模式可以前面有字符 'u',见下文:

  • uw截断为零长度或创建用于写入的文本文件,默认权限
  • ua附加; 打开或创建文本文件以在文件末尾写入,默认权限
  • uwb截断为零长度或创建二进制文件进行写入,默认权限
  • uab附加; 打开或创建二进制文件以在文件末尾写入,默认权限
  • uw+截断为零长度或创建用于更新的文本文件,默认权限
  • ua+附加; 打开或创建文本文件以进行更新,在文件末尾写入,默认权限
  • uw+buwb+截断为零长度或创建二进制文件进行更新,默认权限
  • ua+buab+附加;打开或创建二进制文件以进行更新,在文件末尾写入,默认权限

在底层系统支持这些概念的范围内,为写入而打开的文件应以独占(也称为非共享)访问权限打开。如果正在创建文件,并且模式字符串的第一个字符不是'u',则在底层系统支持的范围内,该文件应具有防止系统上其他用户访问该文件的文件权限。如果正在创建文件并且模式字符串的第一个字符是'u',那么当文件被关闭时,它应该具有系统默认的文件访问权限10)

如果文件打开成功,则指向的指针FILEstreamptr 设置为指向控制打开文件的对象的指针。否则,指向的指针FILEstreamptr被设置为空指针。

退货

fopen_s如果打开文件,该函数将返回零。如果它没有打开文件或存在运行时约束冲突,则fopen_s返回一个非零值。

10)这些权限与 fopen 创建文件的权限相同。

于 2009-05-25T17:54:42.193 回答
8

fopen_s()函数已由 Microsoft 添加到 C 运行时,与以下基本区别fopen()

  • 如果打开文件以进行写入(在模式中指定“w”或“a”),则打开文件以进行独占(非共享)访问(如果平台支持)。
  • 如果在 mode 参数中使用了“u”说明符并带有“w”或“a”说明符,那么在文件关闭时,它将具有系统默认权限,其他用户可以访问该文件(可能没有如果这是系统默认设置,则访问)。
  • 如果在这些情况下未使用指定的“u” ,则当文件关闭(或之前)时,将设置文件的权限,以使其他用户无法访问该文件。

从本质上讲,这意味着应用程序写入的文件默认受到其他用户的保护。

他们没有这样做是fopen()因为现有代码可能会破坏。

Microsoft 选择弃用fopen()以鼓励 Windows 开发人员有意识地决定他们的应用程序使用的文件是否具有宽松的权限。

Jonathan Leffler 的回答fopen_s(). 我添加了这个答案,希望能阐明理由。

于 2009-07-09T23:50:25.937 回答
2

或者是别的什么?

'fopen' 使用的 FILE 结构的某些实现将文件描述符定义为 'unsigned short'。这样一来,您最多可以同时打开 255 个文件,减去 stdin、stdout 和 stderr。

虽然能够打开 255 个文件的价值值得商榷,当然,当您有超过252 个套接字连接时,这个实现细节会在 Solaris 8 平台上实现!最初在我的应用程序中使用 libcurl 建立 SSL 连接时出现的看似随机的失败原来是由这个引起的,但它需要部署 libcurl 和 openssl 的调试版本并通过调试器脚本逐步引导客户才能最终解决。

虽然这不完全是“fopen”的错,但我们可以看到摆脱旧接口束缚的好处;弃用的选择可能是基于维护与过时实现的二进制兼容性的痛苦。

于 2009-05-25T16:25:17.833 回答
1

新版本进行参数验证,而旧版本没有。

有关更多信息,请参阅此 SO 线程

于 2009-05-25T12:52:57.400 回答
1

线程安全。fopen()使用全局变量 ,errnofopen_s()替换返回一个errno_t并接受一个FILE**参数来存储文件指针。

于 2009-05-25T12:56:30.527 回答