Reporting Crashes in IMVU: Part II: C++ Exceptions

A year ago, I explained
how the IMVU client automatically reports unexpected Python exceptions
(crashes) to us. I intended that post to be the first of a long
series that covered all of the tricks we use to detect and report
abnormal situations. Clearly, my intentions have not played out yet,
so I am going to pick up that series by describing how we catch
exceptions that occur in our C++ code. Without further ado,

Reporting C++ Exceptions

As discussed earlier, IMVU’s error handling system can handle any
Python exception that bubbles out of the client’s main loop and
automatically report the failure back to us so that we can fix it for
the next release. However, our application is a
combination of Python and C++, so what happens if our C++ code has a
bug and raises an uncaught C++ exception, such as std::bad_alloc
or std::out_of_range?

Most of our C++ code is exposed to Python via the excellent
Boost.Python library, which automatically catches C++ exceptions at
the boundary and translates them to Python exceptions. The
translation layer looks something like this:

bool handle_errors(function fn) {
    try {
        fn();
        return false; // no error
    }
    catch (const std::runtime_error& e) {
        // raise RuntimeError into Python
        PyErr_SetString(PyExc_RuntimeError, e.what());
    }
    catch (const std::bad_alloc&) {
        // raise MemoryError into Python
        PyErr_SetString(PyExc_MemoryError, "out of memory");
    }
    catch (const std::exception& e) {
        // raise Exception into Python
        PyErr_SetString(PyExc_Exception, e.what());
    }
    catch (...) {
        PyErr_SetString(PyExc_Exception, "Unknown C++ exception");
    }
    return true;
}

Thus, any C++ exception that’s thrown by the C++ function is
caught by Boost.Python and reraised as the appropriate Python
exception, which will already be handled by the previously-discussed
crash reporting system.

Let’s take another look at the client’s main loop:

def mainLoop():
    while running:
        pumpWindowsMessages()
        updateAnimations()
        redrawWindows()

def main():
    try:
        mainLoop()
    except:
        # includes exception type, exception value, and python stack trace
        error_information = sys.exc_info()
        if OK == askUserForPermission():
            submitError(error_information)

If the C++ functions called from updateAnimations() or redrawWindows()
raise a C++ exception, it will be caught by the Python error-handling
code and reported to us the same way Python
exceptions are.

Great! But is this a complete solution to the problem? Exercise
for the reader: what else could go wrong here? (Hint: we use Visual
Studio 2005 and there was a bug in catch (…) that Microsoft fixed in
Visual Studio 2008…)

2 thoughts on “Reporting Crashes in IMVU: Part II: C++ Exceptions”

  1. Traceback (most recent call last):
    File “main\clientapp.pyo”, line 1233, in runClientApp ()
    File “contextlib.pyo”, line 16, in __enter__ (self=)
    File “main\clientapp.pyo”, line 1197, in deadlockDetection (serviceProvider=)
    File “util\thread.pyo”, line 168, in enableNativeDeadlockDetection ()
    StructuredException: EXCEPTION_ILLEGAL_INSTRUCTION(c000001d)
    Parameters: []
    (#00000000000000000000000000000000!00000000, pc=02abb420)
    (#00000000000000000000000000000000!00000000, pc=008f1030)
    (#00000000000000000000000000000000!00000000, pc=00f50270)
    (PYTHON26.DLL#0abcd2a9d25e4e8ab80506bee79b65e61!000d28cd, pc=1e0d28cd)
    (#00000000000000000000000000000000!00000000, pc=02abb420)
    (#00000000000000000000000000000000!00000000, pc=008f1030)
    (#00000000000000000000000000000000!00000000, pc=02abb420)
    (#00000000000000000000000000000000!00000000, pc=008f1030)
    (#00000000000000000000000000000000!00000000, pc=0012eff0)
    (PYTHON26.DLL#0abcd2a9d25e4e8ab80506bee79b65e61!0006b60c, pc=1e06b60c)
    (boost_python.dll#c60ea3faaad249c1b76818a0f71a79761!0000c331, pc=014dc331)
    (boost_python.dll#c60ea3faaad249c1b76818a0f71a79761!00015f25, pc=014e5f25)
    (boost_python.dll#c60ea3faaad249c1b76818a0f71a79761!00015e76, pc=014e5e76)
    (boost_python.dll#c60ea3faaad249c1b76818a0f71a79761!00015bcf, pc=014e5bcf)
    (boost_python.dll#c60ea3faaad249c1b76818a0f71a79761!0001572f, pc=014e572f)
    (_avatarwindow.pyd#f24cc84a4c524336b55ccf87dd0ed7e81!0002f2c6, pc=012af2c6)
    (_avatarwindow.pyd#f24cc84a4c524336b55ccf87dd0ed7e81!0002f3a5, pc=012af3a5)
    (boost_python.dll#c60ea3faaad249c1b76818a0f71a79761!00015f86, pc=014e5f86)
    (boost_python.dll#c60ea3faaad249c1b76818a0f71a79761!0001604d, pc=014e604d)
    (boost_python.dll#c60ea3faaad249c1b76818a0f71a79761!0000cdd9, pc=014dcdd9)
    (_avatarwindow.pyd#f24cc84a4c524336b55ccf87dd0ed7e81!0002dd8a, pc=012add8a)
    (SceneWindow.dll#47a10c8c456b4b48b8bad8274b1e3cb51!000564fe, pc=015964fe)
    (SceneWindow.dll#47a10c8c456b4b48b8bad8274b1e3cb51!000565c7, pc=015965c7)

Leave a Reply

Your email address will not be published. Required fields are marked *