Process: avoid performing operations on a different process with recycled pid#28404
Process: avoid performing operations on a different process with recycled pid#28404stephentoub merged 8 commits intodotnet:masterfrom
Conversation
|
unrelated CI fail in ClientAsyncAuthenticate_AllServerVsIndividualClientSupportedProtocols_Success(clientProtocol: Tls) on OSX.1012: |
|
@dotnet-bot test this please |
|
I want to update the test that is added in #27763 to cover this. I'll do that when that PR is merged. |
|
|
||
| if (GetWaitState().GetExited(out _, refresh)) | ||
| { | ||
| throw new InvalidOperationException(SR.Format(SR.ProcessHasExited, _processId.ToString(CultureInfo.CurrentCulture))); |
There was a problem hiding this comment.
Is the CultureInfo.CurrentCulture needed?
There was a problem hiding this comment.
I lifted this exception from GetProcessHandle. I don't know if it is needed.
There was a problem hiding this comment.
We can remove it. It won't affect the default formatting.
| { | ||
| HaveId = 0x1, | ||
| IsLocal = 0x2, | ||
| HaveNonExitedId = HaveId | 0x4, |
There was a problem hiding this comment.
It was nice of Nt to leave a gap here :)
| } | ||
| if (pws == null) | ||
| { | ||
| pws = new ProcessWaitState(processId, isChild: false, exitTime); |
There was a problem hiding this comment.
Can you help me understand this better? It's not clear to me from this code nor from the comment why a different ProcessWaitState object helps with anything. What's the key difference between the pws we nulled out and this one we're creating?
There was a problem hiding this comment.
The key difference is the new pws isn't in the exited state.
If we have a non-child Process with a recycled PID and we'd reused the exited pws, then the Process is unusable because HaveNonExitedId throws.
|
I suppose it is unlikely this would help fix https://github.com/dotnet/corefx/issues/28668 |
|
@dotnet-bot test this please |
|
@tmds @stephentoub given all the churn to pid management in the last month and we are about to enter ask -mode for 2.1 changes, do we need some focused stress testing to reduce risk here? |
|
Yes. I'm not comfortable with the level of churn and the associated risks on stability. I'm concerned we've been fixing some niche issues that could cause problems for some, but only in rare conditions, and in exchange potentially causing problems for main-stream cases. It's possible of course everything is fine, but... |
|
@stephentoub what do you suggest? Defer changes (which) or test more first? Perhaps take this change then do focused testing, based on that choose if and whether it is necessary to revert any part for 2.1? Testing would have to cover distro /Mac matrix. |
|
I'd suggest testing more first. I'm not convinced this PR is necessary for 2.1. |
|
@ViktorHofer could you please look at this and related pid-tracking changes (@stephentoub can list them perhaps) and devise and execute a plan for stress tests? We can use CI/official runs to cover the matrix. |
|
The most recent two shown here: https://github.com/dotnet/corefx/commits/master/src/System.Diagnostics.Process/src?author=tmds. They overhaul how process waiting works. |
|
These are the related PRs:
The first PR is the most important one. It is also the most risky/churny. edit: #26291 is in preview2 so it will get some external 'testing' too. |
sorry, I missed that one. does this still apply? |
|
@ViktorHofer it's less urgent but yes, I would look at the changes above by @tmds, the tests he performed locally and/or added, and recommend whether we should add more test coverage/stress tests. |
|
@dotnet-bot test this please |
| return; | ||
| } | ||
|
|
||
| if (GetWaitState().GetExited(out _, refresh)) |
There was a problem hiding this comment.
Maybe combine the above into:
if ((_waitStateHolder != null || refresh) && GetWaitState().GetExited(out _, refresh))?
|
@tmds seems I can merge, unless you want to update per suggestion above? |
|
The combined check would be: I've left it separate and added a comment what we're checking for. |
It would? Doesn't the == need to be != ? Otherwise I'm confused. |
|
|
Ok, but how does that work with the current check? Currently you return if _waitStateHolder == null && !refresh. So not returning is !(_waitStateHolder == null && !refresh) which is _waitStateHolder != null || refresh. |
|
Correct. The combined check is: I think you had suggested but that would have been different too. I had added a comment about what we're checking to make it more clear. Do you prefer putting things in a single if statement? with the comment? |
Yes
Yes, we both had it wrong. I fixed mine after the fact.
Either is fine. But I wanted to make sure what's there is what you intended since the combined version you shared initially didn't match the behavior. |
…ycled pid (dotnet/corefx#28404) * Process: avoid performing operations on a different process with recycled pid * ThrowIfExited: don't create ProcessWaitState(Holder) if we are not refreshing * Handle non-child pid recycling * ProcessWaitState: update overview comment to reflect current implementation * Update TestProcessRecycledPid * Add comment to ThrowIfExited * Remove CultureInfo.CurrentCulture from _processId.ToString Commit migrated from dotnet/corefx@4e27e0a
With recent changes to the Process class, we know when our child processes have exited.
We can use this information to ensure a process instance doesn't start hitting a different process with a recycled pid.
Requires #27763
Example code:
This code will throw when the Kill operation targets a recycled pid:
CC @stephentoub @danmosemsft @wfurt