Add specialized terminate handler and add error handling info to the README. Also updated demo.
This commit is contained in:
parent
2e0fa880bc
commit
05c3f7160b
@ -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 "")
|
||||
|
||||
29
README.md
29
README.md
@ -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.
|
||||
|
||||
6
cmake/has_cxx_exception_type.cpp
Normal file
6
cmake/has_cxx_exception_type.cpp
Normal file
@ -0,0 +1,6 @@
|
||||
#include <cxxabi.h>
|
||||
|
||||
int main() {
|
||||
std::type_info* t = abi::__cxa_current_exception_type();
|
||||
(void*) t;
|
||||
}
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
26
src/platform/exception_type.hpp
Normal file
26
src/platform/exception_type.hpp
Normal 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
|
||||
@ -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));
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user