@@ -1306,6 +1306,26 @@ def _close_pipe_fds(self,
1306
1306
# Prevent a double close of these handles/fds from __init__ on error.
1307
1307
self ._closed_child_pipe_fds = True
1308
1308
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
+
1309
1329
if _mswindows :
1310
1330
#
1311
1331
# Windows methods
@@ -1321,22 +1341,18 @@ def _get_handles(self, stdin, stdout, stderr):
1321
1341
c2pread , c2pwrite = - 1 , - 1
1322
1342
errread , errwrite = - 1 , - 1
1323
1343
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 :
1329
1345
if stdin is None :
1330
1346
p2cread = _winapi .GetStdHandle (_winapi .STD_INPUT_HANDLE )
1331
1347
if p2cread is None :
1332
- stdin_needsclose = True
1333
1348
p2cread , _ = _winapi .CreatePipe (None , 0 )
1334
1349
p2cread = Handle (p2cread )
1335
1350
_winapi .CloseHandle (_ )
1351
+ err_close_fds .append (p2cread )
1336
1352
elif stdin == PIPE :
1337
- stdin_needsclose = True
1338
1353
p2cread , p2cwrite = _winapi .CreatePipe (None , 0 )
1339
1354
p2cread , p2cwrite = Handle (p2cread ), Handle (p2cwrite )
1355
+ err_close_fds .extend ((p2cread , p2cwrite ))
1340
1356
elif stdin == DEVNULL :
1341
1357
p2cread = msvcrt .get_osfhandle (self ._get_devnull ())
1342
1358
elif isinstance (stdin , int ):
@@ -1349,14 +1365,14 @@ def _get_handles(self, stdin, stdout, stderr):
1349
1365
if stdout is None :
1350
1366
c2pwrite = _winapi .GetStdHandle (_winapi .STD_OUTPUT_HANDLE )
1351
1367
if c2pwrite is None :
1352
- stdout_needsclose = True
1353
1368
_ , c2pwrite = _winapi .CreatePipe (None , 0 )
1354
1369
c2pwrite = Handle (c2pwrite )
1355
1370
_winapi .CloseHandle (_ )
1371
+ err_close_fds .append (c2pwrite )
1356
1372
elif stdout == PIPE :
1357
- stdout_needsclose = True
1358
1373
c2pread , c2pwrite = _winapi .CreatePipe (None , 0 )
1359
1374
c2pread , c2pwrite = Handle (c2pread ), Handle (c2pwrite )
1375
+ err_close_fds .extend ((c2pread , c2pwrite ))
1360
1376
elif stdout == DEVNULL :
1361
1377
c2pwrite = msvcrt .get_osfhandle (self ._get_devnull ())
1362
1378
elif isinstance (stdout , int ):
@@ -1369,14 +1385,14 @@ def _get_handles(self, stdin, stdout, stderr):
1369
1385
if stderr is None :
1370
1386
errwrite = _winapi .GetStdHandle (_winapi .STD_ERROR_HANDLE )
1371
1387
if errwrite is None :
1372
- stderr_needsclose = True
1373
1388
_ , errwrite = _winapi .CreatePipe (None , 0 )
1374
1389
errwrite = Handle (errwrite )
1375
1390
_winapi .CloseHandle (_ )
1391
+ err_close_fds .append (errwrite )
1376
1392
elif stderr == PIPE :
1377
- stderr_needsclose = True
1378
1393
errread , errwrite = _winapi .CreatePipe (None , 0 )
1379
1394
errread , errwrite = Handle (errread ), Handle (errwrite )
1395
+ err_close_fds .extend ((errread , errwrite ))
1380
1396
elif stderr == STDOUT :
1381
1397
errwrite = c2pwrite
1382
1398
elif stderr == DEVNULL :
@@ -1388,27 +1404,6 @@ def _get_handles(self, stdin, stdout, stderr):
1388
1404
errwrite = msvcrt .get_osfhandle (stderr .fileno ())
1389
1405
errwrite = self ._make_inheritable (errwrite )
1390
1406
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
-
1412
1407
return (p2cread , p2cwrite ,
1413
1408
c2pread , c2pwrite ,
1414
1409
errread , errwrite )
@@ -1678,13 +1673,14 @@ def _get_handles(self, stdin, stdout, stderr):
1678
1673
c2pread , c2pwrite = - 1 , - 1
1679
1674
errread , errwrite = - 1 , - 1
1680
1675
1681
- try :
1676
+ with self . _on_error_fd_closer () as err_close_fds :
1682
1677
if stdin is None :
1683
1678
pass
1684
1679
elif stdin == PIPE :
1685
1680
p2cread , p2cwrite = os .pipe ()
1686
1681
if self .pipesize > 0 and hasattr (fcntl , "F_SETPIPE_SZ" ):
1687
1682
fcntl .fcntl (p2cwrite , fcntl .F_SETPIPE_SZ , self .pipesize )
1683
+ err_close_fds .extend ((p2cread , p2cwrite ))
1688
1684
elif stdin == DEVNULL :
1689
1685
p2cread = self ._get_devnull ()
1690
1686
elif isinstance (stdin , int ):
@@ -1699,6 +1695,7 @@ def _get_handles(self, stdin, stdout, stderr):
1699
1695
c2pread , c2pwrite = os .pipe ()
1700
1696
if self .pipesize > 0 and hasattr (fcntl , "F_SETPIPE_SZ" ):
1701
1697
fcntl .fcntl (c2pwrite , fcntl .F_SETPIPE_SZ , self .pipesize )
1698
+ err_close_fds .extend ((c2pread , c2pwrite ))
1702
1699
elif stdout == DEVNULL :
1703
1700
c2pwrite = self ._get_devnull ()
1704
1701
elif isinstance (stdout , int ):
@@ -1713,6 +1710,7 @@ def _get_handles(self, stdin, stdout, stderr):
1713
1710
errread , errwrite = os .pipe ()
1714
1711
if self .pipesize > 0 and hasattr (fcntl , "F_SETPIPE_SZ" ):
1715
1712
fcntl .fcntl (errwrite , fcntl .F_SETPIPE_SZ , self .pipesize )
1713
+ err_close_fds .extend ((errread , errwrite ))
1716
1714
elif stderr == STDOUT :
1717
1715
if c2pwrite != - 1 :
1718
1716
errwrite = c2pwrite
@@ -1726,22 +1724,6 @@ def _get_handles(self, stdin, stdout, stderr):
1726
1724
# Assuming file-like object
1727
1725
errwrite = stderr .fileno ()
1728
1726
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
-
1745
1727
return (p2cread , p2cwrite ,
1746
1728
c2pread , c2pwrite ,
1747
1729
errread , errwrite )
0 commit comments