Skip to content

Commit d602141

Browse files
cptpcrdgpshead
andcommitted
Refactor to use context manager
Simplifies the logic and should help avoid mistakes in the future. Co-authored-by: Gregory P. Smith <greg@krypto.org>
1 parent e299737 commit d602141

File tree

1 file changed

+31
-49
lines changed

1 file changed

+31
-49
lines changed

Lib/subprocess.py

+31-49
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)