Search code examples
c++winapistructatexitmember-functions

Trying to pass a struct member function to atexit


I am writing a debugger in C++ and upon exit I need it to cleanup any breakpoints set in the debuggee.

I have made a struct called BREAKPOINT_INFO that contains the information needed to cleanup each breakpoint. Information such as a handle to the process(hProcess), the virtual memory address of the breakpoint(lpBreakPoint), and the opcode of the original instruction that was replaced(instr).

I then have a CleanUp member function that uses the data members described above to restore the original instruction so the debuggee doesn't crash.

typedef struct
{
    HANDLE hProcess;

    PCHAR  lpBreakPoint;

    CHAR   instr;

    void CleanUp()
    {
        DWORD dwError = 0;
        std::ostringstream oss;
        LPSTR szErrorRest = (LPSTR)"Error restoring original instruction: ";

        if(!WriteProcessMemory(hProcess, lpBreakPoint, &instr, sizeof(CHAR), NULL))
        {
            dwError = GetLastError();

            oss << szErrorRest << dwError;

            szErrorRest = oss.str().c_str();

            MessageBox(NULL, szErrorRest, "ERROR", MB_OK|MB_ICONERROR);
        }
    }
}BREAKPOINT_INFO, *PBREAKPOINT_INFO;

However, when I try to pass my member function for each BREAKPOINT_INFO structure, I get a compilation error:

C:\...\...\main.cpp|39|error: cannot convert 'BREAKPOINT_INFO::CleanUp' from type 'void (BREAKPOINT_INFO::)()' to type 'void (__attribute__((__cdecl__)) *)()'|

And even after trying to cast to that type it fails to compile. Is it possible to pass a member function to atexit? And if so, how would I go about doing so? Thank you for your time.


Solution

  • No you cannot pass anything other than a function pointer to atexit, as specified by its declaration.

    int atexit (void (*func)(void)) noexcept
    

    A member function is not a free function.
    As you can see in your error message, it has type void (BREAKPOINT_INFO::)() which is not the same as void ().

    A pointer to member function in fact, takes an extra first parameter to specify which instance of the class is invoking the member function.

    auto member_function_pointer = BREAKPOINT_INFO::CleanUp;
    BREAKPOINT_INFO some_info;
    member_function_pointer(&some_info);  //is equivalent to...
    some_info.CleanUp();
    

    And no, you cannot pass a capturing lambda as a function pointer. A non capturing lambda has an public non-virtual non-explicit const conversion function to pointer to function, which may be the source of misconception that a function pointer can point to other things.

    What you should do instead, as mentioned in the comments, is to use a destructor to do cleanup work. This pattern is known as RAII, and is by far one of the best.


    As a sidenote, you don't need to do crazy typedef on struct declarations in C++, what you are writing looks a lot like C with methods.