-
-
Notifications
You must be signed in to change notification settings - Fork 33.7k
Description
Bug report
Bug description:
This is primarily motivated by shadow/shadow#3697. The shadow simulator runs unmodified Linux software in an emulated environment where time passes precisely and deterministically. We use it at the Tor project for experimentation and testing. More about shadow, including academic publications about and using it, can be found at https://shadow.github.io/.
Popen.communicate passes the remaining time as a timeout to the poll syscall (on Linux). Under shadow's default time model, the poll syscall returns with a timeout after exactly that amount of time has passed, and no more time will have passed when remaining time is calculated in the Popen._communicate loop. This means that the calculated remaining time will be exactly 0. Since the loop only terminates when strictly less than 0 time remains, the loop never terminates.
As a result, under shadow, the following python program never terminates:
import subprocess as sp
p = sp.Popen(['sleep', '1'], stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE)
p.communicate(timeout=0.01)I've locally verified that the following patch fixes the issue under shadow, and python's "make test" still passes:
diff --git a/Lib/subprocess.py b/Lib/subprocess.py
index 4d5ab6fbff0..0dbc2d2e4e3 100644
--- a/Lib/subprocess.py
+++ b/Lib/subprocess.py
@@ -2140,7 +2140,7 @@ def _communicate(self, input, endtime, orig_timeout):
while selector.get_map():
timeout = self._remaining_time(endtime)
- if timeout is not None and timeout < 0:
+ if timeout is not None and timeout <= 0:
self._check_timeout(endtime, orig_timeout,
stdout, stderr,
skip_check_and_raise=True)Would you be amenable to a PR with this change?
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux