Skip to content

Commit 38295b4

Browse files
committed
Fix race condition in GetExitCodeAsync().
After `WaitForExitAsync`, the git process has written all its output to the pipes and terminated. However, it's possible that CodeConverter process has not yet read the data from the pipe, or that `OutputDataReceived` event is still executing after `GetExitCodeAsync()` returns. This can cause an `ObjectDisposedException` if the caller manages to dispose the `StringWriter` before the data is read from the pipe. The `OutputDataReceived` event is called once with `e.Data == null` to signify the end-of-output. Waiting for that prevents the race condition.
1 parent 41a53e0 commit 38295b4

File tree

1 file changed

+15
-5
lines changed

1 file changed

+15
-5
lines changed

CommandLine/CodeConv.Shared/Util/ProcessRunner.cs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,28 @@ private static async Task<int> GetExitCodeAsync(this ProcessStartInfo psi, TextW
3636
psi.RedirectStandardError = true;
3737
psi.RedirectStandardOutput = true;
3838
using var process = new Process() { StartInfo = psi };
39-
process.OutputDataReceived += (sender, e) => stdOut.WriteLine(e.Data);
40-
process.ErrorDataReceived += (sender, e) => stdErr.WriteLine(e.Data);
39+
var stdOutComplete = new TaskCompletionSource<object?>();
40+
var stdErrComplete = new TaskCompletionSource<object?>();
41+
process.OutputDataReceived += (sender, e) => {
42+
if (e.Data != null)
43+
stdOut.WriteLine(e.Data);
44+
else
45+
stdOutComplete.SetResult(null);
46+
};
47+
process.ErrorDataReceived += (sender, e) => {
48+
if (e.Data != null)
49+
stdErr.WriteLine(e.Data);
50+
else
51+
stdErrComplete.SetResult(null);
52+
};
4153
try {
4254
process.Start();
4355
} catch (Win32Exception win32Exception) {
4456
return win32Exception.ErrorCode;
4557
}
4658
process.BeginOutputReadLine();
4759
process.BeginErrorReadLine();
48-
await process.WaitForExitAsync();
49-
await stdOut.FlushAsync();
50-
await stdErr.FlushAsync();
60+
await Task.WhenAll(process.WaitForExitAsync(), stdOutComplete.Task, stdErrComplete.Task);
5161

5262
return process.ExitCode;
5363
}

0 commit comments

Comments
 (0)