Add specialized terminate handler and add error handling info to the README. Also updated demo.

This commit is contained in:
Jeremy 2023-10-07 17:34:49 -04:00
parent 2e0fa880bc
commit 05c3f7160b
No known key found for this signature in database
GPG Key ID: 19AA8270105E8EB4
7 changed files with 104 additions and 8 deletions

View File

@ -106,6 +106,10 @@ else()
check_support(HAS_STACKWALK has_stackwalk.cpp "" "dbghelp" "")
endif()
if(NOT WIN32 OR MINGW)
check_support(HAS_CXX_EXCEPTION_TYPE has_cxx_exception_type.cpp "" "" "")
endif()
# =============================================== Autoconfig unwinding ===============================================
# Unwind back-ends
if(
@ -248,6 +252,10 @@ target_compile_options(
# =============================================== Apply options to build ===============================================
if(HAS_CXX_EXCEPTION_TYPE)
target_compile_definitions(cpptrace PUBLIC CPPTRACE_HAS_CXX_EXCEPTION_TYPE)
endif()
function(check_backtrace_error)
if(NOT HAS_BACKTRACE)
if(NOT "${CPPTRACE_BACKTRACE_PATH}" STREQUAL "")

View File

@ -20,6 +20,7 @@ and Windows including MinGW and Cygwin environments. The goal: Make stack traces
- [Raw Traces](#raw-traces)
- [Utilities](#utilities)
- [Traced Exceptions](#traced-exceptions)
- [Exception handling with cpptrace](#exception-handling-with-cpptrace)
- [Notable Library Configurations](#notable-library-configurations)
- [Notes About the Library and Future Work](#notes-about-the-library-and-future-work)
- [FAQ: What about C++23 `<stacktrace>`?](#faq-what-about-c23-stacktrace)
@ -226,6 +227,9 @@ performed.
`cpptrace::isatty` and the fileno definitions are useful for deciding whether to use color when printing stack taces.
`cpptrace::register_terminate_handler()` is a helper function to set a custom `std::terminate` handler that prints a
stack trace from a cpptrace exception (more info below) and otherwise behaves like the normal terminate handler.
```cpp
namespace cpptrace {
std::string demangle(const std::string& name);
@ -236,6 +240,8 @@ namespace cpptrace {
extern const int stderr_fileno;
extern const int stdout_fileno;
void register_terminate_handler();
enum class cache_mode {
// Only minimal lookup tables
prioritize_memory,
@ -300,6 +306,29 @@ namespace cpptrace {
}
```
## Exception handling with cpptrace
To register a custom handler for `std::terminate` that prints a stack trace from a cpptrace exception and otherwise
behaves like the normal terminate handler.
```cpp
cpptrace::register_terminate_handler();
```
Working with cpptrace exceptions in your code:
```cpp
try {
foo();
} catch(cpptrace::exception& e) {
// Prints the exception info and stack trace, conditionally enabling color codes depending on
// whether stderr is a terminal
std::cerr << "Error: " << e.get_raw_what() << '\n';
e.get_trace().print(std::cerr, cpptrace::isatty(cpptrace::stderr_fileno));
} catch(std::exception& e) {
std::cerr << "Error: " << e.what() << '\n';
}
```
## Notable Library Configurations
- `CPPTRACE_STATIC=On/Off`: Create cpptrace as a static library.

View File

@ -0,0 +1,6 @@
#include <cxxabi.h>
int main() {
std::type_info* t = abi::__cxa_current_exception_type();
(void*) t;
}

View File

@ -133,6 +133,8 @@ namespace cpptrace {
CPPTRACE_API extern const int stderr_fileno;
CPPTRACE_API extern const int stdout_fileno;
CPPTRACE_API void register_terminate_handler();
enum class cache_mode {
// Only minimal lookup tables
prioritize_memory,

View File

@ -14,8 +14,9 @@
#include "unwind/unwind.hpp"
#include "demangle/demangle.hpp"
#include "platform/common.hpp"
#include "platform/utils.hpp"
#include "platform/exception_type.hpp"
#include "platform/object.hpp"
#include "platform/utils.hpp"
#define ESC "\033["
#define RESET ESC "0m"
@ -328,6 +329,34 @@ namespace cpptrace {
CPPTRACE_API extern const int stdout_fileno = detail::fileno(stdout);
CPPTRACE_API extern const int stderr_fileno = detail::fileno(stderr);
CPPTRACE_API [[noreturn]] void terminate_handler() {
try {
std::rethrow_exception(std::current_exception());
} catch(cpptrace::exception& e) {
std::cerr << "Terminate called after throwing an instance of "
<< cpptrace::demangle(typeid(e).name())
<< ": "
<< e.get_raw_what()
<< '\n';
e.get_trace().print(std::cerr, cpptrace::isatty(cpptrace::stderr_fileno));
} catch(std::exception& e) {
std::cerr << "Terminate called after throwing an instance of "
<< cpptrace::demangle(typeid(e).name())
<< ": "
<< e.what()
<< '\n';
} catch(...) {
std::cerr << "Terminate called after throwing an instance of "
<< detail::exception_type_name()
<< "\n";
}
abort();
}
CPPTRACE_API void register_terminate_handler() {
std::set_terminate(terminate_handler);
}
namespace detail {
std::atomic_bool absorb_trace_exceptions(true); // NOSONAR
std::atomic<enum cache_mode> cache_mode(cache_mode::prioritize_speed); // NOSONAR

View File

@ -0,0 +1,26 @@
#ifndef EXCEPTION_TYPE_HPP
#define EXCEPTION_TYPE_HPP
#include <string>
// libstdc++ and libc++
#if CPPTRACE_HAS_CXX_EXCEPTION_TYPE && defined(__GLIBCXX__) || defined(__GLIBCPP__) || defined(_LIBCPP_VERSION)
#include <cxxabi.h>
#endif
#include "../demangle/demangle.hpp"
namespace cpptrace {
namespace detail {
inline std::string exception_type_name() {
#if CPPTRACE_HAS_CXX_EXCEPTION_TYPE && defined(__GLIBCXX__) || defined(__GLIBCPP__) || defined(_LIBCPP_VERSION)
std::type_info* t = abi::__cxa_current_exception_type();
return t ? detail::demangle(t->name()) : "<unknown>";
#else
return "<unknown>";
#endif
}
}
}
#endif

View File

@ -7,7 +7,7 @@
void trace() {
cpptrace::generate_trace().print();
throw cpptrace::exception_with_message("foobar");
throw cpptrace::logic_error("foobar");
}
void foo(int n) {
@ -31,12 +31,8 @@ void function_one(int) {
function_two(0, 0);
}
int main() try {
int main() {
cpptrace::absorb_trace_exceptions(false);
cpptrace::register_terminate_handler();
function_one(0);
} catch(cpptrace::exception& e) {
std::cerr << "Error: "
<< e.get_raw_what()
<< '\n';
e.get_trace().print(std::cerr, cpptrace::isatty(cpptrace::stderr_fileno));
}