diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h --- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h @@ -196,5 +196,21 @@ uptr local_stack; \ uptr sp = (uptr)&local_stack +// GET_CURRENT_PC() is equivalent to StackTrace::GetCurrentPc(). +// Optimized x86 version is faster than GetCurrentPc because +// it does not involve a function call, instead it takes an address +// of a local label. It needs to be a macro because clang rejects +// to inline a function with an addr-taken label. +#if defined(__i386__) || defined(__x86_64__) +# define CONCAT2(x, y) x##y +# define CONCAT(x, y) CONCAT2(x, y) +# define GET_CURRENT_PC() \ + ({ \ + CONCAT(here, __LINE__) : asm("nop"); \ + ((uptr) && CONCAT(here, __LINE__)) + 1; \ + }) +#else +# define GET_CURRENT_PC() StackTrace::GetCurrentPc() +#endif #endif // SANITIZER_STACKTRACE_H diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cpp b/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cpp --- a/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cpp +++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cpp @@ -271,6 +271,27 @@ EXPECT_EQ(bp, stack.top_frame_bp); } +TEST(GetCurrentPc, Basic) { + // Test that PCs obtained via GET_CURRENT_PC() + // and StackTrace::GetCurrentPc() are all different + // and are close to the function start. + struct Local { + static NOINLINE void Test() { + const uptr pcs[] = { + (uptr)&Local::Test, GET_CURRENT_PC(), + GET_CURRENT_PC(), StackTrace::GetCurrentPc(), + StackTrace::GetCurrentPc(), + }; + for (uptr i = 1; i < ARRAY_SIZE(pcs); i++) { + EXPECT_GT(pcs[i], pcs[0]); + EXPECT_LT(pcs[i], pcs[0] + 1000); + for (uptr j = 0; j < i; j++) EXPECT_NE(pcs[i], pcs[j]); + } + } + }; + Local::Test(); +} + // Dummy implementation. This should never be called, but is required to link // non-optimized builds of this test. void BufferedStackTrace::UnwindImpl(uptr pc, uptr bp, void *context, diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors.h b/compiler-rt/lib/tsan/rtl/tsan_interceptors.h --- a/compiler-rt/lib/tsan/rtl/tsan_interceptors.h +++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors.h @@ -30,14 +30,14 @@ } // namespace __tsan -#define SCOPED_INTERCEPTOR_RAW(func, ...) \ - cur_thread_init(); \ - ThreadState *thr = cur_thread(); \ - const uptr caller_pc = GET_CALLER_PC(); \ - ScopedInterceptor si(thr, #func, caller_pc); \ - const uptr pc = StackTrace::GetCurrentPc(); \ - (void)pc; \ -/**/ +#define SCOPED_INTERCEPTOR_RAW(func, ...) \ + cur_thread_init(); \ + ThreadState *thr = cur_thread(); \ + const uptr caller_pc = GET_CALLER_PC(); \ + ScopedInterceptor si(thr, #func, caller_pc); \ + const uptr pc = GET_CURRENT_PC(); \ + (void)pc; \ + /**/ #define SCOPED_TSAN_INTERCEPTOR(func, ...) \ SCOPED_INTERCEPTOR_RAW(func, __VA_ARGS__); \