当前位置: 首页 > 面试题库 >

不检查close()的返回值:真的有多严重?

茅慈
2023-03-14
问题内容

Linux的“手动关闭”警告(SVr4、4.3BSD,POSIX.1-2001):

不检查close()的返回值是 常见严重的
编程错误。很有可能首先在最后的close()中报告了先前write(2)操作的错误。关闭文件时不检查返回值可能会导致数据静默丢失。使用NFS和磁盘配额尤其可以观察到这一点。

我可以相信这个错误是 常见的 (至少在应用程序中;我不是内核黑客)。但是,今天或过去三十年中的任何时候,它有多 严重 ?特别是:

是否有一个简单,可复制的示例,说明这种无声的数据丢失?即使是人为的人也喜欢在close()期间发送SIGKILL?

如果存在这样的例子,是否可以比仅仅更优雅地处理数据丢失

printf("Sorry, dude, you lost some data.\n");


问题答案:

[现在]是严重的还是在过去的三十年中的任何时候?

典型应用程序 处理
数据。他们消耗一些输入,并产生结果。因此,在两种情况下close()可能会返回错误:关闭输入(只读?)文件时,以及关闭刚刚生成或修改的文件时。

close()返回错误的已知情况特定于将数据写入/刷新到永久存储中。特别是,它是常见的操作系统来缓存数据在本地,之前实际写入永久存储(在close()fsync()fdatasync());
这在远程文件系统中非常常见,这就是手册页中提到NFS的原因。

关闭只读输入文件时,我从未遇到错误。我可以想到的是,使用任何常见文件系统在现实生活中可能发生的所有情况都是发生灾难性故障的情况,例如内核数据结构损坏。如果发生这种情况,我认为该close()错误不可能是发生严重错误的唯一迹象。

当写入远程文件系统上的文件时,close()如果本地网络容易出现故障或只是丢弃大量数据包,则-time错误非常普遍。作为最终用户,我 希望
我的应用程序告诉我写入文件时是否出错。通常,到远程文件系统的连接会完全断开,并且向新文件写入失败的事实是用户的第一个指示。

如果不检查close()返回值,应用程序将对用户说谎。它将指示(如果没有错误消息,则将缺少错误消息)表明文件已正确写入,而实际上并非如此,并且已告知应用程序;该应用程序只是忽略了指示。如果用户像我一样,他们会对应用程序感到非常不满意。

问题是,用户数据对您有多重要?当前大多数应用程序程序员根本不在乎。Basile
Starynkevitch(在对原始问题的评论中)是绝对正确的;close()大多数程序员都不愿意检查错误。

我认为这种态度是应受谴责的。骑士无视用户数据。

但是,这很自然,因为用户没有明确指示哪个应用程序破坏了他们的数据。根据我的经验,最终用户最终会归咎于操作系统,硬件,开放源代码或免费软件,或者是本地IT支持。因此,程序员不必担心社交或其他方面的压力。因为只有程序员才知道诸如此类的细节,而大多数程序员都不在乎,所以没有改变现状的压力。

(我知道上面的内容会使很多程序员讨厌我的胆量,但至少我是诚实的。我指出诸如此类的典型反应是,这种情况很少见,浪费资源来检查这一点。这可能是正确的。但是我愿意花更多的CPU周期并向程序员多付几分钱,这是否意味着我的机器实际上可以更可预测地工作,并告诉我是否它丢失了情节,而不是无声地破坏了我的数据。)

是否有一个简单,可复制的示例,说明这种无声的数据丢失?

我知道三种方法:

  1. 使用USB记忆棒,然后在决赛之后write()但在之前将其拔出close()。不幸的是,大多数USB记忆棒的硬件都设计得不能幸免,因此您最终可能会弄脏USB记忆棒。取决于文件系统,您的内核也可能会死机,因为大多数文件系统都是在假设这种情况永远不会发生的情况下编写的。

  2. 设置NFS服务器,并通过使用iptables丢弃NFS服务器与客户端之间的所有数据包来模拟间歇性数据包丢弃。具体情况取决于服务器和客户端,安装选项和使用的版本。但是,使用两个或三个虚拟机来建立测试台应该相对容易。

  3. 使用自定义文件系统来模拟一次写入错误close()。当前的内核不允许您强制卸载tmpfs或回送挂载,而只能强制卸载NFS挂载,否则可以通过在最终写入之后但在之前写入文件来强制卸载文件系统,这很容易模拟close()。(当前的内核只是在该文件系统上存在打开的文件时拒绝umount。)对于应用程序测试,创建tmpfs的变体,close()如果文件模式表明需要,则返回一个错误(例如,其他可写但非其他可写-可读性或其他可执行性,即-??????-w-)将非常容易且安全。它实际上并不会破坏数据,但是如果内核在关闭时间报告数据破坏(存在风险),它将使检查应用程序的行为变得容易。



 类似资料:
  • 是否有一种简单的方法来确保返回的所有值都为真?在下面的示例中,我有一组表示文件的对象。在继续之前,我想确保所有源文件都存在。我将所有路径传递到测试路径,函数为每个文件返回True/False。 我如何检查所有返回值都是真的?

  • 我正在等待(从USSD请求中)检索一个值,以便返回它(getUSSD):

  • 我想在php上创建一个函数,它将返回数组中sql查询的值。函数中的sql ode可以工作,我可以显示值。 但是当我想在一个函数中使用它时,它就不起作用了。我的语法中有什么错误?

  • 我必须使用一个c函数(),它在失败时返回标量、或。 这适用于以下故障: 但对于有效的论点,我得到: 如何检查呼叫是否成功?

  • 5.3. 多返回值 在Go中,一个函数可以返回多个值。我们已经在之前例子中看到,许多标准库中的函数返回2个值,一个是期望得到的返回值,另一个是函数出错时的错误信息。下面的例子会展示如何编写多返回值的函数。 下面的程序是findlinks的改进版本。修改后的findlinks可以自己发起HTTP请求,这样我们就不必再运行fetch。因为HTTP请求和解析操作可能会失败,因此findlinks声明了2

  • 在弹性搜索索引中,我试图通过来自字段companyName和字段productName的两个不同的顶级字段值进行查询,按generatedDate字段排序,并包括domainModelId字段。 下面的SQL查询显示了所有现有值的结果,我通过generatedDate突出显示了两个唯一的文档行(在本例中); 响应如下: 我尝试了以下方法 这将返回正确的存储桶,如下所示; 如何包含domainMod