Skip to content

Commit 0256e8c

Browse files
committed
Implement a system for preventing redundant tracing during search
1 parent 0249b50 commit 0256e8c

File tree

2 files changed

+51
-10
lines changed

2 files changed

+51
-10
lines changed

include/cpptrace/from_current.hpp

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,46 @@ namespace cpptrace {
88
CPPTRACE_EXPORT const stacktrace& from_current_exception();
99

1010
namespace detail {
11+
// Trace switch is to prevent multiple tracing of stacks on call stacks with multiple catches that don't
12+
// immediately match
13+
inline bool& get_trace_switch() {
14+
static bool trace_switch = true;
15+
return trace_switch;
16+
}
17+
18+
class CPPTRACE_EXPORT try_canary {
19+
public:
20+
~try_canary() {
21+
// Fires when we exit a try block, either via normal means or during unwinding.
22+
// Either way: Flip the switch.
23+
get_trace_switch() = true;
24+
}
25+
};
26+
27+
CPPTRACE_EXPORT CPPTRACE_FORCE_NO_INLINE void collect_current_trace(std::size_t skip);
28+
29+
// this function can be void, however, a char return is used to prevent TCO of the collect_current_trace
30+
CPPTRACE_FORCE_NO_INLINE inline char exception_unwind_interceptor(std::size_t skip) {
31+
if(get_trace_switch()) {
32+
// Done during a search phase. Flip the switch off, no more traces until an unwind happens
33+
get_trace_switch() = false;
34+
collect_current_trace(skip + 1);
35+
}
36+
return 42;
37+
}
38+
1139
#ifdef _MSC_VER
12-
CPPTRACE_EXPORT CPPTRACE_FORCE_NO_INLINE int exception_filter();
40+
CPPTRACE_FORCE_NO_INLINE inline int exception_filter() {
41+
exception_unwind_interceptor(1);
42+
return 0; // EXCEPTION_CONTINUE_SEARCH
43+
}
1344
#else
1445
class CPPTRACE_EXPORT unwind_interceptor {
1546
public:
1647
virtual ~unwind_interceptor();
1748
};
1849

19-
CPPTRACE_EXPORT void do_prepare_unwind_interceptor();
50+
CPPTRACE_EXPORT void do_prepare_unwind_interceptor(char(*)(std::size_t));
2051

2152
#ifndef CPPTRACE_DONT_PREPARE_UNWIND_INTERCEPTOR_ON
2253
__attribute__((constructor)) inline void prepare_unwind_interceptor() {
@@ -27,7 +58,7 @@ namespace cpptrace {
2758
// against it here too as a fast path, not that this should matter for performance
2859
static bool did_prepare = false;
2960
if(!did_prepare) {
30-
do_prepare_unwind_interceptor();
61+
do_prepare_unwind_interceptor(exception_unwind_interceptor);
3162
did_prepare = true;
3263
}
3364
}
@@ -41,6 +72,7 @@ namespace cpptrace {
4172
// exception handling (try/catch) in the same function."
4273
#define CPPTRACE_TRY \
4374
try { \
75+
::cpptrace::detail::try_canary cpptrace_try_canary; \
4476
[&]() { \
4577
__try { \
4678
[&]() {
@@ -52,6 +84,10 @@ namespace cpptrace {
5284
#else
5385
#define CPPTRACE_TRY \
5486
try { \
87+
_Pragma("GCC diagnostic push") \
88+
_Pragma("GCC diagnostic ignored \"-Wshadow\"") \
89+
::cpptrace::detail::try_canary cpptrace_try_canary; \
90+
_Pragma("GCC diagnostic pop") \
5591
try {
5692
#define CPPTRACE_CATCH(param) \
5793
} catch(::cpptrace::detail::unwind_interceptor&) {} \

src/from_current.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,19 @@ namespace cpptrace {
3232
namespace detail {
3333
thread_local lazy_trace_holder current_exception_trace;
3434

35+
CPPTRACE_FORCE_NO_INLINE void collect_current_trace(std::size_t skip) {
36+
current_exception_trace = lazy_trace_holder(cpptrace::generate_raw_trace(skip + 1));
37+
}
38+
3539
#ifndef _MSC_VER
40+
// set only once by do_prepare_unwind_interceptor
41+
char (*intercept_unwind_handler)(std::size_t) = nullptr;
42+
3643
CPPTRACE_FORCE_NO_INLINE
3744
bool intercept_unwind(const std::type_info*, const std::type_info*, void**, unsigned) {
38-
current_exception_trace = lazy_trace_holder(cpptrace::generate_raw_trace(1));
45+
if(intercept_unwind_handler) {
46+
intercept_unwind_handler(1);
47+
}
3948
return false;
4049
}
4150

@@ -259,9 +268,10 @@ namespace cpptrace {
259268
mprotect_page(reinterpret_cast<void*>(page_addr), page_size, old_protections);
260269
}
261270

262-
void do_prepare_unwind_interceptor() {
271+
void do_prepare_unwind_interceptor(char(*intercept_unwind_handler)(std::size_t)) {
263272
static bool did_prepare = false;
264273
if(!did_prepare) {
274+
cpptrace::detail::intercept_unwind_handler = intercept_unwind_handler;
265275
try {
266276
perform_typeinfo_surgery(typeid(cpptrace::detail::unwind_interceptor));
267277
} catch(std::exception& e) {
@@ -276,11 +286,6 @@ namespace cpptrace {
276286
did_prepare = true;
277287
}
278288
}
279-
#else
280-
CPPTRACE_FORCE_NO_INLINE int exception_filter() {
281-
current_exception_trace = lazy_trace_holder(cpptrace::generate_raw_trace(1));
282-
return EXCEPTION_CONTINUE_SEARCH;
283-
}
284289
#endif
285290
}
286291

0 commit comments

Comments
 (0)