[Python-checkins] bpo-40138: Fix Windows os.waitpid() for large exit code (GH-19654)

Miss Islington (bot) webhook-mailer at python.org
Wed Apr 22 12:16:52 EDT 2020


https://github.com/python/cpython/commit/de5dcfa3bcabf52e43468a2b088ed71b5e5c4503
commit: de5dcfa3bcabf52e43468a2b088ed71b5e5c4503
branch: 3.7
author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
committer: GitHub <noreply at github.com>
date: 2020-04-22T09:16:42-07:00
summary:

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.
(cherry picked from commit b07350901cac9197aef41855d8a4d56533636b91)

Co-authored-by: Victor Stinner <vstinner at python.org>

files:
A Misc/NEWS.d/next/Library/2020-04-22-00-05-10.bpo-40138.i_oGqa.rst
M Lib/test/test_os.py
M Modules/posixmodule.c

diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
index 411e5aa507389..3a76940a08947 100644
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -2417,12 +2417,37 @@ def test_getppid(self):
         # 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 0000000000000..ad5faf3865751
--- /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 87ef2a9e0d22e..977e49f432a34 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -7127,8 +7127,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
 



More information about the Python-checkins mailing list