From 9c8119316bb353ebc734c0d8fe315976031b2909 Mon Sep 17 00:00:00 2001 From: Remi Gacogne Date: Wed, 18 Jan 2017 17:04:28 +0100 Subject: [PATCH] rec: Let ASAN know that we are switching stacks, which one is in use Enabled via the --enable-asan configure switch if the `__sanitizer_start_switch_fiber` function is present in `sanitizer/common_interface_defs.h` . --- m4/pdns_enable_sanitizers.m4 | 12 +++++++++++- pdns/mtasker.cc | 16 +++++++++++++--- pdns/mtasker.hh | 12 ++++++++++++ pdns/mtasker_context.hh | 31 +++++++++++++++++++++++++++++++ pdns/mtasker_fcontext.cc | 12 ++++++++++++ pdns/mtasker_ucontext.cc | 7 +++++++ 6 files changed, 86 insertions(+), 4 deletions(-) diff --git a/m4/pdns_enable_sanitizers.m4 b/m4/pdns_enable_sanitizers.m4 index 339c258306..c392480a0a 100644 --- a/m4/pdns_enable_sanitizers.m4 +++ b/m4/pdns_enable_sanitizers.m4 @@ -39,7 +39,17 @@ AC_DEFUN([PDNS_ENABLE_ASAN], [ AS_IF([test "x$enable_asan" != "xno"], [ gl_COMPILER_OPTION_IF([-fsanitize=address], - [SANITIZER_FLAGS="-fsanitize=address $SANITIZER_FLAGS"], + [ + [SANITIZER_FLAGS="-fsanitize=address $SANITIZER_FLAGS"] + AC_CHECK_HEADERS([sanitizer/common_interface_defs.h], asan_headers=yes, asan_headers=no) + AS_IF([test x"$asan_headers" = "xyes" ], + [AC_CHECK_DECL(__sanitizer_start_switch_fiber, + [ AC_DEFINE([HAVE_FIBER_SANITIZER], [1], [Define if ASAN fiber annotation interface is available.]) ], + [ ], + [#include ] + )] + ) + ], [AC_MSG_ERROR([Cannot enable AddressSanitizer])] ) ]) diff --git a/pdns/mtasker.cc b/pdns/mtasker.cc index 4ae49c6cc8..aed0839ccf 100644 --- a/pdns/mtasker.cc +++ b/pdns/mtasker.cc @@ -200,7 +200,9 @@ templateint MTasker::waitEven unsigned int diff=d_threads[d_tid].dt.ndiff()/1000; d_threads[d_tid].totTime+=diff; #endif + notifyStackSwitchToKernel(); pdns_swapcontext(*d_waiters.find(key)->context,d_kernel); // 'A' will return here when 'key' has arrived, hands over control to kernel first + notifyStackSwitchDone(); #ifdef MTASKERTIMING d_threads[d_tid].dt.start(); #endif @@ -220,7 +222,9 @@ templateint MTasker::waitEven templatevoid MTasker::yield() { d_runQueue.push(d_tid); + notifyStackSwitchToKernel(); pdns_swapcontext(*d_threads[d_tid].context ,d_kernel); // give control to the kernel + notifyStackSwitchDone(); } //! reports that an event took place for which threads may be waiting @@ -247,8 +251,10 @@ templateint MTasker::sendEven d_tid=waiter->tid; // set tid d_eventkey=waiter->key; // pass waitEvent the exact key it was woken for auto userspace=std::move(waiter->context); - d_waiters.erase(waiter); // removes the waitpoint + d_waiters.erase(waiter); // removes the waitpoint + notifyStackSwitch(d_threads[d_tid].startOfStack, d_stacksize); pdns_swapcontext(d_kernel,*userspace); // swaps back to the above point 'A' + notifyStackSwitchDone(); return 1; } @@ -301,8 +307,10 @@ templatebool MTasker::schedule(struct timeval* n #ifdef MTASKERTIMING d_threads[d_tid].dt.start(); #endif + notifyStackSwitch(d_threads[d_tid].startOfStack, d_stacksize); pdns_swapcontext(d_kernel, *d_threads[d_tid].context); - + notifyStackSwitchDone(); + d_runQueue.pop(); return true; } @@ -328,9 +336,11 @@ templatebool MTasker::schedule(struct timeval* n d_eventkey=i->key; // pass waitEvent the exact key it was woken for auto uc = i->context; d_tid = i->tid; - ttdindex.erase(i++); // removes the waitpoint + ttdindex.erase(i++); // removes the waitpoint + notifyStackSwitch(d_threads[d_tid].startOfStack, d_stacksize); pdns_swapcontext(d_kernel, *uc); // swaps back to the above point 'A' + notifyStackSwitchDone(); } else if(i->ttd.tv_sec) break; diff --git a/pdns/mtasker.hh b/pdns/mtasker.hh index dfa59921ad..ced18d1b4a 100644 --- a/pdns/mtasker.hh +++ b/pdns/mtasker.hh @@ -94,6 +94,17 @@ public: waiters_t d_waiters; + void initMainStackBounds() + { +#ifdef HAVE_FIBER_SANITIZER + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_getattr_np(pthread_self(), &attr); + pthread_attr_getstack(&attr, &t_mainStack, &t_mainStackSize); + pthread_attr_destroy(&attr); +#endif /* HAVE_FIBER_SANITIZER */ + } + //! Constructor /** Constructor with a small default stacksize. If any of your threads exceeds this stack, your application will crash. This limit applies solely to the stack, the heap is not limited in any way. If threads need to allocate a lot of data, @@ -101,6 +112,7 @@ public: */ MTasker(size_t stacksize=8192) : d_tid(0), d_maxtid(0), d_stacksize(stacksize), d_waitstatus(Error) { + initMainStackBounds(); } typedef void tfunc_t(void *); //!< type of the pointer that starts a thread diff --git a/pdns/mtasker_context.hh b/pdns/mtasker_context.hh index d0f82e14cd..9acff39176 100644 --- a/pdns/mtasker_context.hh +++ b/pdns/mtasker_context.hh @@ -50,4 +50,35 @@ void pdns_makecontext (pdns_ucontext_t& ctx, boost::function& start); +#ifdef HAVE_FIBER_SANITIZER +#include +#endif /* HAVE_FIBER_SANITIZER */ + +#ifdef HAVE_FIBER_SANITIZER +extern __thread void* t_mainStack; +extern __thread size_t t_mainStackSize; +#endif /* HAVE_FIBER_SANITIZER */ + +static inline void notifyStackSwitch(void* startOfStack, size_t stackSize) +{ +#ifdef HAVE_FIBER_SANITIZER + __sanitizer_start_switch_fiber(nullptr, startOfStack, stackSize); +#endif /* HAVE_FIBER_SANITIZER */ +} + +static inline void notifyStackSwitchToKernel() +{ +#ifdef HAVE_FIBER_SANITIZER + notifyStackSwitch(t_mainStack, t_mainStackSize); +#endif /* HAVE_FIBER_SANITIZER */ +} + +static inline void notifyStackSwitchDone() +{ +#ifdef HAVE_FIBER_SANITIZER + __sanitizer_finish_switch_fiber(nullptr); +#endif /* HAVE_FIBER_SANITIZER */ +} + + #endif // MTASKER_CONTEXT_HH diff --git a/pdns/mtasker_fcontext.cc b/pdns/mtasker_fcontext.cc index cc945c16ee..362a2f797f 100644 --- a/pdns/mtasker_fcontext.cc +++ b/pdns/mtasker_fcontext.cc @@ -36,6 +36,11 @@ using boost::context::detail::make_fcontext; #include #endif /* PDNS_USE_VALGRIND */ +#ifdef HAVE_FIBER_SANITIZER +__thread void* t_mainStack{nullptr}; +__thread size_t t_mainStackSize{0}; +#endif /* HAVE_FIBER_SANITIZER */ + #if BOOST_VERSION < 105600 /* Note: This typedef means functions taking fcontext_t*, like jump_fcontext(), * now require a reinterpret_cast rather than a static_cast, since we're @@ -107,6 +112,7 @@ threadWrapper (transfer_t const t) { * the behaviour of the System V implementation, which can inherently only * be passed ints and pointers. */ + notifyStackSwitchDone(); #if BOOST_VERSION < 106100 auto args = reinterpret_cast(xargs); #else @@ -115,6 +121,7 @@ threadWrapper (transfer_t const t) { auto ctx = args->self; auto work = args->work; /* we switch back to pdns_makecontext() */ + notifyStackSwitchToKernel(); #if BOOST_VERSION < 106100 jump_fcontext (reinterpret_cast(&ctx->uc_mcontext), static_cast(args->prev_ctx), 0); @@ -129,6 +136,7 @@ threadWrapper (transfer_t const t) { *ptr = res.fctx; } #endif + notifyStackSwitchDone(); args = nullptr; try { @@ -138,6 +146,7 @@ threadWrapper (transfer_t const t) { ctx->exception = std::current_exception(); } + notifyStackSwitchToKernel(); /* Emulate the System V uc_link feature. */ auto const next_ctx = ctx->uc_link->uc_mcontext; #if BOOST_VERSION < 106100 @@ -211,6 +220,7 @@ pdns_makecontext args.self = &ctx; args.work = &start; /* jumping to threadwrapper */ + notifyStackSwitch(&ctx.uc_stack[ctx.uc_stack.size()], ctx.uc_stack.size()); #if BOOST_VERSION < 106100 jump_fcontext (reinterpret_cast(&args.prev_ctx), static_cast(ctx.uc_mcontext), @@ -221,4 +231,6 @@ pdns_makecontext /* back from threadwrapper, updating the context */ ctx.uc_mcontext = res.fctx; #endif + notifyStackSwitchDone(); + } diff --git a/pdns/mtasker_ucontext.cc b/pdns/mtasker_ucontext.cc index ea7d2a4edf..d7663e340b 100644 --- a/pdns/mtasker_ucontext.cc +++ b/pdns/mtasker_ucontext.cc @@ -31,6 +31,11 @@ #include #endif /* PDNS_USE_VALGRIND */ +#ifdef HAVE_FIBER_SANITIZER +__thread void* t_mainStack{nullptr}; +__thread size_t t_mainStackSize{0}; +#endif /* HAVE_FIBER_SANITIZER */ + template static __attribute__((noinline, cold, noreturn)) void throw_errno (Message&& msg) { @@ -75,6 +80,7 @@ extern "C" { static void threadWrapper (int const ctx0, int const ctx1, int const fun0, int const fun1) { + notifyStackSwitchDone(); auto ctx = joinPtr(ctx0, ctx1); try { auto start = std::move(*joinPtr>(fun0, fun1)); @@ -82,6 +88,7 @@ threadWrapper (int const ctx0, int const ctx1, int const fun0, int const fun1) { } catch (...) { ctx->exception = std::current_exception(); } + notifyStackSwitchToKernel(); } } // extern "C" -- 2.47.2