diff options
author | Victor Stinner <vstinner@python.org> | 2020-04-22 15:57:59 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-22 15:57:59 (GMT) |
commit | b07350901cac9197aef41855d8a4d56533636b91 (patch) | |
tree | b9ab42158db0cea7b537f8dc3e23d9f8ec2bedba | |
parent | 3a5545025685040842420c85a4a9aab5f044aeb8 (diff) | |
download | cpython-b07350901cac9197aef41855d8a4d56533636b91.zip cpython-b07350901cac9197aef41855d8a4d56533636b91.tar.gz cpython-b07350901cac9197aef41855d8a4d56533636b91.tar.bz2 |
bpo-40138: Fix Windows os.waitpid() for large exit code (GH-19654)
Fix the Windows implementation of os.waitpid() for exit code
larger than "INT_MAX >> 8". The exit status is now interpreted as an
unsigned number.
-rw-r--r-- | Lib/test/test_os.py | 35 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2020-04-22-00-05-10.bpo-40138.i_oGqa.rst | 2 | ||||
-rw-r--r-- | Modules/posixmodule.c | 4 |
3 files changed, 35 insertions, 6 deletions
diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index 11454b2..2a4ae15 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -2675,12 +2675,37 @@ class PidTests(unittest.TestCase): # We are the parent of our subprocess self.assertEqual(int(stdout), os.getpid()) + def check_waitpid(self, code, exitcode): + if sys.platform == 'win32': + # On Windows, os.spawnv() simply joins arguments with spaces: + # arguments need to be quoted + args = [f'"{sys.executable}"', '-c', f'"{code}"'] + else: + args = [sys.executable, '-c', code] + pid = os.spawnv(os.P_NOWAIT, sys.executable, args) + + pid2, status = os.waitpid(pid, 0) + if sys.platform == 'win32': + self.assertEqual(status, exitcode << 8) + else: + self.assertTrue(os.WIFEXITED(status), status) + self.assertEqual(os.WEXITSTATUS(status), exitcode) + self.assertEqual(pid2, pid) + def test_waitpid(self): - args = [sys.executable, '-c', 'pass'] - # Add an implicit test for PyUnicode_FSConverter(). - pid = os.spawnv(os.P_NOWAIT, FakePath(args[0]), args) - status = os.waitpid(pid, 0) - self.assertEqual(status, (pid, 0)) + self.check_waitpid(code='pass', exitcode=0) + + def test_waitpid_exitcode(self): + exitcode = 23 + code = f'import sys; sys.exit({exitcode})' + self.check_waitpid(code, exitcode=exitcode) + + @unittest.skipUnless(sys.platform == 'win32', 'win32-specific test') + def test_waitpid_windows(self): + # bpo-40138: test os.waitpid() with exit code larger than INT_MAX. + STATUS_CONTROL_C_EXIT = 0xC000013A + code = f'import _winapi; _winapi.ExitProcess({STATUS_CONTROL_C_EXIT})' + self.check_waitpid(code, exitcode=STATUS_CONTROL_C_EXIT) class SpawnTests(unittest.TestCase): diff --git a/Misc/NEWS.d/next/Library/2020-04-22-00-05-10.bpo-40138.i_oGqa.rst b/Misc/NEWS.d/next/Library/2020-04-22-00-05-10.bpo-40138.i_oGqa.rst new file mode 100644 index 0000000..ad5faf3 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-04-22-00-05-10.bpo-40138.i_oGqa.rst @@ -0,0 +1,2 @@ +Fix the Windows implementation of :func:`os.waitpid` for exit code larger than +``INT_MAX >> 8``. The exit status is now interpreted as an unsigned number. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index d40827d..eb0b56a 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -7867,8 +7867,10 @@ os_waitpid_impl(PyObject *module, intptr_t pid, int options) if (res < 0) return (!async_err) ? posix_error() : NULL; + unsigned long long ustatus = (unsigned int)status; + /* shift the status left a byte so this is more like the POSIX waitpid */ - return Py_BuildValue(_Py_PARSE_INTPTR "i", res, status << 8); + return Py_BuildValue(_Py_PARSE_INTPTR "K", res, ustatus << 8); } #endif |