File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -1938,6 +1938,23 @@ def test_leak_fast_process_del_killed(self):
19381938 self .assertRaises (OSError , os .waitpid , pid , 0 )
19391939 self .assertNotIn (ident , [id (o ) for o in subprocess ._active ])
19401940
1941+ def test_close_fds_after_preexec (self ):
1942+ fd_status = support .findfile ("fd_status.py" , subdir = "subprocessdata" )
1943+
1944+ # this FD is used as dup2() target by preexec_fn, and should be closed
1945+ # in the child process
1946+ fd = os .dup (1 )
1947+ self .addCleanup (os .close , fd )
1948+
1949+ p = subprocess .Popen ([sys .executable , fd_status ],
1950+ stdout = subprocess .PIPE , close_fds = True ,
1951+ preexec_fn = lambda : os .dup2 (1 , fd ))
1952+ output , ignored = p .communicate ()
1953+
1954+ remaining_fds = set (map (int , output .split (b',' )))
1955+
1956+ self .assertNotIn (fd , remaining_fds )
1957+
19411958
19421959@unittest .skipUnless (mswindows , "Windows specific tests" )
19431960class Win32ProcessTestCase (BaseTestCase ):
Original file line number Diff line number Diff line change @@ -412,17 +412,6 @@ child_exec(char *const exec_array[],
412412 POSIX_CALL (close (errwrite ));
413413 }
414414
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-
426415 if (cwd )
427416 POSIX_CALL (chdir (cwd ));
428417
@@ -451,6 +440,18 @@ child_exec(char *const exec_array[],
451440 /* Py_DECREF(result); - We're about to exec so why bother? */
452441 }
453442
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
451+ /* TODO HP-UX could use pstat_getproc() if anyone cares about it. */
452+ _close_open_fd_range (3 , local_max_fd , py_fds_to_keep );
453+ }
454+
454455 /* This loop matches the Lib/os.py _execvpe()'s PATH search when */
455456 /* given the executable_list generated by Lib/subprocess.py. */
456457 saved_errno = 0 ;
You can’t perform that action at this time.
0 commit comments