@@ -870,37 +870,6 @@ def __init__(self, args, bufsize=-1, executable=None,
870870 'and universal_newlines are supplied but '
871871 'different. Pass one or the other.' )
872872
873- # Input and output objects. The general principle is like
874- # this:
875- #
876- # Parent Child
877- # ------ -----
878- # p2cwrite ---stdin---> p2cread
879- # c2pread <--stdout--- c2pwrite
880- # errread <--stderr--- errwrite
881- #
882- # On POSIX, the child objects are file descriptors. On
883- # Windows, these are Windows file handles. The parent objects
884- # are file descriptors on both platforms. The parent objects
885- # are -1 when not using PIPEs. The child objects are -1
886- # when not redirecting.
887-
888- (p2cread , p2cwrite ,
889- c2pread , c2pwrite ,
890- errread , errwrite ) = self ._get_handles (stdin , stdout , stderr )
891-
892- # We wrap OS handles *before* launching the child, otherwise a
893- # quickly terminating child could make our fds unwrappable
894- # (see #8458).
895-
896- if _mswindows :
897- if p2cwrite != - 1 :
898- p2cwrite = msvcrt .open_osfhandle (p2cwrite .Detach (), 0 )
899- if c2pread != - 1 :
900- c2pread = msvcrt .open_osfhandle (c2pread .Detach (), 0 )
901- if errread != - 1 :
902- errread = msvcrt .open_osfhandle (errread .Detach (), 0 )
903-
904873 self .text_mode = encoding or errors or text or universal_newlines
905874 if self .text_mode and encoding is None :
906875 self .encoding = encoding = _text_encoding ()
@@ -1001,6 +970,39 @@ def __init__(self, args, bufsize=-1, executable=None,
1001970 if uid < 0 :
1002971 raise ValueError (f"User ID cannot be negative, got { uid } " )
1003972
973+ # Input and output objects. The general principle is like
974+ # this:
975+ #
976+ # Parent Child
977+ # ------ -----
978+ # p2cwrite ---stdin---> p2cread
979+ # c2pread <--stdout--- c2pwrite
980+ # errread <--stderr--- errwrite
981+ #
982+ # On POSIX, the child objects are file descriptors. On
983+ # Windows, these are Windows file handles. The parent objects
984+ # are file descriptors on both platforms. The parent objects
985+ # are -1 when not using PIPEs. The child objects are -1
986+ # when not redirecting.
987+
988+ (p2cread , p2cwrite ,
989+ c2pread , c2pwrite ,
990+ errread , errwrite ) = self ._get_handles (stdin , stdout , stderr )
991+
992+ # From here on, raising exceptions may cause file descriptor leakage
993+
994+ # We wrap OS handles *before* launching the child, otherwise a
995+ # quickly terminating child could make our fds unwrappable
996+ # (see #8458).
997+
998+ if _mswindows :
999+ if p2cwrite != - 1 :
1000+ p2cwrite = msvcrt .open_osfhandle (p2cwrite .Detach (), 0 )
1001+ if c2pread != - 1 :
1002+ c2pread = msvcrt .open_osfhandle (c2pread .Detach (), 0 )
1003+ if errread != - 1 :
1004+ errread = msvcrt .open_osfhandle (errread .Detach (), 0 )
1005+
10041006 try :
10051007 if p2cwrite != - 1 :
10061008 self .stdin = io .open (p2cwrite , 'wb' , bufsize )
@@ -1319,61 +1321,93 @@ def _get_handles(self, stdin, stdout, stderr):
13191321 c2pread , c2pwrite = - 1 , - 1
13201322 errread , errwrite = - 1 , - 1
13211323
1322- if stdin is None :
1323- p2cread = _winapi .GetStdHandle (_winapi .STD_INPUT_HANDLE )
1324- if p2cread is None :
1325- p2cread , _ = _winapi .CreatePipe (None , 0 )
1326- p2cread = Handle (p2cread )
1327- _winapi .CloseHandle (_ )
1328- elif stdin == PIPE :
1329- p2cread , p2cwrite = _winapi .CreatePipe (None , 0 )
1330- p2cread , p2cwrite = Handle (p2cread ), Handle (p2cwrite )
1331- elif stdin == DEVNULL :
1332- p2cread = msvcrt .get_osfhandle (self ._get_devnull ())
1333- elif isinstance (stdin , int ):
1334- p2cread = msvcrt .get_osfhandle (stdin )
1335- else :
1336- # Assuming file-like object
1337- p2cread = msvcrt .get_osfhandle (stdin .fileno ())
1338- p2cread = self ._make_inheritable (p2cread )
1339-
1340- if stdout is None :
1341- c2pwrite = _winapi .GetStdHandle (_winapi .STD_OUTPUT_HANDLE )
1342- if c2pwrite is None :
1343- _ , c2pwrite = _winapi .CreatePipe (None , 0 )
1344- c2pwrite = Handle (c2pwrite )
1345- _winapi .CloseHandle (_ )
1346- elif stdout == PIPE :
1347- c2pread , c2pwrite = _winapi .CreatePipe (None , 0 )
1348- c2pread , c2pwrite = Handle (c2pread ), Handle (c2pwrite )
1349- elif stdout == DEVNULL :
1350- c2pwrite = msvcrt .get_osfhandle (self ._get_devnull ())
1351- elif isinstance (stdout , int ):
1352- c2pwrite = msvcrt .get_osfhandle (stdout )
1353- else :
1354- # Assuming file-like object
1355- c2pwrite = msvcrt .get_osfhandle (stdout .fileno ())
1356- c2pwrite = self ._make_inheritable (c2pwrite )
1357-
1358- if stderr is None :
1359- errwrite = _winapi .GetStdHandle (_winapi .STD_ERROR_HANDLE )
1360- if errwrite is None :
1361- _ , errwrite = _winapi .CreatePipe (None , 0 )
1362- errwrite = Handle (errwrite )
1363- _winapi .CloseHandle (_ )
1364- elif stderr == PIPE :
1365- errread , errwrite = _winapi .CreatePipe (None , 0 )
1366- errread , errwrite = Handle (errread ), Handle (errwrite )
1367- elif stderr == STDOUT :
1368- errwrite = c2pwrite
1369- elif stderr == DEVNULL :
1370- errwrite = msvcrt .get_osfhandle (self ._get_devnull ())
1371- elif isinstance (stderr , int ):
1372- errwrite = msvcrt .get_osfhandle (stderr )
1373- else :
1374- # Assuming file-like object
1375- errwrite = msvcrt .get_osfhandle (stderr .fileno ())
1376- errwrite = self ._make_inheritable (errwrite )
1324+ stdin_needsclose = False
1325+ stdout_needsclose = False
1326+ stderr_needsclose = False
1327+
1328+ try :
1329+ if stdin is None :
1330+ p2cread = _winapi .GetStdHandle (_winapi .STD_INPUT_HANDLE )
1331+ if p2cread is None :
1332+ stdin_needsclose = True
1333+ p2cread , _ = _winapi .CreatePipe (None , 0 )
1334+ p2cread = Handle (p2cread )
1335+ _winapi .CloseHandle (_ )
1336+ elif stdin == PIPE :
1337+ stdin_needsclose = True
1338+ p2cread , p2cwrite = _winapi .CreatePipe (None , 0 )
1339+ p2cread , p2cwrite = Handle (p2cread ), Handle (p2cwrite )
1340+ elif stdin == DEVNULL :
1341+ p2cread = msvcrt .get_osfhandle (self ._get_devnull ())
1342+ elif isinstance (stdin , int ):
1343+ p2cread = msvcrt .get_osfhandle (stdin )
1344+ else :
1345+ # Assuming file-like object
1346+ p2cread = msvcrt .get_osfhandle (stdin .fileno ())
1347+ p2cread = self ._make_inheritable (p2cread )
1348+
1349+ if stdout is None :
1350+ c2pwrite = _winapi .GetStdHandle (_winapi .STD_OUTPUT_HANDLE )
1351+ if c2pwrite is None :
1352+ stdout_needsclose = True
1353+ _ , c2pwrite = _winapi .CreatePipe (None , 0 )
1354+ c2pwrite = Handle (c2pwrite )
1355+ _winapi .CloseHandle (_ )
1356+ elif stdout == PIPE :
1357+ stdout_needsclose = True
1358+ c2pread , c2pwrite = _winapi .CreatePipe (None , 0 )
1359+ c2pread , c2pwrite = Handle (c2pread ), Handle (c2pwrite )
1360+ elif stdout == DEVNULL :
1361+ c2pwrite = msvcrt .get_osfhandle (self ._get_devnull ())
1362+ elif isinstance (stdout , int ):
1363+ c2pwrite = msvcrt .get_osfhandle (stdout )
1364+ else :
1365+ # Assuming file-like object
1366+ c2pwrite = msvcrt .get_osfhandle (stdout .fileno ())
1367+ c2pwrite = self ._make_inheritable (c2pwrite )
1368+
1369+ if stderr is None :
1370+ errwrite = _winapi .GetStdHandle (_winapi .STD_ERROR_HANDLE )
1371+ if errwrite is None :
1372+ stderr_needsclose = True
1373+ _ , errwrite = _winapi .CreatePipe (None , 0 )
1374+ errwrite = Handle (errwrite )
1375+ _winapi .CloseHandle (_ )
1376+ elif stderr == PIPE :
1377+ stderr_needsclose = True
1378+ errread , errwrite = _winapi .CreatePipe (None , 0 )
1379+ errread , errwrite = Handle (errread ), Handle (errwrite )
1380+ elif stderr == STDOUT :
1381+ errwrite = c2pwrite
1382+ elif stderr == DEVNULL :
1383+ errwrite = msvcrt .get_osfhandle (self ._get_devnull ())
1384+ elif isinstance (stderr , int ):
1385+ errwrite = msvcrt .get_osfhandle (stderr )
1386+ else :
1387+ # Assuming file-like object
1388+ errwrite = msvcrt .get_osfhandle (stderr .fileno ())
1389+ errwrite = self ._make_inheritable (errwrite )
1390+
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
13771411
13781412 return (p2cread , p2cwrite ,
13791413 c2pread , c2pwrite ,
@@ -1644,52 +1678,69 @@ def _get_handles(self, stdin, stdout, stderr):
16441678 c2pread , c2pwrite = - 1 , - 1
16451679 errread , errwrite = - 1 , - 1
16461680
1647- if stdin is None :
1648- pass
1649- elif stdin == PIPE :
1650- p2cread , p2cwrite = os .pipe ()
1651- if self .pipesize > 0 and hasattr (fcntl , "F_SETPIPE_SZ" ):
1652- fcntl .fcntl (p2cwrite , fcntl .F_SETPIPE_SZ , self .pipesize )
1653- elif stdin == DEVNULL :
1654- p2cread = self ._get_devnull ()
1655- elif isinstance (stdin , int ):
1656- p2cread = stdin
1657- else :
1658- # Assuming file-like object
1659- p2cread = stdin .fileno ()
1681+ try :
1682+ if stdin is None :
1683+ pass
1684+ elif stdin == PIPE :
1685+ p2cread , p2cwrite = os .pipe ()
1686+ if self .pipesize > 0 and hasattr (fcntl , "F_SETPIPE_SZ" ):
1687+ fcntl .fcntl (p2cwrite , fcntl .F_SETPIPE_SZ , self .pipesize )
1688+ elif stdin == DEVNULL :
1689+ p2cread = self ._get_devnull ()
1690+ elif isinstance (stdin , int ):
1691+ p2cread = stdin
1692+ else :
1693+ # Assuming file-like object
1694+ p2cread = stdin .fileno ()
16601695
1661- if stdout is None :
1662- pass
1663- elif stdout == PIPE :
1664- c2pread , c2pwrite = os .pipe ()
1665- if self .pipesize > 0 and hasattr (fcntl , "F_SETPIPE_SZ" ):
1666- fcntl .fcntl (c2pwrite , fcntl .F_SETPIPE_SZ , self .pipesize )
1667- elif stdout == DEVNULL :
1668- c2pwrite = self ._get_devnull ()
1669- elif isinstance (stdout , int ):
1670- c2pwrite = stdout
1671- else :
1672- # Assuming file-like object
1673- c2pwrite = stdout .fileno ()
1696+ if stdout is None :
1697+ pass
1698+ elif stdout == PIPE :
1699+ c2pread , c2pwrite = os .pipe ()
1700+ if self .pipesize > 0 and hasattr (fcntl , "F_SETPIPE_SZ" ):
1701+ fcntl .fcntl (c2pwrite , fcntl .F_SETPIPE_SZ , self .pipesize )
1702+ elif stdout == DEVNULL :
1703+ c2pwrite = self ._get_devnull ()
1704+ elif isinstance (stdout , int ):
1705+ c2pwrite = stdout
1706+ else :
1707+ # Assuming file-like object
1708+ c2pwrite = stdout .fileno ()
16741709
1675- if stderr is None :
1676- pass
1677- elif stderr == PIPE :
1678- errread , errwrite = os .pipe ()
1679- if self .pipesize > 0 and hasattr (fcntl , "F_SETPIPE_SZ" ):
1680- fcntl .fcntl (errwrite , fcntl .F_SETPIPE_SZ , self .pipesize )
1681- elif stderr == STDOUT :
1682- if c2pwrite != - 1 :
1683- errwrite = c2pwrite
1684- else : # child's stdout is not set, use parent's stdout
1685- errwrite = sys .__stdout__ .fileno ()
1686- elif stderr == DEVNULL :
1687- errwrite = self ._get_devnull ()
1688- elif isinstance (stderr , int ):
1689- errwrite = stderr
1690- else :
1691- # Assuming file-like object
1692- errwrite = stderr .fileno ()
1710+ if stderr is None :
1711+ pass
1712+ elif stderr == PIPE :
1713+ errread , errwrite = os .pipe ()
1714+ if self .pipesize > 0 and hasattr (fcntl , "F_SETPIPE_SZ" ):
1715+ fcntl .fcntl (errwrite , fcntl .F_SETPIPE_SZ , self .pipesize )
1716+ elif stderr == STDOUT :
1717+ if c2pwrite != - 1 :
1718+ errwrite = c2pwrite
1719+ else : # child's stdout is not set, use parent's stdout
1720+ errwrite = sys .__stdout__ .fileno ()
1721+ elif stderr == DEVNULL :
1722+ errwrite = self ._get_devnull ()
1723+ elif isinstance (stderr , int ):
1724+ errwrite = stderr
1725+ else :
1726+ # Assuming file-like object
1727+ errwrite = stderr .fileno ()
1728+
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
16931744
16941745 return (p2cread , p2cwrite ,
16951746 c2pread , c2pwrite ,
0 commit comments