From 30b7d7037810e3b09d7a446816e04637bd42bb9f Mon Sep 17 00:00:00 2001 From: Patrick Meinecke Date: Thu, 4 Jan 2024 13:25:54 -0500 Subject: [PATCH 1/4] Keep old message queue when error is redirected Fixes #20747 --- .../engine/NativeCommandProcessor.cs | 11 +++++++---- .../NativeExecution/NativeCommandProcessor.Tests.ps1 | 6 ++++++ test/tools/TestExe/TestExe.cs | 4 ++++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/System.Management.Automation/engine/NativeCommandProcessor.cs b/src/System.Management.Automation/engine/NativeCommandProcessor.cs index 02af209f6ed..1920f0e5331 100644 --- a/src/System.Management.Automation/engine/NativeCommandProcessor.cs +++ b/src/System.Management.Automation/engine/NativeCommandProcessor.cs @@ -817,7 +817,10 @@ private ProcessOutputObject DequeueProcessOutput(bool blocking) if (_stdOutByteTransfer is not null) { _stdOutByteTransfer.EOF.GetAwaiter().GetResult(); - return null; + if (!_nativeProcess.StartInfo.RedirectStandardError) + { + return null; + } } // If adding was completed and collection is empty (IsCompleted == true) @@ -843,7 +846,7 @@ private ProcessOutputObject DequeueProcessOutput(bool blocking) } else { - if (_stdOutByteTransfer is not null) + if (_stdOutByteTransfer is not null && !_nativeProcess.StartInfo.RedirectStandardError) { return null; } @@ -886,7 +889,7 @@ internal override void Complete() if (!_isRunningInBackground) { // Wait for input writer to finish. - if (!UpstreamIsNativeCommand) + if (!UpstreamIsNativeCommand || _nativeProcess.StartInfo.RedirectStandardError) { _inputWriter.Done(); } @@ -1771,7 +1774,7 @@ public ProcessOutputHandler( // we incrementing refCount on the same thread and before running any processing // so it's safe to do it without Interlocked. - if (process.StartInfo.RedirectStandardOutput) + if (process.StartInfo.RedirectStandardOutput && stdOutDestination is null) { _refCount++; } diff --git a/test/powershell/Language/Scripting/NativeExecution/NativeCommandProcessor.Tests.ps1 b/test/powershell/Language/Scripting/NativeExecution/NativeCommandProcessor.Tests.ps1 index d166ca265c7..ab03227878d 100644 --- a/test/powershell/Language/Scripting/NativeExecution/NativeCommandProcessor.Tests.ps1 +++ b/test/powershell/Language/Scripting/NativeExecution/NativeCommandProcessor.Tests.ps1 @@ -213,6 +213,12 @@ Describe "Native Command Processor" -tags "Feature" { Wait-UntilTrue -sb { (Get-Process mmc).Count -gt 0 } -TimeoutInMilliseconds 5000 -IntervalInMilliseconds 1000 | Should -BeTrue Get-Process mmc | Stop-Process } + + It 'Can redirect stdout and stderr to different files' { + testexe -stderrandout testing > $TestDrive/stdout.txt 2> $TestDrive/stderr.txt + Get-Content $TestDrive/stdout.txt | Should -Be testing + Get-Content $TestDrive/stderr.txt | Should -Be testing + } } Describe "Open a text file with NativeCommandProcessor" -tags @("Feature", "RequireAdminOnWindows") { diff --git a/test/tools/TestExe/TestExe.cs b/test/tools/TestExe/TestExe.cs index a91e2141b58..64f4cab3609 100644 --- a/test/tools/TestExe/TestExe.cs +++ b/test/tools/TestExe/TestExe.cs @@ -36,6 +36,10 @@ private static int Main(string[] args) case "-stderr": Console.Error.WriteLine(args[1]); break; + case "-stderrandout": + Console.WriteLine(args[1]); + Console.Error.WriteLine(args[1]); + break; case "-readbytes": ReadBytes(); break; From f75140e1165745501777de3ec8d3c81e13a5bcb2 Mon Sep 17 00:00:00 2001 From: Patrick Meinecke Date: Wed, 17 Jan 2024 13:44:28 -0500 Subject: [PATCH 2/4] Address feedback --- .../Scripting/NativeExecution/NativeCommandProcessor.Tests.ps1 | 2 +- test/tools/TestExe/TestExe.cs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/test/powershell/Language/Scripting/NativeExecution/NativeCommandProcessor.Tests.ps1 b/test/powershell/Language/Scripting/NativeExecution/NativeCommandProcessor.Tests.ps1 index ab03227878d..542f1724303 100644 --- a/test/powershell/Language/Scripting/NativeExecution/NativeCommandProcessor.Tests.ps1 +++ b/test/powershell/Language/Scripting/NativeExecution/NativeCommandProcessor.Tests.ps1 @@ -217,7 +217,7 @@ Describe "Native Command Processor" -tags "Feature" { It 'Can redirect stdout and stderr to different files' { testexe -stderrandout testing > $TestDrive/stdout.txt 2> $TestDrive/stderr.txt Get-Content $TestDrive/stdout.txt | Should -Be testing - Get-Content $TestDrive/stderr.txt | Should -Be testing + Get-Content $TestDrive/stderr.txt | Should -Be gnitset } } diff --git a/test/tools/TestExe/TestExe.cs b/test/tools/TestExe/TestExe.cs index 64f4cab3609..39c1d2b2ecb 100644 --- a/test/tools/TestExe/TestExe.cs +++ b/test/tools/TestExe/TestExe.cs @@ -8,6 +8,7 @@ using System.Runtime.InteropServices; using System.IO; using System.Globalization; +using System.Linq; namespace TestExe { @@ -38,7 +39,7 @@ private static int Main(string[] args) break; case "-stderrandout": Console.WriteLine(args[1]); - Console.Error.WriteLine(args[1]); + Console.Error.WriteLine(new string(args[1].ToCharArray().Reverse().ToArray())); break; case "-readbytes": ReadBytes(); From e090f7ee4c786986d1e68e07c5c02a631b8eba07 Mon Sep 17 00:00:00 2001 From: Patrick Meinecke Date: Mon, 4 Mar 2024 15:07:58 -0500 Subject: [PATCH 3/4] Move drain logic out of DequeueProcessOutput --- .../engine/NativeCommandProcessor.cs | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/System.Management.Automation/engine/NativeCommandProcessor.cs b/src/System.Management.Automation/engine/NativeCommandProcessor.cs index 1920f0e5331..fb3d8a51a92 100644 --- a/src/System.Management.Automation/engine/NativeCommandProcessor.cs +++ b/src/System.Management.Automation/engine/NativeCommandProcessor.cs @@ -814,15 +814,6 @@ private ProcessOutputObject DequeueProcessOutput(bool blocking) { if (blocking) { - if (_stdOutByteTransfer is not null) - { - _stdOutByteTransfer.EOF.GetAwaiter().GetResult(); - if (!_nativeProcess.StartInfo.RedirectStandardError) - { - return null; - } - } - // If adding was completed and collection is empty (IsCompleted == true) // there is no need to do a blocking Take(), we should just return. if (!_nativeProcessOutputQueue.IsCompleted) @@ -844,17 +835,9 @@ private ProcessOutputObject DequeueProcessOutput(bool blocking) return null; } - else - { - if (_stdOutByteTransfer is not null && !_nativeProcess.StartInfo.RedirectStandardError) - { - return null; - } - ProcessOutputObject record = null; - _nativeProcessOutputQueue.TryTake(out record); - return record; - } + _nativeProcessOutputQueue.TryTake(out ProcessOutputObject record); + return record; } /// @@ -864,19 +847,36 @@ private void ConsumeAvailableNativeProcessOutput(bool blocking) { if (!_isRunningInBackground) { - if (_nativeProcess.StartInfo.RedirectStandardOutput || _nativeProcess.StartInfo.RedirectStandardError) + return; + } + + bool stdOutRedirected = _nativeProcess.StartInfo.RedirectStandardOutput; + bool stdErrRedirected = _nativeProcess.StartInfo.RedirectStandardError; + if (stdOutRedirected && _stdOutByteTransfer is not null) + { + if (blocking) { - ProcessOutputObject record; - while ((record = DequeueProcessOutput(blocking)) != null) - { - if (this.Command.Context.CurrentPipelineStopping) - { - this.StopProcessing(); - return; - } + _stdOutByteTransfer.EOF.GetAwaiter().GetResult(); + } - ProcessOutputRecord(record); + if (!stdErrRedirected) + { + return; + } + } + + if (stdOutRedirected || stdErrRedirected) + { + ProcessOutputObject record; + while ((record = DequeueProcessOutput(blocking)) != null) + { + if (this.Command.Context.CurrentPipelineStopping) + { + this.StopProcessing(); + return; } + + ProcessOutputRecord(record); } } } From 8724456c541aa8ad32a4c81d16d796b057c39b2b Mon Sep 17 00:00:00 2001 From: Patrick Meinecke Date: Thu, 14 Mar 2024 13:47:37 -0400 Subject: [PATCH 4/4] Update src/System.Management.Automation/engine/NativeCommandProcessor.cs Co-authored-by: Dongbo Wang --- .../engine/NativeCommandProcessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Management.Automation/engine/NativeCommandProcessor.cs b/src/System.Management.Automation/engine/NativeCommandProcessor.cs index fb3d8a51a92..371e1ff00ff 100644 --- a/src/System.Management.Automation/engine/NativeCommandProcessor.cs +++ b/src/System.Management.Automation/engine/NativeCommandProcessor.cs @@ -845,7 +845,7 @@ private ProcessOutputObject DequeueProcessOutput(bool blocking) /// private void ConsumeAvailableNativeProcessOutput(bool blocking) { - if (!_isRunningInBackground) + if (_isRunningInBackground) { return; }