From 682107cf458578ee6bd92b7cc6862113034a4fad Mon Sep 17 00:00:00 2001 From: Zackery Spytz Date: Mon, 9 Sep 2019 09:48:32 -0600 Subject: bpo-36279: Ensure os.wait3() rusage is initialized (GH-15111) Co-Authored-By: David Wilson --- Lib/test/test_wait3.py | 18 ++++++++++++++++++ .../2019-08-04-12-24-18.bpo-36279.8Zy7jZ.rst | 1 + Modules/posixmodule.c | 6 ++++++ 3 files changed, 25 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2019-08-04-12-24-18.bpo-36279.8Zy7jZ.rst diff --git a/Lib/test/test_wait3.py b/Lib/test/test_wait3.py index eb51b2c..3825451 100644 --- a/Lib/test/test_wait3.py +++ b/Lib/test/test_wait3.py @@ -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 index 0000000..0d045c5 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2019-08-04-12-24-18.bpo-36279.8Zy7jZ.rst @@ -0,0 +1 @@ +Fix potential use of uninitialized memory in :func:`os.wait3`. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 81704ee..a0a2a30 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -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) -- cgit v0.12