Issue #6274. Fixed a potential FD leak in subprocess.py.
This commit is contained in:
parent
5fe420e34c
commit
8c826b77e0
|
@ -1056,90 +1056,98 @@ class Popen(object):
|
||||||
# The first char specifies the exception type: 0 means
|
# The first char specifies the exception type: 0 means
|
||||||
# OSError, 1 means some other error.
|
# OSError, 1 means some other error.
|
||||||
errpipe_read, errpipe_write = os.pipe()
|
errpipe_read, errpipe_write = os.pipe()
|
||||||
self._set_cloexec_flag(errpipe_write)
|
|
||||||
|
|
||||||
gc_was_enabled = gc.isenabled()
|
|
||||||
# Disable gc to avoid bug where gc -> file_dealloc ->
|
|
||||||
# write to stderr -> hang. http://bugs.python.org/issue1336
|
|
||||||
gc.disable()
|
|
||||||
try:
|
try:
|
||||||
self.pid = os.fork()
|
|
||||||
except:
|
|
||||||
if gc_was_enabled:
|
|
||||||
gc.enable()
|
|
||||||
raise
|
|
||||||
self._child_created = True
|
|
||||||
if self.pid == 0:
|
|
||||||
# Child
|
|
||||||
try:
|
try:
|
||||||
# Close parent's pipe ends
|
self._set_cloexec_flag(errpipe_write)
|
||||||
if p2cwrite is not None:
|
|
||||||
os.close(p2cwrite)
|
|
||||||
if c2pread is not None:
|
|
||||||
os.close(c2pread)
|
|
||||||
if errread is not None:
|
|
||||||
os.close(errread)
|
|
||||||
os.close(errpipe_read)
|
|
||||||
|
|
||||||
# Dup fds for child
|
gc_was_enabled = gc.isenabled()
|
||||||
if p2cread is not None:
|
# Disable gc to avoid bug where gc -> file_dealloc ->
|
||||||
os.dup2(p2cread, 0)
|
# write to stderr -> hang. http://bugs.python.org/issue1336
|
||||||
if c2pwrite is not None:
|
gc.disable()
|
||||||
os.dup2(c2pwrite, 1)
|
try:
|
||||||
if errwrite is not None:
|
self.pid = os.fork()
|
||||||
os.dup2(errwrite, 2)
|
except:
|
||||||
|
if gc_was_enabled:
|
||||||
|
gc.enable()
|
||||||
|
raise
|
||||||
|
self._child_created = True
|
||||||
|
if self.pid == 0:
|
||||||
|
# Child
|
||||||
|
try:
|
||||||
|
# Close parent's pipe ends
|
||||||
|
if p2cwrite is not None:
|
||||||
|
os.close(p2cwrite)
|
||||||
|
if c2pread is not None:
|
||||||
|
os.close(c2pread)
|
||||||
|
if errread is not None:
|
||||||
|
os.close(errread)
|
||||||
|
os.close(errpipe_read)
|
||||||
|
|
||||||
# Close pipe fds. Make sure we don't close the same
|
# Dup fds for child
|
||||||
# fd more than once, or standard fds.
|
if p2cread is not None:
|
||||||
if p2cread is not None and p2cread not in (0,):
|
os.dup2(p2cread, 0)
|
||||||
os.close(p2cread)
|
if c2pwrite is not None:
|
||||||
if c2pwrite is not None and c2pwrite not in (p2cread, 1):
|
os.dup2(c2pwrite, 1)
|
||||||
os.close(c2pwrite)
|
if errwrite is not None:
|
||||||
if errwrite is not None and errwrite not in (p2cread, c2pwrite, 2):
|
os.dup2(errwrite, 2)
|
||||||
os.close(errwrite)
|
|
||||||
|
|
||||||
# Close all other fds, if asked for
|
# Close pipe fds. Make sure we don't close the same
|
||||||
if close_fds:
|
# fd more than once, or standard fds.
|
||||||
self._close_fds(but=errpipe_write)
|
if p2cread is not None and p2cread not in (0,):
|
||||||
|
os.close(p2cread)
|
||||||
|
if c2pwrite is not None and c2pwrite not in (p2cread, 1):
|
||||||
|
os.close(c2pwrite)
|
||||||
|
if errwrite is not None and errwrite not in (p2cread, c2pwrite, 2):
|
||||||
|
os.close(errwrite)
|
||||||
|
|
||||||
if cwd is not None:
|
# Close all other fds, if asked for
|
||||||
os.chdir(cwd)
|
if close_fds:
|
||||||
|
self._close_fds(but=errpipe_write)
|
||||||
|
|
||||||
if preexec_fn:
|
if cwd is not None:
|
||||||
preexec_fn()
|
os.chdir(cwd)
|
||||||
|
|
||||||
if env is None:
|
if preexec_fn:
|
||||||
os.execvp(executable, args)
|
preexec_fn()
|
||||||
else:
|
|
||||||
os.execvpe(executable, args, env)
|
|
||||||
|
|
||||||
except:
|
if env is None:
|
||||||
exc_type, exc_value, tb = sys.exc_info()
|
os.execvp(executable, args)
|
||||||
# Save the traceback and attach it to the exception object
|
else:
|
||||||
exc_lines = traceback.format_exception(exc_type,
|
os.execvpe(executable, args, env)
|
||||||
exc_value,
|
|
||||||
tb)
|
|
||||||
exc_value.child_traceback = ''.join(exc_lines)
|
|
||||||
os.write(errpipe_write, pickle.dumps(exc_value))
|
|
||||||
|
|
||||||
# This exitcode won't be reported to applications, so it
|
except:
|
||||||
# really doesn't matter what we return.
|
exc_type, exc_value, tb = sys.exc_info()
|
||||||
os._exit(255)
|
# Save the traceback and attach it to the exception object
|
||||||
|
exc_lines = traceback.format_exception(exc_type,
|
||||||
|
exc_value,
|
||||||
|
tb)
|
||||||
|
exc_value.child_traceback = ''.join(exc_lines)
|
||||||
|
os.write(errpipe_write, pickle.dumps(exc_value))
|
||||||
|
|
||||||
# Parent
|
# This exitcode won't be reported to applications, so it
|
||||||
if gc_was_enabled:
|
# really doesn't matter what we return.
|
||||||
gc.enable()
|
os._exit(255)
|
||||||
os.close(errpipe_write)
|
|
||||||
if p2cread is not None and p2cwrite is not None:
|
# Parent
|
||||||
os.close(p2cread)
|
if gc_was_enabled:
|
||||||
if c2pwrite is not None and c2pread is not None:
|
gc.enable()
|
||||||
os.close(c2pwrite)
|
finally:
|
||||||
if errwrite is not None and errread is not None:
|
# be sure the FD is closed no matter what
|
||||||
os.close(errwrite)
|
os.close(errpipe_write)
|
||||||
|
|
||||||
|
if p2cread is not None and p2cwrite is not None:
|
||||||
|
os.close(p2cread)
|
||||||
|
if c2pwrite is not None and c2pread is not None:
|
||||||
|
os.close(c2pwrite)
|
||||||
|
if errwrite is not None and errread is not None:
|
||||||
|
os.close(errwrite)
|
||||||
|
|
||||||
|
# Wait for exec to fail or succeed; possibly raising exception
|
||||||
|
data = os.read(errpipe_read, 1048576) # Exception limited to 1M
|
||||||
|
finally:
|
||||||
|
# be sure the FD is closed no matter what
|
||||||
|
os.close(errpipe_read)
|
||||||
|
|
||||||
# Wait for exec to fail or succeed; possibly raising exception
|
|
||||||
data = os.read(errpipe_read, 1048576) # Exceptions limited to 1 MB
|
|
||||||
os.close(errpipe_read)
|
|
||||||
if data != "":
|
if data != "":
|
||||||
os.waitpid(self.pid, 0)
|
os.waitpid(self.pid, 0)
|
||||||
child_exception = pickle.loads(data)
|
child_exception = pickle.loads(data)
|
||||||
|
|
|
@ -327,6 +327,8 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #6274: Fixed possible file descriptors leak in subprocess.py
|
||||||
|
|
||||||
- Issue #6189: Restored compatibility of subprocess.py with Python 2.2.
|
- Issue #6189: Restored compatibility of subprocess.py with Python 2.2.
|
||||||
|
|
||||||
- Issue #6287: Added the license field in Distutils documentation.
|
- Issue #6287: Added the license field in Distutils documentation.
|
||||||
|
|
Loading…
Reference in New Issue