]> granicus.if.org Git - python/commitdiff
bpo-36279: Ensure os.wait3() rusage is initialized (GH-15111)
authorZackery Spytz <zspytz@gmail.com>
Mon, 9 Sep 2019 15:48:32 +0000 (09:48 -0600)
committerT. Wouters <thomas@python.org>
Mon, 9 Sep 2019 15:48:32 +0000 (08:48 -0700)
Co-Authored-By: David Wilson <dw@botanicus.net>
Lib/test/test_wait3.py
Misc/NEWS.d/next/Core and Builtins/2019-08-04-12-24-18.bpo-36279.8Zy7jZ.rst [new file with mode: 0644]
Modules/posixmodule.c

index eb51b2c03b232d32037302bc7ba47829b30115ed..3825451b058cc5ab82ab1ccea4c044bbf9f229f2 100644 (file)
@@ -2,6 +2,8 @@
 """
 
 import os
+import subprocess
+import sys
 import time
 import unittest
 from test.fork_wait import ForkWait
@@ -31,6 +33,22 @@ class Wait3Test(ForkWait):
         self.assertEqual(status, 0, "cause = %d, exit = %d" % (status&0xff, status>>8))
         self.assertTrue(rusage)
 
+    def test_wait3_rusage_initialized(self):
+        # Ensure a successful wait3() call where no child was ready to report
+        # its exit status does not return uninitialized memory in the rusage
+        # structure. See bpo-36279.
+        args = [sys.executable, '-c', 'import sys; sys.stdin.read()']
+        proc = subprocess.Popen(args, stdin=subprocess.PIPE)
+        try:
+            pid, status, rusage = os.wait3(os.WNOHANG)
+            self.assertEqual(0, pid)
+            self.assertEqual(0, status)
+            self.assertEqual(0, sum(rusage))
+        finally:
+            proc.stdin.close()
+            proc.wait()
+
+
 def tearDownModule():
     reap_children()
 
diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-08-04-12-24-18.bpo-36279.8Zy7jZ.rst b/Misc/NEWS.d/next/Core and Builtins/2019-08-04-12-24-18.bpo-36279.8Zy7jZ.rst
new file mode 100644 (file)
index 0000000..0d045c5
--- /dev/null
@@ -0,0 +1 @@
+Fix potential use of uninitialized memory in :func:`os.wait3`.
index 81704eec321cdf19424fd7b71a9b070e5f111d45..a0a2a305119e4355636e1a27c3e8ddea3fc2d32a 100644 (file)
@@ -7489,6 +7489,12 @@ wait_helper(pid_t pid, int status, struct rusage *ru)
     if (pid == -1)
         return posix_error();
 
+    // If wait succeeded but no child was ready to report status, ru will not
+    // have been populated.
+    if (pid == 0) {
+        memset(ru, 0, sizeof(*ru));
+    }
+
     if (struct_rusage == NULL) {
         PyObject *m = PyImport_ImportModuleNoBlock("resource");
         if (m == NULL)