Skip to content

Commit 15c11c6

Browse files
committed
gitconfig: avoid deadlock on large amounts of config data
As per the Remarks section in https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.processstartinfo.redirectstandardoutput we should first read the output until the end before waiting for the `git config` process to finish, to avoid deadlocks. This indeed helps in the situation of this developer whose config is so large that `git config -l` produces 25 kilobyte worth of output. Apparently, this fills up some buffer that seems to be around 8kB and then `git config -l` waits for its output to be consumed, and before this patch, the consumer (i.e. GCM Core) would wait for `git config -l` to exit already.
1 parent 13f53e0 commit 15c11c6

File tree

1 file changed

+6
-6
lines changed

1 file changed

+6
-6
lines changed

src/shared/Microsoft.Git.CredentialManager/GitConfiguration.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ public void Enumerate(GitConfigurationEnumerationCallback cb)
101101
using (Process git = _git.CreateProcess($"config --null {level} --list"))
102102
{
103103
git.Start();
104+
// To avoid deadlocks, always read the output stream first and then wait
105+
// TODO: don't read in all the data at once; stream it
106+
string data = git.StandardOutput.ReadToEnd();
104107
git.WaitForExit();
105108

106109
switch (git.ExitCode)
@@ -112,9 +115,6 @@ public void Enumerate(GitConfigurationEnumerationCallback cb)
112115
$"Failed to enumerate all Git configuration entries. Exit code '{git.ExitCode}' (level={_filterLevel})");
113116
}
114117

115-
// TODO: don't read in all the data at once; stream it
116-
string data = git.StandardOutput.ReadToEnd();
117-
118118
IEnumerable<string> entries = data.Split('\0').Where(x => !string.IsNullOrWhiteSpace(x));
119119
foreach (string entry in entries)
120120
{
@@ -217,6 +217,9 @@ public IEnumerable<string> GetRegex(string nameRegex, string valueRegex)
217217
using (Process git = _git.CreateProcess($"config --null {level} --get-regex {nameRegex} {valueRegex}"))
218218
{
219219
git.Start();
220+
// To avoid deadlocks, always read the output stream first and then wait
221+
// TODO: don't read in all the data at once; stream it
222+
string data = git.StandardOutput.ReadToEnd();
220223
git.WaitForExit();
221224

222225
switch (git.ExitCode)
@@ -229,9 +232,6 @@ public IEnumerable<string> GetRegex(string nameRegex, string valueRegex)
229232
$"Failed to get Git configuration multi-valued entry '{nameRegex}' with value regex '{valueRegex}'. Exit code '{git.ExitCode}' (level={_filterLevel})");
230233
}
231234

232-
// TODO: don't read in all the data at once; stream it
233-
string data = git.StandardOutput.ReadToEnd();
234-
235235
string[] entries = data.Split('\0');
236236
foreach (string entry in entries)
237237
{

0 commit comments

Comments
 (0)