[GWP-ASan] Add locking around unwinder for atfork protection.
authorMitch Phillips <31459023+hctim@users.noreply.github.com>
Tue, 2 Feb 2021 22:32:28 +0000 (14:32 -0800)
committerMitch Phillips <31459023+hctim@users.noreply.github.com>
Tue, 2 Feb 2021 22:44:35 +0000 (14:44 -0800)
Unwinders (like libc's backtrace()) can call their own locks (like the
libdl lock). We need to let the unwinder release the locks before
forking. Wrap a new lock around the unwinder for atfork protection.

Reviewed By: eugenis

Differential Revision: https://reviews.llvm.org/D95889

compiler-rt/lib/gwp_asan/guarded_pool_allocator.cpp
compiler-rt/lib/gwp_asan/guarded_pool_allocator.h

index 86304d9..5e3455e 100644 (file)
@@ -103,9 +103,15 @@ void GuardedPoolAllocator::init(const options::Options &Opts) {
     installAtFork();
 }
 
-void GuardedPoolAllocator::disable() { PoolMutex.lock(); }
+void GuardedPoolAllocator::disable() {
+  PoolMutex.lock();
+  BacktraceMutex.lock();
+}
 
-void GuardedPoolAllocator::enable() { PoolMutex.unlock(); }
+void GuardedPoolAllocator::enable() {
+  PoolMutex.unlock();
+  BacktraceMutex.unlock();
+}
 
 void GuardedPoolAllocator::iterate(void *Base, size_t Size, iterate_callback Cb,
                                    void *Arg) {
@@ -232,7 +238,10 @@ void *GuardedPoolAllocator::allocate(size_t Size, size_t Alignment) {
       roundUpTo(Size, PageSize));
 
   Meta->RecordAllocation(UserPtr, Size);
-  Meta->AllocationTrace.RecordBacktrace(Backtrace);
+  {
+    ScopedLock UL(BacktraceMutex);
+    Meta->AllocationTrace.RecordBacktrace(Backtrace);
+  }
 
   return reinterpret_cast<void *>(UserPtr);
 }
@@ -281,6 +290,7 @@ void GuardedPoolAllocator::deallocate(void *Ptr) {
     // otherwise non-reentrant unwinders may deadlock.
     if (!getThreadLocals()->RecursiveGuard) {
       ScopedRecursiveGuard SRG;
+      ScopedLock UL(BacktraceMutex);
       Meta->DeallocationTrace.RecordBacktrace(Backtrace);
     }
   }
index 86521f9..26a4599 100644 (file)
@@ -196,6 +196,10 @@ private:
 
   // A mutex to protect the guarded slot and metadata pool for this class.
   Mutex PoolMutex;
+  // Some unwinders can grab the libdl lock. In order to provide atfork
+  // protection, we need to ensure that we allow an unwinding thread to release
+  // the libdl lock before forking.
+  Mutex BacktraceMutex;
   // Record the number allocations that we've sampled. We store this amount so
   // that we don't randomly choose to recycle a slot that previously had an
   // allocation before all the slots have been utilised.