分段故障和RAII

Segmentation Fault and RAII

本文关键字:RAII 故障 分段      更新时间:2023-10-16

这更像是一个哲学类型的问题。

C++中,我们有一个很好的闪亮成语-RAII。但我经常认为它是不完整的。这与我的应用程序可以用SIGSEGV杀死这一事实并不一致。

我知道,我知道,像这样的程序是错误的你说。但有一个可悲的事实是,在POSIX(特别是Linux)上,您可以分配超出物理内存限制的内存,并在执行过程中满足SIGSEGV,使用正确分配的内存。

您可能会说:"应用程序死了,为什么要关心那些糟糕的析构函数没有被调用呢?"。不幸的是,有些资源在应用程序终止时不会自动释放,例如文件系统实体。

我现在已经厌倦了设计技巧,破坏好的应用程序设计来应对这种情况。所以,我所要求的是为这类问题找到一个好的、优雅的解决方案。

编辑

看来我错了,Linux上的应用程序被内核寻呼机杀死了。在这种情况下,问题仍然相同,但申请死亡的原因不同。

代码片段:

struct UnlinkGuard
{
    UnlinkGuard(const std::string path_to_file)
        : _path_to_file(path_to_file)
    { }
    ~UnlinkGuard() {
        unlink();
    }
    bool unlink() {
        if (_path_to_file.empty())
            return true;
        if (::unlink(_path_to_file.c_str())) {
            /// Probably some logging.
            return false;
        }
        disengage();
        return true;
    }
    void disengage() {
        _path_to_file.clear();
    }
private:
    std::string _path_to_file;
};
void foo()
{
    /// Pick path to temp file.
    std::string path_to_temp_file = "...";
    /// Create file.
    /// ...
    /// Set up unlink guard.
    UnlinkGuard unlink_guard(path_to_temp_file);
    /// Call some potentially unsafe library function that can cause process to be killed either:
    ///  * by a SIGSEGV
    ///  * by out of memory
    /// ...
    /// Work done, file content is appropriate.
    /// Rename tmp file.
    /// ...
    /// Disengage unlink guard.
    unlink_guard.disengage();
}

一旦成功,我就用锉刀。失败时,我希望此文件丢失。

如果POSIX支持按文件描述符对以前未链接的文件进行link()绑定,但没有这样的功能:(.

所以,我所要求的是为这类问题找到一个好的、优雅的解决方案。

无论是C++还是其他语言,都不存在。在这里,你面临的是一个基本的物理现实,而不是设计决策:当用户拔下插头时会发生什么?没有任何编程解决方案可以防止这种情况(好吧,重启后会恢复)。

所能做的是捕获POSIX信号,有时甚至可以处理它们——但这很古怪,而且有很多注意事项,另一个关于堆栈溢出的讨论对此进行了详细说明。

大多数资源不应该在segfault之后被清除。如果您无论如何都想这样做,只需在全局数组中收集这些资源(或者更确切地说,用于清理的处理程序),捕获SIGSEGV,在处理程序中迭代清理例程数组(希望相关内存仍然完好无损),然后执行清理。

更具体地说,对于临时文件,在系统的一个临时文件夹中创建它们会有所帮助。可以理解的是,它们并不总是由各自的应用程序进行清理,而是由系统或用户定期执行清理。

通常,无论语言或操作系统如何,解决方案都是在启动程序时清理,而不是(仅)在终止程序时清理。如果您的程序可以创建临时文件并在关闭时进行清理,请在启动程序时也清理这些临时文件。

当您的应用程序失效时,大多数其他东西,如文件句柄、tcp连接等,都会被操作系统杀死。