Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Segmentation Fault and RAII

It's more a philosophical type of question.

In C++ we have nice shiny idiom - RAII. But often I see it as incomplete. It does not well aligns with the fact that my application can be killed with SIGSEGV.

I know, I know, programms like that are malformed you say. But there is sad fact that on POSIX (specifically Linux) you can allocate beyond physical memory limits and meet SIGSEGV in the middle of the execution, working with correctly allocated memory.

You may say: "Application dies, why should you care about those poor destructors not being called?". Unfortunately there are some resources that are not automatically freed when application terminates, such as File System entities.

I am pretty sick right now of designing hacks, breaking good application design just to cope with this. So, what I am asking is for a nice, elegant solution to this kind of problems.

Edit:

It seems that I was wrong, and on Linux applications are killed by a kernel pager. In which case the question is still the same, but the cause of application death is different.

Code snippet:

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();
}

On success I use file. On failure I want this file to be missing.

This could be achived if POSIX had support for link()-ing of previously unlinked file by file descriptor, but there is no such feature :(.

like image 362
GreenScape Avatar asked Sep 11 '14 07:09

GreenScape


People also ask

What is a segmentation fault?

A segmentation fault (aka segfault) is a common condition that causes programs to crash; they are often associated with a file named core . Segfaults are caused by a program trying to read or write an illegal memory location.

What happens during segmentation fault?

A segmentation fault occurs when a program attempts to access a memory location that it is not allowed to access, or attempts to access a memory location in a way that is not allowed (for example, attempting to write to a read-only location, or to overwrite part of the operating system).

Is segmentation fault a memory error?

Segmentation fault is an error caused by accessing invalid memory, e.g., accessing variable that has already been freed, writing to a read-only portion of memory, or accessing elements out of range of the array, etc.

What causes segmentation fault in C++?

Core Dump/Segmentation fault is a specific kind of error caused by accessing memory that “does not belong to you.” When a piece of code tries to do read and write operation in a read only location in memory or freed block of memory, it is known as core dump. It is an error indicating memory corruption.


2 Answers

So, what I am asking is for a nice, elegant solution to this kind of problems.

None exists, neither for C++ nor for other languages. You are faced with a fundamental physical reality here, not a design decision: what happens when the user pulls the plug? No programming solution can guard against that (well, there’s restore-upon-restart).

What you can do is catch POSIX signals and sometimes you can even handle them – but it’s flakey and there are tons of caveats, which another discussion on Stack Overflow details.

Most resources should not be cleared up after a segfault. If you want to do it anyway, simply collect those resources (or rather, handlers for their cleanup) in a global array, trap SIGSEGV, iterate through the cleanup routine array in the handler (hoping that the relevant memory is still intact), and perform the cleanup.

More specifically, for temporary files it helps to create them inside one of the system’s temporary folders. It’s understood that these don’t always get cleaned up by their respective applications, and either the system or the user will periodically perform cleanup instead.

like image 162
Konrad Rudolph Avatar answered Sep 20 '22 06:09

Konrad Rudolph


Usually the solution, regardless of language or OS, is to clean up when you start the program, not (only) when you terminate. If your program can create temporary files that it cleans up on shutdown, clean up the temporary files when you start the program too.

Most everything else, like file handles, tcp connections, and so forth, is killed by the OS when your application dies.

like image 45
Peter Avatar answered Sep 20 '22 06:09

Peter