Skip to content
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

bpo-38630: subprocess: enhance send_signal() on Unix #16984

Merged
merged 1 commit into from
Jan 15, 2020
Merged

bpo-38630: subprocess: enhance send_signal() on Unix #16984

merged 1 commit into from
Jan 15, 2020

Conversation

vstinner
Copy link
Member

@vstinner vstinner commented Oct 29, 2019

On Unix, subprocess.Popen.send_signal() now polls the process status.
Polling reduces the risk of sending a signal to the wrong process if
the process completed, but its identifier has been reassigned
(recycled) to a new different process.

https://bugs.python.org/issue38630

@vstinner
Copy link
Member Author

vstinner commented Oct 29, 2019

For the test, I tried to call os.kill(pid, 0) in a loop to wait until the process completes without calling waitpid(). os.kill(pid, 0) doesn't fail even if the process already completes. It only starts failing when waitpid() is called.

@vstinner
Copy link
Member Author

@gpshead: Would you mind to review this change? The additional poll() call should be cheap in term of performance and it makes the code "more correct" (reduce the risk of race condition).

@gpshead
Copy link
Member

gpshead commented Oct 30, 2019

feel free to backport this to 3.8 if you want.

@vstinner
Copy link
Member Author

vstinner commented Nov 5, 2019

Note for myself: I would like to elaborate a few comments before merging the change. I need to clarify in which cases the polling is required.

@vstinner
Copy link
Member Author

vstinner commented Nov 5, 2019

@gpshead: I elaborated send_signal() comment. Would you mind to review my updated PR? I also added a comment explaining why my change does not fully fix the race condition, it only reduces the risk.

I would like to backport this bugfix to Python 3.7 and 3.8 branch.


By the way, what do you have think of modifying send_signal(), terminate() and kill() return value? Return True if a signal has been set, or False if the method did nothing.

The return value must not be modified in micro releases (3.7 and 3.8 branches). I'm only talking about the master branch (future Python 3.9).

I will propose a separated PR once this one is merged.

@vstinner vstinner requested a review from gpshead November 5, 2019 13:02
@vstinner
Copy link
Member Author

vstinner commented Nov 5, 2019

cc @giampaolo

On Unix, subprocess.Popen.send_signal() now polls the process status.
Polling reduces the risk of sending a signal to the wrong process if
the process completed, the Popen.returncode attribute is still None,
and the pid has been reassigned (recycled) to a new different
process.
@gpshead
Copy link
Member

gpshead commented Nov 5, 2019

seems fine for 3.7 and 3.8 as well. i waffled on trying to enhance the wording in the docs to mention the possible race condition, but those are all unusual circumstances not worth laying out in the docs for send_signal.

@vstinner
Copy link
Member Author

vstinner commented Nov 6, 2019

i waffled on trying to enhance the wording in the docs to mention the possible race condition, but those are all unusual circumstances not worth laying out in the docs for send_signal.

I agree :-)

@vstinner
Copy link
Member Author

@giampaolo, @njsmith: I understand that there are other approaches to fix https://bugs.python.org/issue38630 but are you ok with this change which is simple enough and reduce the risk?

@njsmith
Copy link
Contributor

njsmith commented Nov 13, 2019

It's not clear to me that this actually does reduce the risk. Merging won't do any harm; it's a no-op at worst. But the comment seems misleading, and you should make sure the bug isn't marked as closed.

@giampaolo
Copy link
Contributor

giampaolo commented Nov 13, 2019

I don't have a strong opinion about this change. It seems it does not do any harm so it can probably be committed, but at the same time it does not solve the original problem either. For that (avoiding to kill() a reused process PID) the right solution IMO is using the process creation time. It appears to be more portable than using the pidfd API(s) as it's Linux only (?).

@njsmith
Copy link
Contributor

njsmith commented Nov 13, 2019

I don't see any way process creation time can fix the race condition (kill doesn't take a process creation time!), but that discussion should probably go in the bpo issue. That issue also has another suggestion that I think does actually solve the race condition.

@csabella
Copy link
Contributor

Should this be flagged for additional discussion or is it ready to be merged? Thanks!

@vstinner vstinner merged commit e85a305 into python:master Jan 15, 2020
@vstinner vstinner deleted the subprocess_send_signal branch January 15, 2020 16:38
shihai1991 pushed a commit to shihai1991/cpython that referenced this pull request Jan 31, 2020
…H-16984)

On Unix, subprocess.Popen.send_signal() now polls the process status.
Polling reduces the risk of sending a signal to the wrong process if
the process completed, the Popen.returncode attribute is still None,
and the pid has been reassigned (recycled) to a new different
process.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants