Selaa lähdekoodia

[System.Core] Fix possible state corruption in ReaderWriterLockSlim. Fix #6635.

The problem was triggered in a situation where threads were competing for the write-lock and were using timeout:
   - thread t1 takes the lock (state = RwWrite)
   - thread t2 tries to take the lock but fails because of t1, it registers it interest (state = RwWrite | RwWait) and goes to sleep
   - thread t3 tries to take the lock but failes because of t1 and don't register any interest because t2 did it already (state = RwWrite | RwWait)
   - t1 releases the lock, waking up t2 and t3 which race for it with t3 winning the race (state = RwWrite)
   - t2 tries to go back to sleep but has overrun its timeout so it exits.
   - with t2 exiting, it tries to remove previously registered interest (state = RwWrite - RwWait -> corruption).
Jérémie Laval 13 vuotta sitten
vanhempi
sitoutus
e223f978be

+ 4 - 2
mcs/class/System.Core/System.Threading/ReaderWriterLockSlim.cs

@@ -261,6 +261,7 @@ namespace System.Threading {
 
 				int stateCheck = isUpgradable ? RwWaitUpgrade + RwWait : RwWait;
 				long start = millisecondsTimeout == -1 ? 0 : sw.ElapsedMilliseconds;
+				int registration = isUpgradable ? RwWaitUpgrade : RwWait;
 
 				do {
 					int state = rwlock;
@@ -268,7 +269,8 @@ namespace System.Threading {
 					if (state <= stateCheck) {
 						try {}
 						finally {
-							if (Interlocked.CompareExchange (ref rwlock, RwWrite, state) == state) {
+							var toWrite = state + RwWrite - (registered ? registration : 0);
+							if (Interlocked.CompareExchange (ref rwlock, toWrite, state) == state) {
 								writerDoneEvent.Reset ();
 								ctstate.LockState ^= LockState.Write;
 								++ctstate.WriterRecursiveCount;
@@ -452,7 +454,7 @@ namespace System.Threading {
 				return rwlock >= RwRead && CurrentThreadState.LockState.Has (LockState.Read);
 			}
 		}
-		
+
 		public bool IsWriteLockHeld {
 			get {
 				return (rwlock & RwWrite) > 0 && CurrentThreadState.LockState.Has (LockState.Write);