Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++/Windows: How to report an out-of-memory exception (bad_alloc)?

I'm currently working on an exception-based error reporting system for Windows MSVC++ (9.0) apps (i.e. exception structures & types / inheritance, call stack, error reporting & logging and so on).

My question now is: how to correctly report & log an out-of-memory error?

When this error occurs, e.g. as an bad_alloc thrown by the new op, there may be many "features" unavailable, mostly concerning further memory allocation. Normally, I'd pass the exception to the application if it has been thrown in a lib, and then using message boxes and error log files to report and log it. Another way (mostly for services) is to use the Windows Event Log.
The main problem I have is to assemble an error message. To provide some error information, I'd like to define a static error message (may be a string literal, better an entry in a message file, then using FormatMessage) and include some run-time info such as a call stack.
The functions / methods necessary for this use either

  • STL (std::string, std::stringstream, std::ofstream)
  • CRT (swprintf_s, fwrite)
  • or Win32 API (StackWalk64, MessageBox, FormatMessage, ReportEvent, WriteFile)

Besides being documented on the MSDN, all of them more (Win32) or less (STL) closed source in Windows, so I don't really know how they behave under low memory problems.

Just to prove there might be problems, I wrote a trivial small app provoking a bad_alloc:

int main()
{
    InitErrorReporter();  

    try
    {
        for(int i = 0; i < 0xFFFFFFFF; i++)
        {
            for(int j = 0; j < 0xFFFFFFFF; j++)
            {
                char* p = new char;
            }
        }
    }catch(bad_alloc& e_b)
    {
        ReportError(e_b);
    }

    DeinitErrorReporter();

    return 0;
}

Ran two instances w/o debugger attached (in Release config, VS 2008), but "nothing happened", i.e. no error codes from the ReportEvent or WriteFile I used internally in the error reporting. Then, launched one instance with and one w/o debugger and let them try to report their errors one after the other by using a breakpoint on the ReportError line. That worked fine for the instance with the debugger attached (correctly reported & logged the error, even using LocalAlloc w/o problems)! But taskman showed a strange behaviour, where there's a lot of memory freed before the app exits, I suppose when the exception is thrown.


Please consider there may be more than one process [edit] and more than one thread [/edit] consuming much memory, so freeing pre-allocated heap space is not a safe solution to avoid a low memory environment for the process which wants to report the error.

Thank you in advance!

like image 654
dyp Avatar asked Aug 20 '10 17:08

dyp


2 Answers

"Freeing pre-allocated heap space...". This was exactly that I thought reading your question. But I think you can try it. Every process has its own virtual memory space. With another processes consuming a lot of memory, this still may work if the whole computer is working.

like image 177
Alex F Avatar answered Oct 17 '22 02:10

Alex F


  • pre-allocate the buffer(s) you need
  • link statically and use _beginthreadex instead of CreateThread (otherwise, CRT functions may fail) -- OR -- implement the string concat / i2a yourself
  • Use MessageBox (MB_SYSTEMMODAL | MB_OK) MSDN mentions this for reporting OOM conditions (and some MS blogger described this behavior as intended: the message box will not allocate memory.)

Logging is harder, at the very least, the log file needs to be open already.

Probably best with FILE_FLAG_NO_BUFFERING and FILE_FLAG_WRITE_THROUGH, to avoid any buffering attempts. The first one requires that writes and your memory buffers are sector aligned (i.e. you need to query GetDiskFreeSpace, align your buffer by that, and write only to "multiple of sector size" file offsets, and in blocks that are multiples of sector size. I am not sure if this is necessary, or helps, but a system-wide OOM where every allocation fails is hard to simulate.

like image 33
peterchen Avatar answered Oct 17 '22 00:10

peterchen