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.
This commit is contained in:
Victor Stinner 2020-04-22 17:57:59 +02:00 committed by GitHub
parent 3a55450256
commit b07350901c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 35 additions and 6 deletions

View File

@ -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):

View File

@ -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.

View File

@ -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