Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 10706e2

Browse files
Issue #6274. Fixed a potential FD leak in subprocess.py.
1 parent e9ff86e commit 10706e2

2 files changed

Lines changed: 96 additions & 83 deletions

File tree

Lib/subprocess.py

Lines changed: 94 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,91 +1034,102 @@ def _execute_child(self, args, executable, preexec_fn, close_fds,
10341034
# The first char specifies the exception type: 0 means
10351035
# OSError, 1 means some other error.
10361036
errpipe_read, errpipe_write = os.pipe()
1037-
self._set_cloexec_flag(errpipe_write)
1038-
1039-
gc_was_enabled = gc.isenabled()
1040-
# Disable gc to avoid bug where gc -> file_dealloc ->
1041-
# write to stderr -> hang. http://bugs.python.org/issue1336
1042-
gc.disable()
10431037
try:
1044-
self.pid = os.fork()
1045-
except:
1046-
if gc_was_enabled:
1047-
gc.enable()
1048-
raise
1049-
self._child_created = True
1050-
if self.pid == 0:
1051-
# Child
10521038
try:
1053-
# Close parent's pipe ends
1054-
if p2cwrite is not None:
1055-
os.close(p2cwrite)
1056-
if c2pread is not None:
1057-
os.close(c2pread)
1058-
if errread is not None:
1059-
os.close(errread)
1060-
os.close(errpipe_read)
1061-
1062-
# Dup fds for child
1063-
if p2cread is not None:
1064-
os.dup2(p2cread, 0)
1065-
if c2pwrite is not None:
1066-
os.dup2(c2pwrite, 1)
1067-
if errwrite is not None:
1068-
os.dup2(errwrite, 2)
1069-
1070-
# Close pipe fds. Make sure we don't close the same
1071-
# fd more than once, or standard fds.
1072-
if p2cread is not None and p2cread not in (0,):
1073-
os.close(p2cread)
1074-
if c2pwrite is not None and c2pwrite not in (p2cread, 1):
1075-
os.close(c2pwrite)
1076-
if (errwrite is not None and
1077-
errwrite not in (p2cread, c2pwrite, 2)):
1078-
os.close(errwrite)
1079-
1080-
# Close all other fds, if asked for
1081-
if close_fds:
1082-
self._close_fds(but=errpipe_write)
1083-
1084-
if cwd is not None:
1085-
os.chdir(cwd)
1086-
1087-
if preexec_fn:
1088-
preexec_fn()
1089-
1090-
if env is None:
1091-
os.execvp(executable, args)
1092-
else:
1093-
os.execvpe(executable, args, env)
1094-
1095-
except:
1096-
exc_type, exc_value, tb = sys.exc_info()
1097-
# Save the traceback and attach it to the exception object
1098-
exc_lines = traceback.format_exception(exc_type,
1099-
exc_value,
1100-
tb)
1101-
exc_value.child_traceback = ''.join(exc_lines)
1102-
os.write(errpipe_write, pickle.dumps(exc_value))
1103-
1104-
# This exitcode won't be reported to applications, so it
1105-
# really doesn't matter what we return.
1106-
os._exit(255)
1107-
1108-
# Parent
1109-
if gc_was_enabled:
1110-
gc.enable()
1111-
os.close(errpipe_write)
1112-
if p2cread is not None and p2cwrite is not None:
1113-
os.close(p2cread)
1114-
if c2pwrite is not None and c2pread is not None:
1115-
os.close(c2pwrite)
1116-
if errwrite is not None and errread is not None:
1117-
os.close(errwrite)
1118-
1119-
# Wait for exec to fail or succeed; possibly raising exception
1120-
data = os.read(errpipe_read, 1048576) # Exceptions limited to 1 MB
1121-
os.close(errpipe_read)
1039+
self._set_cloexec_flag(errpipe_write)
1040+
1041+
gc_was_enabled = gc.isenabled()
1042+
# Disable gc to avoid bug where gc -> file_dealloc ->
1043+
# write to stderr -> hang. http://bugs.python.org/issue1336
1044+
gc.disable()
1045+
try:
1046+
self.pid = os.fork()
1047+
except:
1048+
if gc_was_enabled:
1049+
gc.enable()
1050+
raise
1051+
self._child_created = True
1052+
if self.pid == 0:
1053+
# Child
1054+
try:
1055+
# Close parent's pipe ends
1056+
if p2cwrite is not None:
1057+
os.close(p2cwrite)
1058+
if c2pread is not None:
1059+
os.close(c2pread)
1060+
if errread is not None:
1061+
os.close(errread)
1062+
os.close(errpipe_read)
1063+
1064+
# Dup fds for child
1065+
if p2cread is not None:
1066+
os.dup2(p2cread, 0)
1067+
if c2pwrite is not None:
1068+
os.dup2(c2pwrite, 1)
1069+
if errwrite is not None:
1070+
os.dup2(errwrite, 2)
1071+
1072+
# Close pipe fds. Make sure we don't close the
1073+
# same fd more than once, or standard fds.
1074+
if p2cread is not None and p2cread not in (0,):
1075+
os.close(p2cread)
1076+
if c2pwrite is not None and \
1077+
c2pwrite not in (p2cread, 1):
1078+
os.close(c2pwrite)
1079+
if (errwrite is not None and
1080+
errwrite not in (p2cread, c2pwrite, 2)):
1081+
os.close(errwrite)
1082+
1083+
# Close all other fds, if asked for
1084+
if close_fds:
1085+
self._close_fds(but=errpipe_write)
1086+
1087+
if cwd is not None:
1088+
os.chdir(cwd)
1089+
1090+
if preexec_fn:
1091+
preexec_fn()
1092+
1093+
if env is None:
1094+
os.execvp(executable, args)
1095+
else:
1096+
os.execvpe(executable, args, env)
1097+
1098+
except:
1099+
exc_type, exc_value, tb = sys.exc_info()
1100+
# Save the traceback and attach it to the exception
1101+
# object
1102+
exc_lines = traceback.format_exception(exc_type,
1103+
exc_value,
1104+
tb)
1105+
exc_value.child_traceback = ''.join(exc_lines)
1106+
os.write(errpipe_write, pickle.dumps(exc_value))
1107+
1108+
# This exitcode won't be reported to applications, so
1109+
# it really doesn't matter what we return.
1110+
os._exit(255)
1111+
1112+
# Parent
1113+
if gc_was_enabled:
1114+
gc.enable()
1115+
finally:
1116+
# be sure the FD is closed no matter what
1117+
os.close(errpipe_write)
1118+
1119+
if p2cread is not None and p2cwrite is not None:
1120+
os.close(p2cread)
1121+
if c2pwrite is not None and c2pread is not None:
1122+
os.close(c2pwrite)
1123+
if errwrite is not None and errread is not None:
1124+
os.close(errwrite)
1125+
1126+
# Wait for exec to fail or succeed; possibly raising an
1127+
# exception (limited to 1 MB)
1128+
data = os.read(errpipe_read, 1048576)
1129+
finally:
1130+
# be sure the FD is closed no matter what
1131+
os.close(errpipe_read)
1132+
11221133
if data:
11231134
os.waitpid(self.pid, 0)
11241135
child_exception = pickle.loads(data)

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ Core and Builtins
1515
Library
1616
-------
1717

18+
- Issue #6274: Fixed possible file descriptors leak in subprocess.py
19+
1820
- Accessing io.StringIO.buffer now raises an AttributeError instead of
1921
io.UnsupportedOperation.
2022

0 commit comments

Comments
 (0)