2

Our project uses Boost.Test for our units tests. We would like to get minidumps when unexpected exceptions occur during our test cases as well, so we've started integrating Google Breakpad to write the minidumps.

It looks like Boost.Test is intercepting all thrown exceptions from user tests - I'm assuming because Boost test cases wrap each function with a try / catch and the unit test simply fails if an unexpected exception is thrown. This prevents the Breakpad exception handler from firing and writing minidumps.

Is it possible to have Boost.Test not just catch and fail on unexpected exceptions in unit tests? And to instead let the exceptions go unhandled (or rethrow) so Breakpad or another exception handler can be triggered to write a minidump?

mbradber
  • 489
  • 5
  • 17

2 Answers2

1

Boost.Test is designed to catch all exceptions from a test case in order to continue executing other test cases. I don't think you can turn this behavior off, but you can always consult the source code.

To achieve what you're after, I'd wrap the body of the test cases myself and catch exceptions and have breakpad minidumps written out when unexpected exceptions are thrown. You can genericize this by writing the catch/dump handler as a function that accepts a functor that is your test case body and invoking your handler with the test case body in a lambda:

void handler(std::function<void()> test_case)
{
  try {
    test_case();
  } catch (...) {
    write_minidump();
  }
}

BOOST_AUTO_TEST_CASE(doit)
{
  handler([] {
    // do testing here
  });
}

It will be more involved if you're using fixtures, but the same idea would apply.

legalize
  • 2,214
  • 18
  • 25
  • I like this suggestion, however by the time the minidump is written in the catch block, the callstack that is saved in the minidump just shows 'handler' at the top of the stack. However, when an 'unhandled exception filter' is triggered and the dump is written, the offending callstack is preserved. – mbradber Oct 04 '17 at 19:41
  • How does breakpad setup the exception handler? – legalize Oct 04 '17 at 19:52
  • https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/windows_client_integration.md I've created an ExceptionHandler based on the doc there. With just this Breakpad sets its own unhandled exception filter callback, and unhandled exceptions produce minidumps nicely. However, I'm using the 'WriteMinidump' API explicitly in a catch block similar to what you've posted. – mbradber Oct 04 '17 at 19:59
  • 1
    Yeah, if you write a minidump captured at the point of the `catch`, then you will only have `handler` in your stack. Somehow you need to capture the call stack at the point of throwing the exception. I'm not sure how breakpad is doing that. I know that in Windows SEH you can query this information from the catch handler. – legalize Oct 05 '17 at 17:17
1

I tried a few different approaches but the following solution provides the best result. Defining a macro to wrap the BOOST_AUTO_TEST_CASE macro, and surrounding the calling code with SEH __try/__except and piping the exception data into Breakpad.

#define CUSTOM_AUTO_TEST_CASE( test_name )                                                                  \
void test_name##_custom_wrapper();                                                                          \
                                                                                                            \
BOOST_AUTO_TEST_CASE( test_name )                                                                           \
{                                                                                                           \
    __try                                                                                                   \
    {                                                                                                       \
        test_name##_custom_wrapper();                                                                       \
    }                                                                                                       \
    __except(pHandler->WriteMinidumpForException(GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER) {}  \
}                                                                                                           \
                                                                                                            \
void test_name##_custom_wrapper()                                                                           \

Where pHandler is a Breakpad ExceptionHandler pointer.

The downside is you have to replace every occurrence of BOOST_AUTO_TEST_CAST with the wrapper macro. But it does the trick.

mbradber
  • 489
  • 5
  • 17