Skip to content
Snippets Groups Projects
Commit 9ef702db authored by Nat Goodspeed's avatar Nat Goodspeed
Browse files

DRTVWR-476: Enrich LLExceptions thrown by LLTHROW() with stack trace.

The LLTHROW() abstraction allows us to enrich the subject exception with a
boost::stacktrace -- without having to propagate the boost/stacktrace.hpp
header throughout the code base.

To my delight, our existing use of
boost::current_exception_diagnostic_information() already reports the newly
added boost::stacktrace information -- we don't have to query it specifically!
parent b41a2eff
No related branches found
No related tags found
No related merge requests found
......@@ -18,10 +18,23 @@
#include <typeinfo>
// external library headers
#include <boost/exception/diagnostic_information.hpp>
#include <boost/exception/error_info.hpp>
// On Mac, got:
// #error "Boost.Stacktrace requires `_Unwind_Backtrace` function. Define
// `_GNU_SOURCE` macro or `BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED` if
// _Unwind_Backtrace is available without `_GNU_SOURCE`."
#define BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED
#include <boost/stacktrace.hpp>
// other Linden headers
#include "llerror.h"
#include "llerrorcontrol.h"
// used to attach and extract stacktrace information to/from boost::exception,
// see https://www.boost.org/doc/libs/release/doc/html/stacktrace/getting_started.html#stacktrace.getting_started.exceptions_with_stacktrace
// apparently the struct passed as the first template param needs no definition?
typedef boost::error_info<struct errinfo_stacktrace_, boost::stacktrace::stacktrace>
errinfo_stacktrace;
namespace {
// used by crash_on_unhandled_exception_() and log_unhandled_exception_()
void log_unhandled_exception_(LLError::ELevel level,
......@@ -53,3 +66,17 @@ void log_unhandled_exception_(const char* file, int line, const char* pretty_fun
// routinely, but we DO expect to return from this function.
log_unhandled_exception_(LLError::LEVEL_WARN, file, line, pretty_function, context);
}
void annotate_exception_(boost::exception& exc)
{
// https://www.boost.org/doc/libs/release/libs/exception/doc/tutorial_transporting_data.html
// "Adding of Arbitrary Data to Active Exception Objects"
// Given a boost::exception&, we can add boost::error_info items to it
// without knowing its leaf type.
// The stacktrace constructor that lets us skip a level -- and why would
// we always include annotate_exception_()? -- also requires a max depth.
// For the nullary constructor, the stacktrace class declaration itself
// passes static_cast<std::size_t>(-1), but that's kind of dubious.
// Anyway, which of us is really going to examine more than 100 frames?
exc << errinfo_stacktrace(boost::stacktrace::stacktrace(1, 100));
}
......@@ -67,9 +67,29 @@ struct LLContinueError: public LLException
* enriches the exception's diagnostic_information() with the source file,
* line and containing function of the LLTHROW() macro.
*/
// Currently we implement that using BOOST_THROW_EXCEPTION(). Wrap it in
// LLTHROW() in case we ever want to revisit that implementation decision.
#define LLTHROW(x) BOOST_THROW_EXCEPTION(x)
#define LLTHROW(x) \
do { \
/* Capture the exception object 'x' by value. (Exceptions must */ \
/* be copyable.) It might seem simpler to use */ \
/* BOOST_THROW_EXCEPTION(annotate_exception_(x)) instead of */ \
/* three separate statements, but: */ \
/* - We want to throw 'x' with its original type, not just a */ \
/* reference to boost::exception. */ \
/* - To return x's original type, annotate_exception_() would */ \
/* have to be a template function. */ \
/* - We want annotate_exception_() to be opaque. */ \
/* We also might consider embedding BOOST_THROW_EXCEPTION() in */ \
/* our helper function, but we want the filename and line info */ \
/* embedded by BOOST_THROW_EXCEPTION() to be the throw point */ \
/* rather than always indicating the same line in */ \
/* llexception.cpp. */ \
auto exc{x}; \
annotate_exception_(exc); \
BOOST_THROW_EXCEPTION(exc); \
/* Use the classic 'do { ... } while (0)' macro trick to wrap */ \
/* our multiple statements. */ \
} while (0)
void annotate_exception_(boost::exception& exc);
/// Call this macro from a catch (...) clause
#define CRASH_ON_UNHANDLED_EXCEPTION(CONTEXT) \
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment