Skip to content

Commit b073509

Browse files
authored
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.
1 parent 3a55450 commit b073509

File tree

3 files changed

+35
-6
lines changed

3 files changed

+35
-6
lines changed

Lib/test/test_os.py

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2675,12 +2675,37 @@ def test_getppid(self):
26752675
# We are the parent of our subprocess
26762676
self.assertEqual(int(stdout), os.getpid())
26772677

2678+
def check_waitpid(self, code, exitcode):
2679+
if sys.platform == 'win32':
2680+
# On Windows, os.spawnv() simply joins arguments with spaces:
2681+
# arguments need to be quoted
2682+
args = [f'"{sys.executable}"', '-c', f'"{code}"']
2683+
else:
2684+
args = [sys.executable, '-c', code]
2685+
pid = os.spawnv(os.P_NOWAIT, sys.executable, args)
2686+
2687+
pid2, status = os.waitpid(pid, 0)
2688+
if sys.platform == 'win32':
2689+
self.assertEqual(status, exitcode << 8)
2690+
else:
2691+
self.assertTrue(os.WIFEXITED(status), status)
2692+
self.assertEqual(os.WEXITSTATUS(status), exitcode)
2693+
self.assertEqual(pid2, pid)
2694+
26782695
def test_waitpid(self):
2679-
args = [sys.executable, '-c', 'pass']
2680-
# Add an implicit test for PyUnicode_FSConverter().
2681-
pid = os.spawnv(os.P_NOWAIT, FakePath(args[0]), args)
2682-
status = os.waitpid(pid, 0)
2683-
self.assertEqual(status, (pid, 0))
2696+
self.check_waitpid(code='pass', exitcode=0)
2697+
2698+
def test_waitpid_exitcode(self):
2699+
exitcode = 23
2700+
code = f'import sys; sys.exit({exitcode})'
2701+
self.check_waitpid(code, exitcode=exitcode)
2702+
2703+
@unittest.skipUnless(sys.platform == 'win32', 'win32-specific test')
2704+
def test_waitpid_windows(self):
2705+
# bpo-40138: test os.waitpid() with exit code larger than INT_MAX.
2706+
STATUS_CONTROL_C_EXIT = 0xC000013A
2707+
code = f'import _winapi; _winapi.ExitProcess({STATUS_CONTROL_C_EXIT})'
2708+
self.check_waitpid(code, exitcode=STATUS_CONTROL_C_EXIT)
26842709

26852710

26862711
class SpawnTests(unittest.TestCase):
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix the Windows implementation of :func:`os.waitpid` for exit code larger than
2+
``INT_MAX >> 8``. The exit status is now interpreted as an unsigned number.

Modules/posixmodule.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7867,8 +7867,10 @@ os_waitpid_impl(PyObject *module, intptr_t pid, int options)
78677867
if (res < 0)
78687868
return (!async_err) ? posix_error() : NULL;
78697869

7870+
unsigned long long ustatus = (unsigned int)status;
7871+
78707872
/* shift the status left a byte so this is more like the POSIX waitpid */
7871-
return Py_BuildValue(_Py_PARSE_INTPTR "i", res, status << 8);
7873+
return Py_BuildValue(_Py_PARSE_INTPTR "K", res, ustatus << 8);
78727874
}
78737875
#endif
78747876

0 commit comments

Comments
 (0)