@@ -108,12 +108,11 @@ private void FinalizeDispose()
108
108
// Thread gate holder and constats
109
109
private bool _stopListening = false ;
110
110
111
- private bool IsHandleInvalid
111
+ private bool IsHandleInvalid { get { return IsHandleInstanceInvalid ( _directoryHandle ) ; } }
112
+
113
+ private bool IsHandleInstanceInvalid ( SafeFileHandle handle )
112
114
{
113
- get
114
- {
115
- return ( _directoryHandle == null || _directoryHandle . IsInvalid || _directoryHandle . IsClosed ) ;
116
- }
115
+ return handle == null || handle . IsInvalid || handle . IsClosed ;
117
116
}
118
117
119
118
/// <devdoc>
@@ -132,12 +131,21 @@ private unsafe void Monitor(byte[] buffer)
132
131
buffer = AllocateBuffer ( ) ;
133
132
}
134
133
134
+ // Use a local copy of _threadPoolBinding for the remainder of the method.
135
+ // Otherwise, the value of the field could get replaced by a different
136
+ // instance if events are stopped and then restarted, and we could end up
137
+ // trying to use the new binding with an overlapped created on the old binding.
138
+ // Similarly for the directory handle.
139
+ ThreadPoolBoundHandle threadPoolBinding = _threadPoolBinding ;
140
+ SafeFileHandle directoryHandle = _directoryHandle ;
141
+
135
142
// Pass "session" counter to callback:
136
143
FSWAsyncResult asyncResult = new FSWAsyncResult ( ) ;
137
144
asyncResult . session = _currentSession ;
138
145
asyncResult . buffer = buffer ;
146
+ asyncResult . threadPoolBinding = threadPoolBinding ;
139
147
140
- NativeOverlapped * overlappedPointer = _threadPoolBinding . AllocateNativeOverlapped ( new IOCompletionCallback ( this . CompletionStatusChanged ) , asyncResult , buffer ) ;
148
+ NativeOverlapped * overlappedPointer = threadPoolBinding . AllocateNativeOverlapped ( new IOCompletionCallback ( this . CompletionStatusChanged ) , asyncResult , buffer ) ;
141
149
142
150
// Can now call OS:
143
151
int size ;
@@ -149,12 +157,12 @@ private unsafe void Monitor(byte[] buffer)
149
157
// and when we get here from CompletionStatusChanged.
150
158
// We might need to take a lock to prevent race absolutely, instead just catch
151
159
// ObjectDisposedException from SafeHandle in case it is disposed
152
- if ( ! IsHandleInvalid )
160
+ if ( ! IsHandleInstanceInvalid ( directoryHandle ) )
153
161
{
154
162
// An interrupt is possible here
155
163
fixed ( byte * buffPtr = buffer )
156
164
{
157
- ok = UnsafeNativeMethods . ReadDirectoryChangesW ( _directoryHandle ,
165
+ ok = UnsafeNativeMethods . ReadDirectoryChangesW ( directoryHandle ,
158
166
buffPtr ,
159
167
_internalBufferSize ,
160
168
_includeSubdirectories ? 1 : 0 ,
@@ -170,17 +178,17 @@ private unsafe void Monitor(byte[] buffer)
170
178
}
171
179
catch ( ArgumentNullException )
172
180
{ //Ignore
173
- Debug . Assert ( IsHandleInvalid , "ArgumentNullException from something other than SafeHandle?" ) ;
181
+ Debug . Assert ( IsHandleInstanceInvalid ( directoryHandle ) , "ArgumentNullException from something other than SafeHandle?" ) ;
174
182
}
175
183
finally
176
184
{
177
185
if ( ! ok )
178
186
{
179
- _threadPoolBinding . FreeNativeOverlapped ( overlappedPointer ) ;
187
+ threadPoolBinding . FreeNativeOverlapped ( overlappedPointer ) ;
180
188
181
189
// If the handle was for some reason changed or closed during this call, then don't throw an
182
190
// exception. Else, it's a valid error.
183
- if ( ! IsHandleInvalid )
191
+ if ( ! IsHandleInstanceInvalid ( directoryHandle ) )
184
192
{
185
193
OnError ( new ErrorEventArgs ( new Win32Exception ( ) ) ) ;
186
194
}
@@ -354,7 +362,7 @@ rename event with the Name field null and then fire the next action.
354
362
}
355
363
finally
356
364
{
357
- _threadPoolBinding . FreeNativeOverlapped ( overlappedPointer ) ;
365
+ asyncResult . threadPoolBinding . FreeNativeOverlapped ( overlappedPointer ) ;
358
366
if ( ! _stopListening )
359
367
{
360
368
Monitor ( asyncResult . buffer ) ;
@@ -368,6 +376,7 @@ private sealed class FSWAsyncResult
368
376
{
369
377
internal int session ;
370
378
internal byte [ ] buffer ;
379
+ internal ThreadPoolBoundHandle threadPoolBinding ;
371
380
}
372
381
373
382
/// <devdoc>
0 commit comments