Implement a system for preventing redundant tracing during search
This commit is contained in:
parent
0249b50698
commit
73ca2b5b49
@ -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&) {} \
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user