-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Process.WaitForExit() deadlock if there are childprocess still running. #51277
Comments
Tagging subscribers to this area: @carlossanlop Issue DetailsDescriptionThis bug was first reported in the msbuild repo but I believe it's a bug in the Process class itself and not in msbuild. We hit this code path because the timeout is
Now there is no way to retrieve the data in the stdout/stderr without a concurrency issue that would cause data to be lost in case of a race condition. Other informationThis bug happens on Windows but by looking at the *nix implementation of
|
I wrote a workaround thats allow to retrieve the stdout/stderr of a process that may cause a deadlock like this. process.WaitForExit( int.MaxValue ); //First we need for the program to exit.
// Here the program exited, but background may still pump messages
ReflectionHack( process ); // This will cancel the reads in the pipes background loop.
process.WaitForExit(); // This allow to wait for the 2 pipes async to finish looping and flushing the last messages.
// Here you shouldn't receive any message.
/// <summary>
/// This method shut down things in <see cref="Process"/>. Call it when you know that the process has exited.
/// Sometimes the <see cref="Process"/> class deadlock itself.
/// See this for more info: https://github.com/dotnet/runtime/issues/51277
/// </summary>
/// <param name="process"></param>
static void ReflectionHack( Process process )
{
const BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
FieldInfo? outputField = typeof( Process ).GetField( "_output", bindingFlags );
FieldInfo? errorField = typeof( Process ).GetField( "_error", bindingFlags );
((IDisposable)outputField!.GetValue( process )!).Dispose();
((IDisposable)errorField!.GetValue( process )!).Dispose();
} Sadly the cleanest way I found to work around this issue is with this little reflection hack. Edit: I now think that this reflection hack may lead to data loss at the end of the process. |
Hello, |
I made a reproduction here: |
I found a SO post from 2016 about this bug: |
#79817 |
I just tested on WSL-ubuntu and it doesn't have the problem at all, so unix was just unaffected. |
Could you please investigate this issue as it seems to be impacting our team (MSBuild)? Your attention to this matter would be greatly appreciated. cc:@baronfel |
@MichalPavlik hey, this issue is a bit in a limbo state due to the "need-further-triage" tag, none in the runtime team looked at this issue for the past 3 years. |
I am running into this issue as well! Any updates? |
it seems to be closed by design: #29232 (comment) |
The problem is that there is a simple use case and it looks like there is no solution to it: |
Description
This bug was first reported in the msbuild repo but I believe it's a bug in the Process class itself and not in msbuild.
The issue is that
WaitForExit()
will synchronously wait for the stderr/stdout to complete, the summoned process has exited, but it has childs process still running (the nodereuse processes in msbuild case).In this case, it looks like that the stderr/stdout pipes wont close.
So we are stuck in the waits there:
https://github.com/dotnet/runtime/blob/main/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Windows.cs#L186
We hit this code path because the timeout is
Timeout.Infinite
.There is hope for a beginning of a workaround:
We can avoid the deadlock if we call
WaitForExit(int milliseconds)
.But there is an issue in this case
Now there is no way to retrieve the data in the stdout/stderr without a concurrency issue that would cause data to be lost in case of a race condition.
Other information
This bug happens on Windows
but by looking at the *nix implementation ofWaitForExitCore
, it may be affected too (I have no idea how the lifecycle of the pipes are supposed to work on linux/windows, so it's probably wrong)Edit: I tested on WSL with ubuntu and it doesn't have a problem, so it's a Windows only problem.
The text was updated successfully, but these errors were encountered: