]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
rec: Let ASAN know that we are switching stacks, which one is in use 4925/head
authorRemi Gacogne <remi.gacogne@powerdns.com>
Wed, 18 Jan 2017 16:04:28 +0000 (17:04 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 24 Jan 2017 13:37:43 +0000 (14:37 +0100)
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
pdns/mtasker.cc
pdns/mtasker.hh
pdns/mtasker_context.hh
pdns/mtasker_fcontext.cc
pdns/mtasker_ucontext.cc

index 339c258306519db7b67a2b1f55b5209c670d0b26..c392480a0a1d9b9f6e64ebcc406fd3785832af71 100644 (file)
@@ -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 <sanitizer/common_interface_defs.h>]
+          )]
+        )
+      ],
       [AC_MSG_ERROR([Cannot enable AddressSanitizer])]
     )
   ])
index 4ae49c6cc8e039c38f10f3cfcaddbfc7b9de1641..aed0839ccf74de32c6df0486c256c47dba8395ff 100644 (file)
@@ -200,7 +200,9 @@ template<class EventKey, class EventVal>int MTasker<EventKey,EventVal>::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 @@ template<class EventKey, class EventVal>int MTasker<EventKey,EventVal>::waitEven
 template<class Key, class Val>void MTasker<Key,Val>::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 @@ template<class EventKey, class EventVal>int MTasker<EventKey,EventVal>::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 @@ template<class Key, class Val>bool MTasker<Key,Val>::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 @@ template<class Key, class Val>bool MTasker<Key,Val>::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;
index dfa59921ad26dc93235415853a4de94cb066c30b..ced18d1b4a942f3524ba45825e3b3ab05bb718c9 100644 (file)
@@ -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 
index d0f82e14cda277df7af169e551867af1ae1f3b06..9acff39176d097f3127f5b78f4ab55487cba719d 100644 (file)
@@ -50,4 +50,35 @@ void
 pdns_makecontext
 (pdns_ucontext_t& ctx, boost::function<void(void)>& start);
 
+#ifdef HAVE_FIBER_SANITIZER
+#include <sanitizer/common_interface_defs.h>
+#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
index cc945c16ee86992f134a3c3643f416090c110bfd..362a2f797fc507a4e7e443ada474bb7721072957 100644 (file)
@@ -36,6 +36,11 @@ using boost::context::detail::make_fcontext;
 #include <valgrind/valgrind.h>
 #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<args_t*>(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<fcontext_t*>(&ctx->uc_mcontext),
                    static_cast<fcontext_t>(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<fcontext_t*>(&args.prev_ctx),
                    static_cast<fcontext_t>(ctx.uc_mcontext),
@@ -221,4 +231,6 @@ pdns_makecontext
     /* back from threadwrapper, updating the context */
     ctx.uc_mcontext = res.fctx;
 #endif
+    notifyStackSwitchDone();
+
 }
index ea7d2a4edf3384e08f7f8bc98d06254d1e719842..d7663e340ba967aecd4f0ea97e9472323b0b5539 100644 (file)
 #include <valgrind/valgrind.h>
 #endif /* PDNS_USE_VALGRIND */
 
+#ifdef HAVE_FIBER_SANITIZER
+__thread void* t_mainStack{nullptr};
+__thread size_t t_mainStackSize{0};
+#endif /* HAVE_FIBER_SANITIZER */
+
 template <typename Message> 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<pdns_ucontext_t>(ctx0, ctx1);
     try {
         auto start = std::move(*joinPtr<boost::function<void()>>(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"