@@ -1306,6 +1306,26 @@ def _close_pipe_fds(self,
13061306 # Prevent a double close of these handles/fds from __init__ on error.
13071307 self ._closed_child_pipe_fds = True
13081308
1309+ @contextlib .contextmanager
1310+ def _on_error_fd_closer (self ):
1311+ """Helper to ensure file descriptors opened in _get_handles are closed"""
1312+ to_close = []
1313+ try :
1314+ yield to_close
1315+ except :
1316+ if hasattr (self , '_devnull' ):
1317+ to_close .append (self ._devnull )
1318+ del self ._devnull
1319+ for fd in to_close :
1320+ try :
1321+ if _mswindows and isinstance (fd , Handle ):
1322+ fd .Close ()
1323+ else :
1324+ os .close (fd )
1325+ except OSError :
1326+ pass
1327+ raise
1328+
13091329 if _mswindows :
13101330 #
13111331 # Windows methods
@@ -1321,22 +1341,18 @@ def _get_handles(self, stdin, stdout, stderr):
13211341 c2pread , c2pwrite = - 1 , - 1
13221342 errread , errwrite = - 1 , - 1
13231343
1324- stdin_needsclose = False
1325- stdout_needsclose = False
1326- stderr_needsclose = False
1327-
1328- try :
1344+ with self ._on_error_fd_closer () as err_close_fds :
13291345 if stdin is None :
13301346 p2cread = _winapi .GetStdHandle (_winapi .STD_INPUT_HANDLE )
13311347 if p2cread is None :
1332- stdin_needsclose = True
13331348 p2cread , _ = _winapi .CreatePipe (None , 0 )
13341349 p2cread = Handle (p2cread )
13351350 _winapi .CloseHandle (_ )
1351+ err_close_fds .append (p2cread )
13361352 elif stdin == PIPE :
1337- stdin_needsclose = True
13381353 p2cread , p2cwrite = _winapi .CreatePipe (None , 0 )
13391354 p2cread , p2cwrite = Handle (p2cread ), Handle (p2cwrite )
1355+ err_close_fds .extend ((p2cread , p2cwrite ))
13401356 elif stdin == DEVNULL :
13411357 p2cread = msvcrt .get_osfhandle (self ._get_devnull ())
13421358 elif isinstance (stdin , int ):
@@ -1349,14 +1365,14 @@ def _get_handles(self, stdin, stdout, stderr):
13491365 if stdout is None :
13501366 c2pwrite = _winapi .GetStdHandle (_winapi .STD_OUTPUT_HANDLE )
13511367 if c2pwrite is None :
1352- stdout_needsclose = True
13531368 _ , c2pwrite = _winapi .CreatePipe (None , 0 )
13541369 c2pwrite = Handle (c2pwrite )
13551370 _winapi .CloseHandle (_ )
1371+ err_close_fds .append (c2pwrite )
13561372 elif stdout == PIPE :
1357- stdout_needsclose = True
13581373 c2pread , c2pwrite = _winapi .CreatePipe (None , 0 )
13591374 c2pread , c2pwrite = Handle (c2pread ), Handle (c2pwrite )
1375+ err_close_fds .extend ((c2pread , c2pwrite ))
13601376 elif stdout == DEVNULL :
13611377 c2pwrite = msvcrt .get_osfhandle (self ._get_devnull ())
13621378 elif isinstance (stdout , int ):
@@ -1369,14 +1385,14 @@ def _get_handles(self, stdin, stdout, stderr):
13691385 if stderr is None :
13701386 errwrite = _winapi .GetStdHandle (_winapi .STD_ERROR_HANDLE )
13711387 if errwrite is None :
1372- stderr_needsclose = True
13731388 _ , errwrite = _winapi .CreatePipe (None , 0 )
13741389 errwrite = Handle (errwrite )
13751390 _winapi .CloseHandle (_ )
1391+ err_close_fds .append (errwrite )
13761392 elif stderr == PIPE :
1377- stderr_needsclose = True
13781393 errread , errwrite = _winapi .CreatePipe (None , 0 )
13791394 errread , errwrite = Handle (errread ), Handle (errwrite )
1395+ err_close_fds .extend ((errread , errwrite ))
13801396 elif stderr == STDOUT :
13811397 errwrite = c2pwrite
13821398 elif stderr == DEVNULL :
@@ -1388,27 +1404,6 @@ def _get_handles(self, stdin, stdout, stderr):
13881404 errwrite = msvcrt .get_osfhandle (stderr .fileno ())
13891405 errwrite = self ._make_inheritable (errwrite )
13901406
1391- except BaseException :
1392- to_close = []
1393- if stdin_needsclose and p2cwrite != - 1 :
1394- to_close .append (p2cread )
1395- to_close .append (p2cwrite )
1396- if stdout_needsclose and p2cwrite != - 1 :
1397- to_close .append (c2pread )
1398- to_close .append (c2pwrite )
1399- if stderr_needsclose and errwrite != - 1 :
1400- to_close .append (errread )
1401- to_close .append (errwrite )
1402- for file in to_close :
1403- if isinstance (file , Handle ):
1404- file .Close ()
1405- else :
1406- os .close (file )
1407- if hasattr (self , "_devnull" ):
1408- os .close (self ._devnull )
1409- del self ._devnull
1410- raise
1411-
14121407 return (p2cread , p2cwrite ,
14131408 c2pread , c2pwrite ,
14141409 errread , errwrite )
@@ -1678,13 +1673,14 @@ def _get_handles(self, stdin, stdout, stderr):
16781673 c2pread , c2pwrite = - 1 , - 1
16791674 errread , errwrite = - 1 , - 1
16801675
1681- try :
1676+ with self . _on_error_fd_closer () as err_close_fds :
16821677 if stdin is None :
16831678 pass
16841679 elif stdin == PIPE :
16851680 p2cread , p2cwrite = os .pipe ()
16861681 if self .pipesize > 0 and hasattr (fcntl , "F_SETPIPE_SZ" ):
16871682 fcntl .fcntl (p2cwrite , fcntl .F_SETPIPE_SZ , self .pipesize )
1683+ err_close_fds .extend ((p2cread , p2cwrite ))
16881684 elif stdin == DEVNULL :
16891685 p2cread = self ._get_devnull ()
16901686 elif isinstance (stdin , int ):
@@ -1699,6 +1695,7 @@ def _get_handles(self, stdin, stdout, stderr):
16991695 c2pread , c2pwrite = os .pipe ()
17001696 if self .pipesize > 0 and hasattr (fcntl , "F_SETPIPE_SZ" ):
17011697 fcntl .fcntl (c2pwrite , fcntl .F_SETPIPE_SZ , self .pipesize )
1698+ err_close_fds .extend ((c2pread , c2pwrite ))
17021699 elif stdout == DEVNULL :
17031700 c2pwrite = self ._get_devnull ()
17041701 elif isinstance (stdout , int ):
@@ -1713,6 +1710,7 @@ def _get_handles(self, stdin, stdout, stderr):
17131710 errread , errwrite = os .pipe ()
17141711 if self .pipesize > 0 and hasattr (fcntl , "F_SETPIPE_SZ" ):
17151712 fcntl .fcntl (errwrite , fcntl .F_SETPIPE_SZ , self .pipesize )
1713+ err_close_fds .extend ((errread , errwrite ))
17161714 elif stderr == STDOUT :
17171715 if c2pwrite != - 1 :
17181716 errwrite = c2pwrite
@@ -1726,22 +1724,6 @@ def _get_handles(self, stdin, stdout, stderr):
17261724 # Assuming file-like object
17271725 errwrite = stderr .fileno ()
17281726
1729- except BaseException :
1730- # Close the file descriptors we opened to avoid leakage
1731- if stdin == PIPE and p2cwrite != - 1 :
1732- os .close (p2cread )
1733- os .close (p2cwrite )
1734- if stdout == PIPE and c2pwrite != - 1 :
1735- os .close (c2pread )
1736- os .close (c2pwrite )
1737- if stderr == PIPE and errwrite != - 1 :
1738- os .close (errread )
1739- os .close (errwrite )
1740- if hasattr (self , "_devnull" ):
1741- os .close (self ._devnull )
1742- del self ._devnull
1743- raise
1744-
17451727 return (p2cread , p2cwrite ,
17461728 c2pread , c2pwrite ,
17471729 errread , errwrite )
0 commit comments