summaryrefslogtreecommitdiff
path: root/src/vm/rwlock.h
diff options
context:
space:
mode:
authorKoundinya Veluri <kouvel@microsoft.com>2016-08-17 14:48:59 -0700
committerKoundinya Veluri <kouvel@microsoft.com>2016-08-17 14:48:59 -0700
commit6ad3d45d6b9096b64c9d9ea933efe5f49f08c81f (patch)
tree72183bd499df77a04c7b0c315e7c2a0a57acfbd4 /src/vm/rwlock.h
parenta641d3aa4e90ef59b89511705c43d2a036a9c0d4 (diff)
downloadcoreclr-6ad3d45d6b9096b64c9d9ea933efe5f49f08c81f.tar.gz
coreclr-6ad3d45d6b9096b64c9d9ea933efe5f49f08c81f.tar.bz2
coreclr-6ad3d45d6b9096b64c9d9ea933efe5f49f08c81f.zip
Fix CRWLock ID generation overflow bug
There are several problems with the CRWLock constructor, where it tries to increment a 64-bit lock ID in two 32-bit pieces using lock-free code in a fast path: - For the lower 32 bits, LLockID, zero is reserved for identifying a free lock entry. Upon incrementing LLockID from -1 to 0, the code was not skipping zero or incrementing the upper 32 bits, ULockID. Instead, it waited for one more increment to LLockID before increment ULockID. Assignment of the invalid LLockID caused a free lock entry to be reused for a new lock, and corruption in lock state thereafter. This is the issue identified by the bug. - If LLockID != -1 in thread A, but the compare-exchange fails because thread B had updated the value before thread A, ULockID was not being read again in thread A. If thread B had also incremented ULockID, thread A would continue to use the old ULockID. - In the locked slow path that handles incrementing ULockID, ULockID is updated before LLockID. The constructor though, was reading ULockID before LLockID. This allows a race where Thread A reads an old value for ULockID and a new value for LLockID, increments LLockID successfully, and continues to use the old ULockID. Due to the availability of InterlockedCompareExchange64 on all supported platforms, we decided to use that instead to simplify the solution and fix all of the above issues at the same time. Bug: 242568 Integrated from changes: 1621197, 1621810 [tfs-changeset: 1622814]
Diffstat (limited to 'src/vm/rwlock.h')
-rw-r--r--src/vm/rwlock.h6
1 files changed, 4 insertions, 2 deletions
diff --git a/src/vm/rwlock.h b/src/vm/rwlock.h
index 0420c45db9..dc8e67e6fb 100644
--- a/src/vm/rwlock.h
+++ b/src/vm/rwlock.h
@@ -204,6 +204,9 @@ private:
static LONG RWInterlockedCompareExchange(LONG RAW_KEYWORD(volatile) *pvDestination,
LONG dwExchange,
LONG dwComperand);
+ static LONGLONG RWInterlockedCompareExchange64(LONGLONG RAW_KEYWORD(volatile) *pvDestination,
+ LONGLONG qwExchange,
+ LONGLONG qwComparand);
static void* RWInterlockedCompareExchangePointer(PVOID RAW_KEYWORD(volatile) *pvDestination,
PVOID pExchange,
PVOID pComparand);
@@ -267,8 +270,7 @@ private:
#endif
// Static data
- static Volatile<LONG> s_mostRecentULockID;
- static Volatile<LONG> s_mostRecentLLockID;
+ static Volatile<LONGLONG> s_mostRecentLockID;
static CrstStatic s_RWLockCrst;
};