There was an error while loading. Please reload this page.
2 parents 58b3ebf + c20a7b9 commit a439b32Copy full SHA for a439b32
2 files changed
Lib/test/test_subprocess.py
@@ -1972,6 +1972,23 @@ def test_leak_fast_process_del_killed(self):
1972
self.assertRaises(OSError, os.waitpid, pid, 0)
1973
self.assertNotIn(ident, [id(o) for o in subprocess._active])
1974
1975
+ def test_close_fds_after_preexec(self):
1976
+ fd_status = support.findfile("fd_status.py", subdir="subprocessdata")
1977
+
1978
+ # this FD is used as dup2() target by preexec_fn, and should be closed
1979
+ # in the child process
1980
+ fd = os.dup(1)
1981
+ self.addCleanup(os.close, fd)
1982
1983
+ p = subprocess.Popen([sys.executable, fd_status],
1984
+ stdout=subprocess.PIPE, close_fds=True,
1985
+ preexec_fn=lambda: os.dup2(1, fd))
1986
+ output, ignored = p.communicate()
1987
1988
+ remaining_fds = set(map(int, output.split(b',')))
1989
1990
+ self.assertNotIn(fd, remaining_fds)
1991
1992
1993
@unittest.skipUnless(mswindows, "Windows specific tests")
1994
class Win32ProcessTestCase(BaseTestCase):
Modules/_posixsubprocess.c
@@ -412,17 +412,6 @@ child_exec(char *const exec_array[],
412
POSIX_CALL(close(errwrite));
413
}
414
415
- if (close_fds) {
416
- int local_max_fd = max_fd;
417
-#if defined(__NetBSD__)
418
- local_max_fd = fcntl(0, F_MAXFD);
419
- if (local_max_fd < 0)
420
- local_max_fd = max_fd;
421
-#endif
422
- /* TODO HP-UX could use pstat_getproc() if anyone cares about it. */
423
- _close_open_fd_range(3, local_max_fd, py_fds_to_keep);
424
- }
425
-
426
if (cwd)
427
POSIX_CALL(chdir(cwd));
428
@@ -451,6 +440,18 @@ child_exec(char *const exec_array[],
451
440
/* Py_DECREF(result); - We're about to exec so why bother? */
452
441
453
442
443
+ /* close FDs after executing preexec_fn, which might open FDs */
444
+ if (close_fds) {
445
+ int local_max_fd = max_fd;
446
+#if defined(__NetBSD__)
447
+ local_max_fd = fcntl(0, F_MAXFD);
448
+ if (local_max_fd < 0)
449
+ local_max_fd = max_fd;
450
+#endif
+ /* TODO HP-UX could use pstat_getproc() if anyone cares about it. */
+ _close_open_fd_range(3, local_max_fd, py_fds_to_keep);
+ }
454
455
/* This loop matches the Lib/os.py _execvpe()'s PATH search when */
456
/* given the executable_list generated by Lib/subprocess.py. */
457
saved_errno = 0;
0 commit comments