(original) (raw)
changeset: 84892:75e5d34898aa user: Victor Stinner victor.stinner@gmail.com date: Tue Jul 30 00:27:10 2013 +0200 files: Lib/test/test_subprocess.py Modules/_posixsubprocess.c description: subprocess makes fds of pass_fds inheritable The inheritable flag is set between fork() and exec(), the change must not affect the parent process. diff -r f8a52518be4c -r 75e5d34898aa Lib/test/test_subprocess.py --- a/Lib/test/test_subprocess.py Mon Jul 29 23:24:50 2013 +0200 +++ b/Lib/test/test_subprocess.py Tue Jul 30 00:27:10 2013 +0200 @@ -1859,10 +1859,10 @@ for x in range(5): fds = os.pipe() + self.addCleanup(os.close, fds[0]) + self.addCleanup(os.close, fds[1]) os.set_inheritable(fds[0], True) os.set_inheritable(fds[1], True) - self.addCleanup(os.close, fds[0]) - self.addCleanup(os.close, fds[1]) open_fds.update(fds) for fd in open_fds: @@ -1885,6 +1885,33 @@ close_fds=False, pass_fds=(fd, ))) self.assertIn('overriding close_fds', str(context.warning)) + def test_pass_fds_inheritable(self): + script = support.findfile("inheritable.py", subdir="subprocessdata") + + inheritable, non_inheritable = os.pipe() + self.addCleanup(os.close, inheritable) + self.addCleanup(os.close, non_inheritable) + os.set_inheritable(inheritable, True) + os.set_inheritable(non_inheritable, False) + pass_fds = (inheritable, non_inheritable) + args = [sys.executable, script] + args += list(map(str, pass_fds)) + + p = subprocess.Popen(args, + stdout=subprocess.PIPE, close_fds=True, + pass_fds=pass_fds) + output, ignored = p.communicate() + fds = set(map(int, output.split(b','))) + + # the non inheritable file descriptor must be inherited, so its + # inheritable flag must be set in the child process after fork() and + # before exec() + self.assertEqual(fds, set(pass_fds)) + + # inheritable flag must not be changed in the parent process + self.assertEqual(os.get_inheritable(inheritable), True) + self.assertEqual(os.get_inheritable(non_inheritable), False) + def test_stdout_stdin_are_single_inout_fd(self): with io.open(os.devnull, "r+") as inout: p = subprocess.Popen([sys.executable, "-c", "import sys; sys.exit(0)"], diff -r f8a52518be4c -r 75e5d34898aa Modules/_posixsubprocess.c --- a/Modules/_posixsubprocess.c Mon Jul 29 23:24:50 2013 +0200 +++ b/Modules/_posixsubprocess.c Tue Jul 30 00:27:10 2013 +0200 @@ -136,6 +136,23 @@ return 0; } +static int +make_inheritable(PyObject *py_fds_to_keep) +{ + Py_ssize_t i, len; + + len = PySequence_Length(py_fds_to_keep); + for (i = 0; i < len; ++i) { + PyObject* fdobj = PySequence_Fast_GET_ITEM(py_fds_to_keep, i); + long fd = PyLong_AsLong(fdobj); + assert(!PyErr_Occurred()); + assert(0 <= fd && fd <= INT_MAX); + if (_Py_set_inheritable((int)fd, 1, NULL) < 0) + return -1; + } + return 0; +} + /* Close all file descriptors in the range start_fd inclusive to * end_fd exclusive except for those in py_fds_to_keep. If the @@ -346,6 +363,9 @@ /* Buffer large enough to hold a hex integer. We can't malloc. */ char hex_errno[sizeof(saved_errno)*2+1]; + if (make_inheritable(py_fds_to_keep) < 0) + goto error; + /* Close parent's pipe ends. */ if (p2cwrite != -1) POSIX_CALL(close(p2cwrite)); /victor.stinner@gmail.com