[compiler-rt] r338331 - [asan/win] Use SRW locks to fix a race in BlockingMutex
Reid Kleckner via llvm-commits
llvm-commits at lists.llvm.org
Mon Jul 30 16:32:33 PDT 2018
Author: rnk
Date: Mon Jul 30 16:32:33 2018
New Revision: 338331
URL: http://llvm.org/viewvc/llvm-project?rev=338331&view=rev
Log:
[asan/win] Use SRW locks to fix a race in BlockingMutex
Summary:
Before my change, BlockingMutex used Windows critial sections. Critical
sections can only be initialized by calling InitializeCriticalSection,
dynamically.
The primary sanitizer allocator expects to be able to reinterpret zero
initialized memory as a BlockingMutex and immediately lock it.
RegionInfo contains a mutex, and it placement new is never called for
it. These objects are accessed via:
RegionInfo *GetRegionInfo(uptr class_id) const {
DCHECK_LT(class_id, kNumClasses);
RegionInfo *regions = reinterpret_cast<RegionInfo *>(SpaceEnd());
return ®ions[class_id];
}
The memory comes from the OS without any other initialization.
For various reasons described in the comments, BlockingMutex::Lock would
check if the object appeared to be zero-initialized, and it would lazily
call the LinkerInitialized constructor to initialize the critical
section. This pattern is obviously racy, and the code had a bunch of
FIXMEs about it.
The best fix here is to use slim reader writer locks, which can start
out zero-initialized. They are available starting in Windows Vista. I
think it's safe to go ahead and use them today.
Reviewers: kcc, vitalybuka
Subscribers: kubamracek, llvm-commits
Differential Revision: https://reviews.llvm.org/D49893
Modified:
compiler-rt/trunk/lib/sanitizer_common/sanitizer_mutex.h
compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc
Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_mutex.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_mutex.h?rev=338331&r1=338330&r2=338331&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_mutex.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_mutex.h Mon Jul 30 16:32:33 2018
@@ -73,13 +73,8 @@ class SpinMutex : public StaticSpinMutex
class BlockingMutex {
public:
-#if SANITIZER_WINDOWS
- // Windows does not currently support LinkerInitialized
- explicit BlockingMutex(LinkerInitialized);
-#else
explicit constexpr BlockingMutex(LinkerInitialized)
- : opaque_storage_ {0, }, owner_(0) {}
-#endif
+ : opaque_storage_ {0, }, owner_{0} {}
BlockingMutex();
void Lock();
void Unlock();
Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc?rev=338331&r1=338330&r2=338331&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_win.cc Mon Jul 30 16:32:33 2018
@@ -767,43 +767,22 @@ void *internal_start_thread(void (*func)
void internal_join_thread(void *th) { }
// ---------------------- BlockingMutex ---------------- {{{1
-const uptr LOCK_UNINITIALIZED = 0;
-const uptr LOCK_READY = (uptr)-1;
-
-BlockingMutex::BlockingMutex(LinkerInitialized li) {
- // FIXME: see comments in BlockingMutex::Lock() for the details.
- CHECK(li == LINKER_INITIALIZED || owner_ == LOCK_UNINITIALIZED);
-
- CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_));
- InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
- owner_ = LOCK_READY;
-}
BlockingMutex::BlockingMutex() {
- CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_));
- InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
- owner_ = LOCK_READY;
+ CHECK(sizeof(SRWLOCK) <= sizeof(opaque_storage_));
+ internal_memset(this, 0, sizeof(*this));
}
void BlockingMutex::Lock() {
- if (owner_ == LOCK_UNINITIALIZED) {
- // FIXME: hm, global BlockingMutex objects are not initialized?!?
- // This might be a side effect of the clang+cl+link Frankenbuild...
- new(this) BlockingMutex((LinkerInitialized)(LINKER_INITIALIZED + 1));
-
- // FIXME: If it turns out the linker doesn't invoke our
- // constructors, we should probably manually Lock/Unlock all the global
- // locks while we're starting in one thread to avoid double-init races.
- }
- EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
- CHECK_EQ(owner_, LOCK_READY);
+ AcquireSRWLockExclusive((PSRWLOCK)opaque_storage_);
+ CHECK_EQ(owner_, 0);
owner_ = GetThreadSelf();
}
void BlockingMutex::Unlock() {
- CHECK_EQ(owner_, GetThreadSelf());
- owner_ = LOCK_READY;
- LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
+ CheckLocked();
+ owner_ = 0;
+ ReleaseSRWLockExclusive((PSRWLOCK)opaque_storage_);
}
void BlockingMutex::CheckLocked() {
More information about the llvm-commits
mailing list