From a01a8838337b7067e3b24427373c8ca18eba652c Mon Sep 17 00:00:00 2001 From: Adam Sitnik Date: Wed, 11 Aug 2021 16:19:09 +0200 Subject: [PATCH 1/3] validate hypothesis that numBytes != 0 for cancelled writes on Win 7 x86 --- .../SafeFileHandle.OverlappedValueTaskSource.Windows.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.OverlappedValueTaskSource.Windows.cs b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.OverlappedValueTaskSource.Windows.cs index 1ba3516c42a9f1..b0242c679434b6 100644 --- a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.OverlappedValueTaskSource.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.OverlappedValueTaskSource.Windows.cs @@ -200,6 +200,12 @@ internal void Complete(uint errorCode, uint numBytes) OSFileStreamStrategy? strategy = _strategy; ReleaseResources(); + if (errorCode != Interop.Errors.ERROR_SUCCESS && numBytes != 0) + { + _source.SetException(new Exception($"The error code was {errorCode} and numBytes was {numBytes}")); + return; + } + if (strategy is not null && _bufferSize != numBytes) // true only for incomplete operations { strategy.OnIncompleteOperation(_bufferSize, (int)numBytes); From cdfd100e7259b12a48ca46cd486aba4b546bb580 Mon Sep 17 00:00:00 2001 From: Adam Sitnik Date: Wed, 11 Aug 2021 16:19:42 +0200 Subject: [PATCH 2/3] run it 10k times to make sure the problem is hit by the CI --- .../tests/FileStream/WriteAsync.cs | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.IO.FileSystem/tests/FileStream/WriteAsync.cs b/src/libraries/System.IO.FileSystem/tests/FileStream/WriteAsync.cs index 06a9422589ee84..2b91becd25c6f3 100644 --- a/src/libraries/System.IO.FileSystem/tests/FileStream/WriteAsync.cs +++ b/src/libraries/System.IO.FileSystem/tests/FileStream/WriteAsync.cs @@ -100,15 +100,24 @@ public async Task SimpleWriteAsync() } } + [Fact] + public async Task TriggerTheProblemAsync() + { + for (int i = 0; i < 10_000; i++) + { + await WriteAsyncCancelledFile(0, FileOptions.Asynchronous | FileOptions.DeleteOnClose); + } + } + [Theory] - [InlineData(0, true)] // 0 == no buffering - [InlineData(4096, true)] // 4096 == default buffer size - [InlineData(0, false)] - [InlineData(4096, false)] - public async Task WriteAsyncCancelledFile(int bufferSize, bool isAsync) + [InlineData(0, FileOptions.Asynchronous)] // 0 == no buffering + [InlineData(4096, FileOptions.Asynchronous)] // 4096 == default buffer size + [InlineData(0, FileOptions.None)] + [InlineData(4096, FileOptions.None)] + public async Task WriteAsyncCancelledFile(int bufferSize, FileOptions fileOptions) { const int writeSize = 1024 * 1024; - using (FileStream fs = new FileStream(GetTestFilePath(), FileMode.CreateNew, FileAccess.Write, FileShare.None, bufferSize, isAsync)) + using (FileStream fs = new FileStream(GetTestFilePath(), FileMode.CreateNew, FileAccess.Write, FileShare.None, bufferSize, fileOptions)) { byte[] buffer = new byte[writeSize]; CancellationTokenSource cts = new CancellationTokenSource(); From 8d00e2a34dc90c040ccff711a744fcc8d7982197 Mon Sep 17 00:00:00 2001 From: Adam Sitnik Date: Wed, 11 Aug 2021 17:55:52 +0200 Subject: [PATCH 3/3] change sth to re-trigger the CI --- .../System.IO.FileSystem/tests/FileStream/WriteAsync.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.IO.FileSystem/tests/FileStream/WriteAsync.cs b/src/libraries/System.IO.FileSystem/tests/FileStream/WriteAsync.cs index 2b91becd25c6f3..a3077a5e7eb612 100644 --- a/src/libraries/System.IO.FileSystem/tests/FileStream/WriteAsync.cs +++ b/src/libraries/System.IO.FileSystem/tests/FileStream/WriteAsync.cs @@ -103,9 +103,12 @@ public async Task SimpleWriteAsync() [Fact] public async Task TriggerTheProblemAsync() { - for (int i = 0; i < 10_000; i++) + if (OperatingSystem.IsWindows()) { - await WriteAsyncCancelledFile(0, FileOptions.Asynchronous | FileOptions.DeleteOnClose); + for (int i = 0; i < 10_000; i++) + { + await WriteAsyncCancelledFile(0, FileOptions.Asynchronous | FileOptions.DeleteOnClose); + } } }