4
0
mirror of https://github.com/QuasarApp/backward-cpp.git synced 2025-05-04 22:09:35 +00:00
This commit is contained in:
François-Xavier Bourlet 2014-07-14 20:33:31 -07:00
parent c3dd434ec8
commit b0568e3042
3 changed files with 214 additions and 105 deletions

@ -480,7 +480,7 @@ template <typename TAG>
class StackTraceImpl {
public:
size_t size() const { return 0; }
Trace operator[](size_t) { return Trace(); }
Trace operator[](size_t) const { return Trace(); }
size_t load_here(size_t=0) { return 0; }
size_t load_from(void*, size_t=0) { return 0; }
unsigned thread_id() const { return 0; }
@ -519,7 +519,7 @@ public:
size_t size() const {
return _stacktrace.size() ? _stacktrace.size() - skip_n_firsts() : 0;
}
Trace operator[](size_t idx) {
Trace operator[](size_t idx) const {
if (idx >= size()) {
return Trace();
}
@ -2047,12 +2047,12 @@ private:
class exception_with_st {
public:
#ifdef BACKWARD_ATLEAST_CXX11
virtual ~exception_with_st() {}
virtual ~exception_with_st() noexcept {}
#else
virtual ~exception_with_st() throw() {}
#endif
exception_with_st() { _st.load_here(); }
StackTrace& stacktrace() { return _st; }
const StackTrace& stacktrace() const { return _st; }
virtual void rethrow() const = 0;
private:
StackTrace _st;
@ -2061,98 +2061,119 @@ private:
template <typename E>
class exception_with_st_mixin: public E, public exception_with_st {
public:
#ifdef BACKWARD_ATLEAST_CXX11
virtual ~exception_with_st_mixin() noexcept {}
#else
virtual ~exception_with_st_mixin() throw() {}
#endif
exception_with_st_mixin(const E& e):
E(e), exception_with_st() {}
virtual void rethrow() const { throw static_cast<const E&>(*this); }
};
class ExceptionHandling {
/*************** EXCEPTION PRINTER **************/
class ExceptionPrinter {
public:
static ExceptionHandling& instance() {
static ExceptionHandling instance;
return instance;
}
void print_current_exception() {
const std::type_info* exception_type = current_exception_type();
if (not exception_type) {
fprintf(stderr, "No exception in flight to be printed.\n");
return;
}
void enable() {
_original_handler = std::set_terminate(&terminate_handler);
}
void disable() {
std::set_terminate(_original_handler);
}
static void pprint_current_exception() {
fprintf(stderr, "Printing exception in flight from here:\n");
_nested_level = 0;
StackTrace st;
st.load_here();
print_exception(&st);
print_stacktrace(st);
print_exception_in_flight();
}
private:
std::terminate_handler _original_handler;
unsigned _nested_level;
ExceptionHandling() {}
~ExceptionHandling() {}
static void terminate_handler() {
pprint_current_exception();
SignalHandling::instance().abort();
abort();
const std::type_info* current_exception_type() {
return abi::__cxa_current_exception_type();
}
static void print_exception(StackTrace* st = 0) {
const std::type_info* current_exception =
abi::__cxa_current_exception_type();
if (not current_exception) {
return;
std::string exception_typename(const std::type_info* const exception_type) {
return details::demangler().demangle(exception_type->name());
}
void print_exception_in_flight() {
const std::string typename_ =
exception_typename(current_exception_type());
for (unsigned i = 1; i < _nested_level; ++i) {
fprintf(stderr, " ");
}
const std::string exception_typename =
details::demangler().demangle(current_exception->name());
if (st) {
print_stacktrace(*st);
if (_nested_level > 0) {
fprintf(stderr, " - ");
}
try {
throw; // rethrow whatever we have got.
} catch (exception_with_st& e) {
fprintf(stderr, "Exception originally thrown from:\n");
print_stacktrace(e.stacktrace());
try {
e.rethrow();
} catch (...) {
print_exception();
}
} catch (const std::nested_exception& e) {
fprintf(stderr, "Nested exception #%u (%s): %s\n", _nested_level,
typename_.c_str(), dynamic_cast<const std::exception&>(e).what());
print_if_nested(dynamic_cast<const std::exception&>(e));
// } catch (const exception_with_st& e) {
// fprintf(stderr, "Exception raised with a stacktrace:\n");
//print_stacktrace(e.stacktrace());
// try {
// e.rethrow();
// } catch (...) {
// print_exception();
// }
} catch (const std::exception& e) {
fprintf(stderr, "Exception (%s): %s\n",
exception_typename.c_str(), e.what());
if (_nested_level > 0) {
fprintf(stderr, "Nested exception #%u (%s): %s\n",
_nested_level, typename_.c_str(), e.what());
} else {
fprintf(stderr, "Exception (%s): %s\n",
typename_.c_str(), e.what());
}
print_if_nested(e);
} catch (...) {
fprintf(stderr, "Exception (%s).\n",
exception_typename.c_str());
fprintf(stderr, "Exception (%s).\n", typename_.c_str());
}
}
static bool is_start_of_trace(const std::string& function) {
#ifdef BACKWARD_ATLEAST_CXX11
void print_if_nested(const std::exception& e) {
try {
std::rethrow_if_nested(e);
} catch (...) {
_nested_level += 1;
print_exception_in_flight();
}
}
#endif // BACKWARD_ATLEAST_CXX11
bool is_start_of_trace(const std::string& function) {
if (function == "__cxa_throw") {
return true;
}
if (function == "__cxa_rethrow") {
return true;
}
if (function.find("backward::raise")
if (function.find("backward::throw_with_st")
!= std::string::npos) {
return true;
}
if (function.find("backward::raise<")
if (function.find("backward::pprint_current_exception")
!= std::string::npos) {
return true;
}
if (function.find("pprint_current_exception")
if (function.find("std::throw_with_nested")
!= std::string::npos) {
return true;
}
return false;
}
static void print_stacktrace(StackTrace& st) {
void print_stacktrace(const StackTrace& st) {
typedef std::vector<ResolvedTrace> resolved_traces_t;
resolved_traces_t resolved_traces;
resolved_traces.reserve(st.size());
@ -2187,11 +2208,54 @@ private:
printer.print(resolved_traces.begin(), resolved_traces.end(), stderr,
st.thread_id());
}
};
static const std::string current_exception_typename() {
return details::demangler().demangle(
abi::__cxa_current_exception_type()->name()
);
/************** EXCEPTION HANDLING **************/
class ExceptionHandling {
public:
static ExceptionHandling& instance() {
static ExceptionHandling instance;
return instance;
}
void enable() {
_original_handler = std::set_terminate(&terminate_handler);
}
void disable() {
std::set_terminate(_original_handler);
}
private:
std::terminate_handler _original_handler;
ExceptionHandling() {}
~ExceptionHandling() {}
static void terminate_handler() {
ExceptionPrinter printer;
printer.print_current_exception();
// StackTrace st;
// st.load_here();
// const std::type_info* const exception_type = current_exception_type();
// if (exception_type) {
// fprintf(stderr,
// "terminate called after throwing an instance of '%s'\n",
// exception_typename(current_exception_type()).c_str());
// print_stacktrace(st);
// print_exception(exception_typename(exception_type));
// fprintf(stderr,
// "terminate called after throwing an instance of '%s'\n",
// exception_typename(current_exception_type()).c_str());
// } else {
// print_stacktrace(st);
// fprintf(stderr, "terminate called without an active exception\n");
// }
fprintf(stderr, "terminate called\n");
SignalHandling::instance().abort();
::abort();
}
};
@ -2224,12 +2288,13 @@ private:
/*************** HELPERS FUNCTIONS **************/
template <typename E>
inline void raise(const E& e) {
inline void throw_with_st(const E& e) {
throw exception_with_st_mixin<E>(e);
}
inline void pprint_current_exception() {
ExceptionHandling::pprint_current_exception();
ExceptionPrinter printer;
printer.print_current_exception();
}
#ifdef BACKWARD_ATLEAST_CXX11

@ -30,20 +30,33 @@
using namespace backward;
void uncaught_level2() {
throw std::runtime_error("OmyGAAAD! Exception!");
TEST(pprint_exception_primitive) {
try {
throw 42;
} catch (...) {
backward::pprint_current_exception();
}
}
void uncaught_level1() {
uncaught_level2();
TEST(pprint_no_base_exception) {
struct error { };
try {
throw error();
} catch (...) {
backward::pprint_current_exception();
}
}
TEST_UNCAUGHT_EXCEPTION(uncaught) {
uncaught_level1();
TEST(pprint_exception) {
try {
throw std::runtime_error("This is a really useless message.");
} catch (...) {
backward::pprint_current_exception();
}
}
void another_sub_function() {
backward::raise(std::runtime_error("OmyGAAAD! Exception!"));
throw std::runtime_error("Something bad happened here.");
}
void a_sub_function() {
@ -65,22 +78,47 @@ void a_little_function() {
TEST(rethrow) {
try {
a_little_function();
} catch (const std::exception& e) {
ExceptionHandling::pprint_current_exception();
} catch (...) {
backward::pprint_current_exception();
}
}
#ifdef BACKWARD_ATLEAST_CXX11
std::exception_ptr catch_something() {
try {
throw std::runtime_error("Something bad happened here.");
} catch(...) {
return std::current_exception();
}
}
TEST(rethrow_exception_ptr) {
auto eptr = catch_something();
try {
std::rethrow_exception(eptr);
} catch (...) {
backward::pprint_current_exception();
}
}
void nested_level4() {
throw std::runtime_error("Shit's hitting the fan!");
}
void nested_level3() {
throw std::runtime_error("OmyGAAAD! Exception!");
try {
nested_level4();
} catch (std::exception& e) {
std::throw_with_nested(std::runtime_error("It's flying everywhere!"));
}
}
void nested_level2() {
try {
nested_level3();
} catch (std::exception& e) {
std::throw_with_nested(std::runtime_error("level1!"));
std::throw_with_nested(std::runtime_error("We are deep in it."));
}
}
@ -88,34 +126,34 @@ void nested_level1() {
try {
nested_level2();
} catch (std::exception& e) {
std::throw_with_nested(std::runtime_error("and level two"));
}
}
static int max_nested_level = 0;
void print_nested_ex(std::exception& e, int level=0) {
std::cout << std::string(level, ' ')
<< " - exception: " << e.what() << std::endl;
max_nested_level = std::max(max_nested_level, level);
try {
std::rethrow_if_nested(e);
} catch (std::exception& e) {
print_nested_ex(e, level + 1);
std::throw_with_nested(std::runtime_error("What a mess."));
}
}
TEST(nested) {
try {
nested_level1();
} catch (std::exception& e) {
print_nested_ex(e);
} catch (...) {
backward::pprint_current_exception();
}
ASSERT_EQ(max_nested_level, 2);
}
#endif // BACKWARD_ATLEAST_CXX11
void throw_too_far() {
throw std::runtime_error("Catch me if you can.");
}
TEST_TERMINATE_HANDLER(uncaught) {
throw_too_far();
}
// ------------------
#ifdef BACKWARD_ATLEAST_CXX11
void nested_2_level3() {
backward::raise(std::runtime_error("OmyGAAAD! Exception!"));
backward::throw_with_st(std::runtime_error("OmyGAAAD! Exception!"));
}
void nested_2_level2() {
@ -134,30 +172,36 @@ void nested_2_level1() {
}
}
static int max_nested_2_level = 0;
void print_nested_2_ex(std::exception& e, int level=0) {
std::cout << std::string(level, ' ')
<< " - exception: " << e.what() << std::endl;
max_nested_2_level = std::max(max_nested_2_level, level);
try {
std::rethrow_if_nested(e);
} catch (std::exception& e) {
print_nested_2_ex(e, level + 1);
}
}
TEST(nested2) {
try {
nested_2_level1();
} catch (std::exception& e) {
print_nested_2_ex(e);
backward::pprint_current_exception();
}
ASSERT_EQ(max_nested_2_level, 2);
}
#endif
TEST_TERMINATE_HANDLER(nested3) {
nested_2_level1();
}
#endif // BACKWARD_ATLEAST_CXX11
TEST(not_pprint_current_exception) {
backward::pprint_current_exception();
}
void uncaught2_level2() {
backward::throw_with_st(std::runtime_error("OmyGAAAD! Exception!"));
}
void uncaught2_level1() {
try {
uncaught2_level2();
} catch (...) {
std::throw_with_nested(std::runtime_error("nested"));
}
}
TEST_TERMINATE_HANDLER(uncaught2) {
uncaught2_level1();
}

@ -143,7 +143,7 @@ TestBase::TestBase(const char* n, TestStatus s, bool cth):
#define TEST_SEGFAULT(name) _TEST_STATUS(name, ::test::SIGNAL_SEGFAULT)
#define TEST_ABORT(name) _TEST_STATUS(name, ::test::SIGNAL_ABORT)
#define TEST_DIVZERO(name) _TEST_STATUS(name, ::test::SIGNAL_DIVZERO)
#define TEST_TERMINATE_HANDLER(name) _TEST_STATUS_CTH(name, ::test::EXCEPTION_UNCAUGHT)
#define TEST_TERMINATE_HANDLER(name) _TEST_STATUS_CTH(name, ::test::SIGNAL_ABORT)
#define ASSERT(expr) \
(expr) ? static_cast<void>(0) \