Implement a system for preventing redundant tracing during search

This commit is contained in:
Jeremy Rifkin 2024-08-19 23:53:57 -05:00
parent 0249b50698
commit 73ca2b5b49
No known key found for this signature in database
GPG Key ID: 19AA8270105E8EB4
2 changed files with 51 additions and 10 deletions

View File

@ -8,15 +8,46 @@ namespace cpptrace {
CPPTRACE_EXPORT const stacktrace& from_current_exception();
namespace detail {
// Trace switch is to prevent multiple tracing of stacks on call stacks with multiple catches that don't
// immediately match
inline bool& get_trace_switch() {
static thread_local bool trace_switch = true;
return trace_switch;
}
class CPPTRACE_EXPORT try_canary {
public:
~try_canary() {
// Fires when we exit a try block, either via normal means or during unwinding.
// Either way: Flip the switch.
get_trace_switch() = true;
}
};
CPPTRACE_EXPORT CPPTRACE_FORCE_NO_INLINE void collect_current_trace(std::size_t skip);
// this function can be void, however, a char return is used to prevent TCO of the collect_current_trace
CPPTRACE_FORCE_NO_INLINE inline char exception_unwind_interceptor(std::size_t skip) {
if(get_trace_switch()) {
// Done during a search phase. Flip the switch off, no more traces until an unwind happens
get_trace_switch() = false;
collect_current_trace(skip + 1);
}
return 42;
}
#ifdef _MSC_VER
CPPTRACE_EXPORT CPPTRACE_FORCE_NO_INLINE int exception_filter();
CPPTRACE_FORCE_NO_INLINE inline int exception_filter() {
exception_unwind_interceptor(1);
return 0; // EXCEPTION_CONTINUE_SEARCH
}
#else
class CPPTRACE_EXPORT unwind_interceptor {
public:
virtual ~unwind_interceptor();
};
CPPTRACE_EXPORT void do_prepare_unwind_interceptor();
CPPTRACE_EXPORT void do_prepare_unwind_interceptor(char(*)(std::size_t));
#ifndef CPPTRACE_DONT_PREPARE_UNWIND_INTERCEPTOR_ON
__attribute__((constructor)) inline void prepare_unwind_interceptor() {
@ -27,7 +58,7 @@ namespace cpptrace {
// against it here too as a fast path, not that this should matter for performance
static bool did_prepare = false;
if(!did_prepare) {
do_prepare_unwind_interceptor();
do_prepare_unwind_interceptor(exception_unwind_interceptor);
did_prepare = true;
}
}
@ -41,6 +72,7 @@ namespace cpptrace {
// exception handling (try/catch) in the same function."
#define CPPTRACE_TRY \
try { \
::cpptrace::detail::try_canary cpptrace_try_canary; \
[&]() { \
__try { \
[&]() {
@ -52,6 +84,10 @@ namespace cpptrace {
#else
#define CPPTRACE_TRY \
try { \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wshadow\"") \
::cpptrace::detail::try_canary cpptrace_try_canary; \
_Pragma("GCC diagnostic pop") \
try {
#define CPPTRACE_CATCH(param) \
} catch(::cpptrace::detail::unwind_interceptor&) {} \

View File

@ -32,10 +32,19 @@ namespace cpptrace {
namespace detail {
thread_local lazy_trace_holder current_exception_trace;
CPPTRACE_FORCE_NO_INLINE void collect_current_trace(std::size_t skip) {
current_exception_trace = lazy_trace_holder(cpptrace::generate_raw_trace(skip + 1));
}
#ifndef _MSC_VER
// set only once by do_prepare_unwind_interceptor
char (*intercept_unwind_handler)(std::size_t) = nullptr;
CPPTRACE_FORCE_NO_INLINE
bool intercept_unwind(const std::type_info*, const std::type_info*, void**, unsigned) {
current_exception_trace = lazy_trace_holder(cpptrace::generate_raw_trace(1));
if(intercept_unwind_handler) {
intercept_unwind_handler(1);
}
return false;
}
@ -259,9 +268,10 @@ namespace cpptrace {
mprotect_page(reinterpret_cast<void*>(page_addr), page_size, old_protections);
}
void do_prepare_unwind_interceptor() {
void do_prepare_unwind_interceptor(char(*intercept_unwind_handler)(std::size_t)) {
static bool did_prepare = false;
if(!did_prepare) {
cpptrace::detail::intercept_unwind_handler = intercept_unwind_handler;
try {
perform_typeinfo_surgery(typeid(cpptrace::detail::unwind_interceptor));
} catch(std::exception& e) {
@ -276,11 +286,6 @@ namespace cpptrace {
did_prepare = true;
}
}
#else
CPPTRACE_FORCE_NO_INLINE int exception_filter() {
current_exception_trace = lazy_trace_holder(cpptrace::generate_raw_trace(1));
return EXCEPTION_CONTINUE_SEARCH;
}
#endif
}