Improve terminate handler behavior when there's no active exception and also try to print a trace for non-cpptrace terminates

This commit is contained in:
Jeremy 2023-10-08 14:55:21 -04:00
parent f6f64954de
commit ae484f0ed2
No known key found for this signature in database
GPG Key ID: 19AA8270105E8EB4
2 changed files with 28 additions and 9 deletions

View File

@ -114,7 +114,8 @@ namespace cpptrace {
inline const_iterator cbegin() const noexcept { return frames.cbegin(); } inline const_iterator cbegin() const noexcept { return frames.cbegin(); }
inline const_iterator cend() const noexcept { return frames.cend(); } inline const_iterator cend() const noexcept { return frames.cend(); }
private: private:
CPPTRACE_API void print(std::ostream& stream, bool color, bool newline_at_end) const; CPPTRACE_API void print(std::ostream& stream, bool color, bool newline_at_end, const char* header) const;
friend void print_terminate_trace();
}; };
CPPTRACE_API raw_trace generate_raw_trace(std::uint_least32_t skip = 0); CPPTRACE_API raw_trace generate_raw_trace(std::uint_least32_t skip = 0);

View File

@ -160,15 +160,15 @@ namespace cpptrace {
CPPTRACE_API CPPTRACE_API
void stacktrace::print(std::ostream& stream, bool color) const { void stacktrace::print(std::ostream& stream, bool color) const {
print(stream, color, true); print(stream, color, true, nullptr);
} }
CPPTRACE_API CPPTRACE_API
void stacktrace::print(std::ostream& stream, bool color, bool newline_at_end) const { void stacktrace::print(std::ostream& stream, bool color, bool newline_at_end, const char* header) const {
if(color) { if(color) {
detail::enable_virtual_terminal_processing_if_needed(); detail::enable_virtual_terminal_processing_if_needed();
} }
stream<<"Stack trace (most recent call first):"<<std::endl; stream<<(header ? header : "Stack trace (most recent call first):")<<std::endl;
std::size_t counter = 0; std::size_t counter = 0;
if(frames.empty()) { if(frames.empty()) {
stream<<"<empty trace>"<<std::endl; stream<<"<empty trace>"<<std::endl;
@ -237,7 +237,7 @@ namespace cpptrace {
CPPTRACE_API CPPTRACE_API
std::string stacktrace::to_string(bool color) const { std::string stacktrace::to_string(bool color) const {
std::ostringstream oss; std::ostringstream oss;
print(oss, color, false); print(oss, color, false, nullptr);
return std::move(oss).str(); return std::move(oss).str();
} }
@ -329,27 +329,45 @@ namespace cpptrace {
CPPTRACE_API extern const int stdout_fileno = detail::fileno(stdout); CPPTRACE_API extern const int stdout_fileno = detail::fileno(stdout);
CPPTRACE_API extern const int stderr_fileno = detail::fileno(stderr); CPPTRACE_API extern const int stderr_fileno = detail::fileno(stderr);
CPPTRACE_FORCE_NO_INLINE void print_terminate_trace() {
generate_trace(1).print(
std::cerr,
isatty(stderr_fileno),
true,
"Stack trace to reach terminate handler (most recent call first):"
);
}
[[noreturn]] CPPTRACE_API void terminate_handler() { [[noreturn]] CPPTRACE_API void terminate_handler() {
try { try {
std::rethrow_exception(std::current_exception()); auto ptr = std::current_exception();
if(ptr == nullptr) {
std::cerr << "terminate called without an active exception\n";
print_terminate_trace();
} else {
std::rethrow_exception(ptr);
}
} catch(cpptrace::exception& e) { } catch(cpptrace::exception& e) {
std::cerr << "Terminate called after throwing an instance of " std::cerr << "Terminate called after throwing an instance of "
<< cpptrace::demangle(typeid(e).name()) << demangle(typeid(e).name())
<< ": " << ": "
<< e.get_raw_what() << e.get_raw_what()
<< '\n'; << '\n';
e.get_trace().print(std::cerr, cpptrace::isatty(cpptrace::stderr_fileno)); e.get_trace().print(std::cerr, isatty(stderr_fileno));
} catch(std::exception& e) { } catch(std::exception& e) {
std::cerr << "Terminate called after throwing an instance of " std::cerr << "Terminate called after throwing an instance of "
<< cpptrace::demangle(typeid(e).name()) << demangle(typeid(e).name())
<< ": " << ": "
<< e.what() << e.what()
<< '\n'; << '\n';
print_terminate_trace();
} catch(...) { } catch(...) {
std::cerr << "Terminate called after throwing an instance of " std::cerr << "Terminate called after throwing an instance of "
<< detail::exception_type_name() << detail::exception_type_name()
<< "\n"; << "\n";
print_terminate_trace();
} }
std::flush(std::cerr);
abort(); abort();
} }