@@ -1308,6 +1308,26 @@ def _close_pipe_fds(self,
1308
1308
# Prevent a double close of these handles/fds from __init__ on error.
1309
1309
self ._closed_child_pipe_fds = True
1310
1310
1311
+ @contextlib .contextmanager
1312
+ def _on_error_fd_closer (self ):
1313
+ """Helper to ensure file descriptors opened in _get_handles are closed"""
1314
+ to_close = []
1315
+ try :
1316
+ yield to_close
1317
+ except :
1318
+ if hasattr (self , '_devnull' ):
1319
+ to_close .append (self ._devnull )
1320
+ del self ._devnull
1321
+ for fd in to_close :
1322
+ try :
1323
+ if _mswindows and isinstance (fd , Handle ):
1324
+ fd .Close ()
1325
+ else :
1326
+ os .close (fd )
1327
+ except OSError :
1328
+ pass
1329
+ raise
1330
+
1311
1331
if _mswindows :
1312
1332
#
1313
1333
# Windows methods
@@ -1323,22 +1343,18 @@ def _get_handles(self, stdin, stdout, stderr):
1323
1343
c2pread , c2pwrite = - 1 , - 1
1324
1344
errread , errwrite = - 1 , - 1
1325
1345
1326
- stdin_needsclose = False
1327
- stdout_needsclose = False
1328
- stderr_needsclose = False
1329
-
1330
- try :
1346
+ with self ._on_error_fd_closer () as err_close_fds :
1331
1347
if stdin is None :
1332
1348
p2cread = _winapi .GetStdHandle (_winapi .STD_INPUT_HANDLE )
1333
1349
if p2cread is None :
1334
- stdin_needsclose = True
1335
1350
p2cread , _ = _winapi .CreatePipe (None , 0 )
1336
1351
p2cread = Handle (p2cread )
1337
1352
_winapi .CloseHandle (_ )
1353
+ err_close_fds .append (p2cread )
1338
1354
elif stdin == PIPE :
1339
- stdin_needsclose = True
1340
1355
p2cread , p2cwrite = _winapi .CreatePipe (None , 0 )
1341
1356
p2cread , p2cwrite = Handle (p2cread ), Handle (p2cwrite )
1357
+ err_close_fds .extend ((p2cread , p2cwrite ))
1342
1358
elif stdin == DEVNULL :
1343
1359
p2cread = msvcrt .get_osfhandle (self ._get_devnull ())
1344
1360
elif isinstance (stdin , int ):
@@ -1351,14 +1367,14 @@ def _get_handles(self, stdin, stdout, stderr):
1351
1367
if stdout is None :
1352
1368
c2pwrite = _winapi .GetStdHandle (_winapi .STD_OUTPUT_HANDLE )
1353
1369
if c2pwrite is None :
1354
- stdout_needsclose = True
1355
1370
_ , c2pwrite = _winapi .CreatePipe (None , 0 )
1356
1371
c2pwrite = Handle (c2pwrite )
1357
1372
_winapi .CloseHandle (_ )
1373
+ err_close_fds .append (c2pwrite )
1358
1374
elif stdout == PIPE :
1359
- stdout_needsclose = True
1360
1375
c2pread , c2pwrite = _winapi .CreatePipe (None , 0 )
1361
1376
c2pread , c2pwrite = Handle (c2pread ), Handle (c2pwrite )
1377
+ err_close_fds .extend ((c2pread , c2pwrite ))
1362
1378
elif stdout == DEVNULL :
1363
1379
c2pwrite = msvcrt .get_osfhandle (self ._get_devnull ())
1364
1380
elif isinstance (stdout , int ):
@@ -1371,14 +1387,14 @@ def _get_handles(self, stdin, stdout, stderr):
1371
1387
if stderr is None :
1372
1388
errwrite = _winapi .GetStdHandle (_winapi .STD_ERROR_HANDLE )
1373
1389
if errwrite is None :
1374
- stderr_needsclose = True
1375
1390
_ , errwrite = _winapi .CreatePipe (None , 0 )
1376
1391
errwrite = Handle (errwrite )
1377
1392
_winapi .CloseHandle (_ )
1393
+ err_close_fds .append (errwrite )
1378
1394
elif stderr == PIPE :
1379
- stderr_needsclose = True
1380
1395
errread , errwrite = _winapi .CreatePipe (None , 0 )
1381
1396
errread , errwrite = Handle (errread ), Handle (errwrite )
1397
+ err_close_fds .extend ((errread , errwrite ))
1382
1398
elif stderr == STDOUT :
1383
1399
errwrite = c2pwrite
1384
1400
elif stderr == DEVNULL :
@@ -1390,27 +1406,6 @@ def _get_handles(self, stdin, stdout, stderr):
1390
1406
errwrite = msvcrt .get_osfhandle (stderr .fileno ())
1391
1407
errwrite = self ._make_inheritable (errwrite )
1392
1408
1393
- except BaseException :
1394
- to_close = []
1395
- if stdin_needsclose and p2cwrite != - 1 :
1396
- to_close .append (p2cread )
1397
- to_close .append (p2cwrite )
1398
- if stdout_needsclose and p2cwrite != - 1 :
1399
- to_close .append (c2pread )
1400
- to_close .append (c2pwrite )
1401
- if stderr_needsclose and errwrite != - 1 :
1402
- to_close .append (errread )
1403
- to_close .append (errwrite )
1404
- for file in to_close :
1405
- if isinstance (file , Handle ):
1406
- file .Close ()
1407
- else :
1408
- os .close (file )
1409
- if hasattr (self , "_devnull" ):
1410
- os .close (self ._devnull )
1411
- del self ._devnull
1412
- raise
1413
-
1414
1409
return (p2cread , p2cwrite ,
1415
1410
c2pread , c2pwrite ,
1416
1411
errread , errwrite )
@@ -1696,13 +1691,14 @@ def _get_handles(self, stdin, stdout, stderr):
1696
1691
c2pread , c2pwrite = - 1 , - 1
1697
1692
errread , errwrite = - 1 , - 1
1698
1693
1699
- try :
1694
+ with self . _on_error_fd_closer () as err_close_fds :
1700
1695
if stdin is None :
1701
1696
pass
1702
1697
elif stdin == PIPE :
1703
1698
p2cread , p2cwrite = os .pipe ()
1704
1699
if self .pipesize > 0 and hasattr (fcntl , "F_SETPIPE_SZ" ):
1705
1700
fcntl .fcntl (p2cwrite , fcntl .F_SETPIPE_SZ , self .pipesize )
1701
+ err_close_fds .extend ((p2cread , p2cwrite ))
1706
1702
elif stdin == DEVNULL :
1707
1703
p2cread = self ._get_devnull ()
1708
1704
elif isinstance (stdin , int ):
@@ -1717,6 +1713,7 @@ def _get_handles(self, stdin, stdout, stderr):
1717
1713
c2pread , c2pwrite = os .pipe ()
1718
1714
if self .pipesize > 0 and hasattr (fcntl , "F_SETPIPE_SZ" ):
1719
1715
fcntl .fcntl (c2pwrite , fcntl .F_SETPIPE_SZ , self .pipesize )
1716
+ err_close_fds .extend ((c2pread , c2pwrite ))
1720
1717
elif stdout == DEVNULL :
1721
1718
c2pwrite = self ._get_devnull ()
1722
1719
elif isinstance (stdout , int ):
@@ -1731,6 +1728,7 @@ def _get_handles(self, stdin, stdout, stderr):
1731
1728
errread , errwrite = os .pipe ()
1732
1729
if self .pipesize > 0 and hasattr (fcntl , "F_SETPIPE_SZ" ):
1733
1730
fcntl .fcntl (errwrite , fcntl .F_SETPIPE_SZ , self .pipesize )
1731
+ err_close_fds .extend ((errread , errwrite ))
1734
1732
elif stderr == STDOUT :
1735
1733
if c2pwrite != - 1 :
1736
1734
errwrite = c2pwrite
@@ -1744,22 +1742,6 @@ def _get_handles(self, stdin, stdout, stderr):
1744
1742
# Assuming file-like object
1745
1743
errwrite = stderr .fileno ()
1746
1744
1747
- except BaseException :
1748
- # Close the file descriptors we opened to avoid leakage
1749
- if stdin == PIPE and p2cwrite != - 1 :
1750
- os .close (p2cread )
1751
- os .close (p2cwrite )
1752
- if stdout == PIPE and c2pwrite != - 1 :
1753
- os .close (c2pread )
1754
- os .close (c2pwrite )
1755
- if stderr == PIPE and errwrite != - 1 :
1756
- os .close (errread )
1757
- os .close (errwrite )
1758
- if hasattr (self , "_devnull" ):
1759
- os .close (self ._devnull )
1760
- del self ._devnull
1761
- raise
1762
-
1763
1745
return (p2cread , p2cwrite ,
1764
1746
c2pread , c2pwrite ,
1765
1747
errread , errwrite )
0 commit comments