繁体   English   中英

内存映射文件读取输入文件的安全性如何?

[英]How safe are memory-mapped files for reading input files?

将输入文件映射到存储器然后直接从映射的存储器页面解析数据可以是从文件读取数据的方便且有效的方式。

但是,除非您可以确保没有其他进程写入映射文件,否则这种做法似乎从根本上说是不安全的,因为即使私有只读映射中的数据可能会在另一个进程写入基础文件时发生更改。 (POSIX例如,未指定 “在建立MAP_PRIVATE映射后是否通过MAP_PRIVATE映射可以看到对基础对象的修改”。)

如果您希望在对映射文件进行外部更改时使代码安全,则必须仅通过易失性指针访问映射内存,然后非常小心您如何读取和验证输入,这似乎不切实际。许多用例。

这个分析是否正确? 内存映射API的文档通常只在传递中提到这个问题,如果有的话,所以我想知道我是否遗漏了一些东西。

这不是一个真正的问题。

是的,另一个进程可能会在您映射文件时修改该文件,是的,您可能会看到修改。 甚至可能 ,因为几乎所有的操作系​​统都有统一的虚拟内存系统,所以除非有人请求无缓冲的写入,否则没有办法在没有经过缓冲区缓存的情况下进行编写,没有办法让没有人拿着映射看到变化。
这甚至都不是坏事。 其实,如果你无法看到的变化会更令人不安。 由于文件准映射时会成为地址空间的一部分,因此您可以看到文件的更改。

如果您使用传统的I / O(例如read ),有人仍然可以在您阅读时修改该文件。 换句话说, 在存在修改的情况下将文件内容复制到内存缓冲区并不总是安全的 它是“安全的”,因为read不会崩溃,但它不能保证您的数据是一致的。
除非您使用readv ,否则您无法保证原子性(即使使用readv您也无法保证内存中的内容与磁盘上的内容一致,或者在两次调用readv之间不会发生变化)。 有人可能会在两次read操作之间修改文件,或者甚至在您处于中间时修改文件。
只是一些没有被正式保证,但“可能仍然有效” -相反,例如在Linux下写的demonstrably不是原子。 甚至不是偶然的。

好消息:
通常,进程只是打开任意随机文件并开始写入它。 当发生这样的事情时,它通常是属于进程的众所周知的文件(例如日志文件),或者是您明确告诉进程写入的文件(例如,保存在文本编辑器中),或者进程创建一个新文件(例如编译器创建一个目标文件),或者该过程仅附加到现有文件(例如db日志,当然还有日志文件)。 或者,进程可能会自动将文件替换为另一个文件(或取消链接)。

在每种情况下,整个可怕的问题归结为“没有问题”,因为要么你很清楚会发生什么(所以这是你的责任),要么它无缝地工作而不会干扰。

如果你真的不喜欢另一个进程可能可能写入文件,而你把它映射的可能性,你可以简单地忽略FILE_SHARE_WRITE当您创建的文件句柄在Windows下。 POSIX使它更复杂,因为您需要为强制锁定fcntl描述符,这在每个系统上都不是必需的,或者是100%可靠的(例如,在Linux下)。

理论上,如果有人在您阅读文件时修改文件,您可能会遇到麻烦。 在实践中:你正在阅读角色,没有别的东西:没有指针,或任何可能让你陷入困境的东西。 在实践中...正式地说,我认为它仍然是未定义的行为,但它是我认为你不必担心的行为。 除非修改非常小,否则会遇到很多编译器错误,但这就是它的结束。

可能导致问题的一个案例是文件缩短了。 我不确定当你读到最后时会发生什么。

最后:系统不是随意打开和修改文件。 这是一个源文件; 这将是一些做这件事的白痴程序员,他应得的。 在任何情况下,您的未定义行为都不会破坏系统或其他人的文件。

另请注意,大多数编辑都在私人副本上工作; 回写时,他们通过重命名原始文件并创建新文件来实现。 在Unix下,一旦你打开文件来mmap它,所有重要的是inode号。 当编辑器重命名或删除文件时,您仍然保留副本。 修改后的文件将获得一个新的inode。 您唯一需要担心的是,如果有人打开文件进行更新,然后继续修改它。 没有多少程序在文本文件上执行此操作,除了向末尾添加其他数据。

因此,虽然正式,但存在一些风险,我认为你不必担心它。 (如果你真的是偏执狂,那么你可以在你编写mmap关闭写入授权。如果真的有一个敌方特工要拿你的,他可以把它重新打开。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM