Skip to content

Commit b9f8d12

Browse files
Copilotadamsitnik
andauthored
Only call WaitOne for ERROR_IO_PENDING, extend test to verify handle usability after failure
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
1 parent 38cf5d0 commit b9f8d12

2 files changed

Lines changed: 22 additions & 4 deletions

File tree

src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Windows.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,12 @@ private static unsafe int ReadSyncUsingAsyncHandle(SafeFileHandle handle, Span<b
7979
Interop.Kernel32.ReadFile(handle, pinned, buffer.Length, IntPtr.Zero, overlapped);
8080

8181
int errorCode = FileStreamHelpers.GetLastWin32ErrorAndDisposeHandleIfInvalid(handle);
82-
if (errorCode is Interop.Errors.ERROR_IO_PENDING or Interop.Errors.ERROR_SUCCESS)
82+
if (errorCode is Interop.Errors.ERROR_IO_PENDING)
8383
{
8484
try
8585
{
8686
waitEvent.WaitOne();
87+
errorCode = Interop.Errors.ERROR_SUCCESS;
8788
}
8889
catch
8990
{
@@ -94,7 +95,10 @@ private static unsafe int ReadSyncUsingAsyncHandle(SafeFileHandle handle, Span<b
9495
Interop.Kernel32.GetOverlappedResult(handle, overlapped, ref canceledBytes, bWait: true);
9596
throw;
9697
}
98+
}
9799

100+
if (errorCode is Interop.Errors.ERROR_SUCCESS)
101+
{
98102
int result = 0;
99103
if (Interop.Kernel32.GetOverlappedResult(handle, overlapped, ref result, bWait: false))
100104
{
@@ -170,11 +174,12 @@ private static unsafe void WriteSyncUsingAsyncHandle(SafeFileHandle handle, Read
170174
Interop.Kernel32.WriteFile(handle, pinned, buffer.Length, IntPtr.Zero, overlapped);
171175

172176
int errorCode = FileStreamHelpers.GetLastWin32ErrorAndDisposeHandleIfInvalid(handle);
173-
if (errorCode is Interop.Errors.ERROR_IO_PENDING or Interop.Errors.ERROR_SUCCESS)
177+
if (errorCode is Interop.Errors.ERROR_IO_PENDING)
174178
{
175179
try
176180
{
177181
waitEvent.WaitOne();
182+
errorCode = Interop.Errors.ERROR_SUCCESS;
178183
}
179184
catch
180185
{
@@ -185,7 +190,10 @@ private static unsafe void WriteSyncUsingAsyncHandle(SafeFileHandle handle, Read
185190
Interop.Kernel32.GetOverlappedResult(handle, overlapped, ref canceledBytes, bWait: true);
186191
throw;
187192
}
193+
}
188194

195+
if (errorCode is Interop.Errors.ERROR_SUCCESS)
196+
{
189197
int result = 0;
190198
if (Interop.Kernel32.GetOverlappedResult(handle, overlapped, ref result, bWait: false))
191199
{

src/libraries/System.Runtime/tests/System.IO.FileSystem.Tests/RandomAccess/Mixed.Windows.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,12 +152,14 @@ public void SyncIOOnAsyncHandle_DoesNotCorruptMemory_WhenSynchronizationContextT
152152
// the pending IO is properly canceled before freeing the NativeOverlapped,
153153
// preventing use-after-free / heap corruption.
154154
string filePath = GetTestFilePath();
155-
File.WriteAllBytes(filePath, new byte[1024]);
155+
byte[] expectedData = new byte[1024];
156+
Random.Shared.NextBytes(expectedData);
157+
File.WriteAllBytes(filePath, expectedData);
156158

157159
SynchronizationContext previous = SynchronizationContext.Current;
158160
try
159161
{
160-
var throwingContext = new ThrowingSynchronizationContext();
162+
ThrowingSynchronizationContext throwingContext = new();
161163
SynchronizationContext.SetSynchronizationContext(throwingContext);
162164

163165
using SafeFileHandle handle = File.OpenHandle(filePath, FileMode.Open, FileAccess.Read, options: FileOptions.Asynchronous);
@@ -167,6 +169,14 @@ public void SyncIOOnAsyncHandle_DoesNotCorruptMemory_WhenSynchronizationContextT
167169
// The ThrowingSynchronizationContext.Wait throws, which should be caught
168170
// and the IO should be canceled gracefully.
169171
Assert.Throws<InvalidOperationException>(() => RandomAccess.Read(handle, buffer, 0));
172+
173+
// Restore the previous context and verify the handle is still usable.
174+
SynchronizationContext.SetSynchronizationContext(previous);
175+
176+
byte[] readBuffer = new byte[expectedData.Length];
177+
int bytesRead = RandomAccess.Read(handle, readBuffer, 0);
178+
Assert.Equal(expectedData.Length, bytesRead);
179+
Assert.Equal(expectedData, readBuffer);
170180
}
171181
finally
172182
{

0 commit comments

Comments
 (0)