为什么我不能使用fopen?

在上一个问题的模型中, 我询问了所谓的安全库弃用 ,我发现自己同样感到困惑的是为什么fopen()应该被弃用。

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

提前致谢

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

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

fopen_s()基本原理是:

6.5.2文件访问function

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

规范说:

6.5.2.1 fopen_s函数

概要

 #define __STDC_WANT_LIB_EXT1__ 1 #include  errno_t fopen_s(FILE * restrict * restrict streamptr, const char * restrict filename, const char * restrict mode); 

运行约束

streamptrfilenamemode都不是空指针。

如果存在运行时约束冲突,则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)

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

返回

如果fopen_s函数打开文件,则返回零。 如果它没有打开文件或者存在运行时约束违规,则fopen_s返回非零值。

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

可以使用fopen() 。 说真的,不要在这里通知微软,他们通过偏离ISO标准让程序员真正受到伤害。 他们似乎认为编写代码的人在某种程度上是脑死亡,并且在调用库函数之前不知道如何检查参数。

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

这似乎只是微软开发商锁定供应商的另一次尝试(虽然他们不是唯一尝试它的人,所以我并没有特别指责他们)。 我通常会添加:

 #define _CRT_SECURE_NO_WARNINGS 

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

Microsoft在fopen_s()函数(文件编码,一个)中提供了额外的function,并改变了返回的方式。 这可能会使Windows程序员更好,但使代码本身不可移植。

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


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

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

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

本质上,它意味着默认情况下应用程序写入的文件不受其他用户的保护。

由于现有代码可能会破坏,他们不会对fopen()这样做。

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

Jonathan Leffler的回答提供了fopen_s()的建议标准化语言。 我添加了这个答案,希望能够明确理由。

或者是别的什么?

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

虽然能够拥有255个打开文件的价值是值得商榷的,但是当你有超过252个套接字连接时,这个实现细节在Solaris 8平台上实现了! 最初出现在我的应用程序中使用libcurl建立SSL连接的看似随机的失败原来是由此引起的,但它花了部署libcurl和openssl的调试版本并通过调试器脚本踩到客户以最终弄明白。

虽然它不完全是’fopen’的错误,但人们可以看到摆脱旧界面束缚的优点; 弃用的选择可能基于与过时的实现保持二进制兼容性的痛苦。

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

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

线程安全。 fopen()使用全局变量errno ,而fopen_s()替换返回errno_t并使用FILE**参数存储文件指针。