【问题标题】:Avoid crash after doing mmap() on a file that is unmounted对已卸载的文件执行 mmap() 后避免崩溃
【发布时间】:2012-10-05 07:18:58
【问题描述】:

我正在对可以卸载的文件执行 mmap()(该文件位于用户可以随时删除的 USB 设备上),如果文件被卸载,我的应用程序将崩溃,然后我尝试访问缓冲区中的任何元素。

有什么解决办法吗?

【问题讨论】:

    标签: c unix kernel mmap


    【解决方案1】:

    首先,我想说这应该作为一个很好的论据不要使用 mmap 不必要地作为“优化读取”或类似的。除了设备删除之外,其他进程截断文件等问题也可能导致访问出现SIGBUS 错误。

    如果您确实需要使用mmap,您可以为SIGBUS 安装信号处理程序。它的任务基本上应该是:

    1. 设置发生SIGBUS 的全局(或线程本地,如果您的程序是多线程的)标志,以便可以知道错误代码。
    2. 使用MAP_FIXED 调用mmap 以在错误页面的顶部映射一个新的匿名页面。可以选择用访问地图的代码将其识别为错误的数据填充它;这可能使第 1 步变得不必要。

    另一种方法是在访问地图之前设置一个全局(或线程本地)jmp_buf,并让信号处理程序简单地调用longjmp

    请注意,mmaplongjmp 都不是异步信号安全的,但有问题的 SIGBUS 不是异步信号(尽管如果错误访问发生在非异步内部,它可能应该被视为异步信号) -信号安全库函数,例如sscanf)。只要它是您自己的代码,而不是库函数,访问地图,您应该是安全的。而mmap 在大多数/所有现实世界的实现中都是异步信号安全的,因此即使第一个解决方案在实践中不正确,您也应该可以接受。

    【讨论】:

    • 会这样说:mmap 的功能远比表面上看到的要多——因为错误处理比传统 I/O 复杂得多。这不一定是_反对使用_mmap 的原因……只要注意你召唤的灵魂;-)
    • 并确保它们不会飞出你的鼻子...... :-)
    【解决方案2】:

    最简单的事情是设置一个信号处理程序,它将检查对与mmaped 地址相对应的内存位置的访问。

    您将使用sigaction 形式的信号处理程序,而不是更简单的signal 处理程序,因为sigaction 处理程序在与信号地址对应的struct __siginfo * 参数中接收信息。可以检查它是否在mmaped文件的地址范围内。

    mmap 非常适合当您不想处理缓冲区读取/写入数据的复杂性时,但由于出现问题您只会得到一种形式的错误(信号)。使用read/write 机制,您可以获得errno 并确定发生了什么。在这种情况下,这在很大程度上是开发人员的选择。

    要在收到信号后跳转到某个位置,则需要使用setjmplongjmp/siglongjmp - 请参阅this question 中的一些用法

    【讨论】:

      【解决方案3】:

      不要访问不可用的文件。检查文件是否还在,或者使用无法卸载的文件。

      【讨论】:

      • 由于可能的竞争条件,我认为这不是很有帮助。在访问映射区域的代码周围期待和捕获SIGBUS 是否有帮助?或者类似的东西?
      • 没有。 SIGBUS 不一定是可恢复的,尽管一些实现在从处理程序返回后重试错误指令。
      • @SimonRichter 你不需要重试错误指令,你只需要确定你不能继续读/写,之后你停止尝试访问该区域并返回到带有一些错误指示的调用者。也许setjmp()/longjmp() 能够避免错误指令的重新执行。
      • @SimonRichter:SIGBUS 是可恢复的。你可以longjmp out(可能会很乱),或者(更容易)mmapMAP_FIXED 在错误页面顶部添加一个新的匿名地图。
      • @R.. 并非在所有平台上。许多人确实在从处理程序返回时重试错误指令,这允许按照您的建议创建新的映射,但这不是一个普遍的保证。
      【解决方案4】:

      您可以使用http://linux.die.net/man/7/inotify 获得有关文件、目录的任何更改的通知。 您可以考虑使用 IN_DELETE。

      【讨论】:

      • 这些通知会像 OP 试图遏制的页面错误一样即时吗?如果没有,请不要打扰。
      • 看来您必须致电read() 以了解是否有任何更改,但更改可能发生在read() 不返回任何感兴趣的内容和以下内存访问之间。这是一个竞赛条件。此外,事件队列可能会溢出。所以,这不是解决方案。
      猜你喜欢
      • 2015-11-16
      • 2014-05-06
      • 1970-01-01
      • 1970-01-01
      • 2012-11-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多