]> granicus.if.org Git - python/commitdiff
(merge 3.2) Close #12383: Fix subprocess module with env={}: don't copy the
authorVictor Stinner <victor.stinner@haypocalc.com>
Tue, 21 Jun 2011 15:24:21 +0000 (17:24 +0200)
committerVictor Stinner <victor.stinner@haypocalc.com>
Tue, 21 Jun 2011 15:24:21 +0000 (17:24 +0200)
environment variables, start with an empty environment.

1  2 
Lib/subprocess.py
Lib/test/test_subprocess.py
Misc/NEWS

index 49137d450379b6c155fdf1084e8f077caeba8572,06285e9462cb99aee13e1db1fd4cc7e81ca9c71c..cfd4c85584c90137b6a44499ccf2ba73e0afa718
@@@ -1245,33 -1162,140 +1245,33 @@@ class Popen(object)
              errpipe_read, errpipe_write = _create_pipe()
              try:
                  try:
 -
 -                    if _posixsubprocess:
 -                        # We must avoid complex work that could involve
 -                        # malloc or free in the child process to avoid
 -                        # potential deadlocks, thus we do all this here.
 -                        # and pass it to fork_exec()
 -
 -                        if env is not None:
 -                            env_list = [os.fsencode(k) + b'=' + os.fsencode(v)
 -                                        for k, v in env.items()]
 -                        else:
 -                            env_list = None  # Use execv instead of execve.
 -                        executable = os.fsencode(executable)
 -                        if os.path.dirname(executable):
 -                            executable_list = (executable,)
 -                        else:
 -                            # This matches the behavior of os._execvpe().
 -                            executable_list = tuple(
 -                                os.path.join(os.fsencode(dir), executable)
 -                                for dir in os.get_exec_path(env))
 -                        fds_to_keep = set(pass_fds)
 -                        fds_to_keep.add(errpipe_write)
 -                        self.pid = _posixsubprocess.fork_exec(
 -                                args, executable_list,
 -                                close_fds, sorted(fds_to_keep), cwd, env_list,
 -                                p2cread, p2cwrite, c2pread, c2pwrite,
 -                                errread, errwrite,
 -                                errpipe_read, errpipe_write,
 -                                restore_signals, start_new_session, preexec_fn)
 +                    # We must avoid complex work that could involve
 +                    # malloc or free in the child process to avoid
 +                    # potential deadlocks, thus we do all this here.
 +                    # and pass it to fork_exec()
 +
-                     if env:
++                    if env is not None:
 +                        env_list = [os.fsencode(k) + b'=' + os.fsencode(v)
 +                                    for k, v in env.items()]
                      else:
 -                        # Pure Python implementation: It is not thread safe.
 -                        # This implementation may deadlock in the child if your
 -                        # parent process has any other threads running.
 -
 -                        gc_was_enabled = gc.isenabled()
 -                        # Disable gc to avoid bug where gc -> file_dealloc ->
 -                        # write to stderr -> hang.  See issue1336
 -                        gc.disable()
 -                        try:
 -                            self.pid = os.fork()
 -                        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 != -1:
 -                                    os.close(p2cwrite)
 -                                if c2pread != -1:
 -                                    os.close(c2pread)
 -                                if errread != -1:
 -                                    os.close(errread)
 -                                os.close(errpipe_read)
 -
 -                                # Dup fds for child
 -                                def _dup2(a, b):
 -                                    # dup2() removes the CLOEXEC flag but
 -                                    # we must do it ourselves if dup2()
 -                                    # would be a no-op (issue #10806).
 -                                    if a == b:
 -                                        _set_cloexec(a, False)
 -                                    elif a != -1:
 -                                        os.dup2(a, b)
 -                                _dup2(p2cread, 0)
 -                                _dup2(c2pwrite, 1)
 -                                _dup2(errwrite, 2)
 -
 -                                # Close pipe fds.  Make sure we don't close the
 -                                # same fd more than once, or standard fds.
 -                                closed = set()
 -                                for fd in [p2cread, c2pwrite, errwrite]:
 -                                    if fd > 2 and fd not in closed:
 -                                        os.close(fd)
 -                                        closed.add(fd)
 -
 -                                # Close all other fds, if asked for
 -                                if close_fds:
 -                                    fds_to_keep = set(pass_fds)
 -                                    fds_to_keep.add(errpipe_write)
 -                                    self._close_fds(fds_to_keep)
 -
 -
 -                                if cwd is not None:
 -                                    os.chdir(cwd)
 -
 -                                # This is a copy of Python/pythonrun.c
 -                                # _Py_RestoreSignals().  If that were exposed
 -                                # as a sys._py_restoresignals func it would be
 -                                # better.. but this pure python implementation
 -                                # isn't likely to be used much anymore.
 -                                if restore_signals:
 -                                    signals = ('SIGPIPE', 'SIGXFZ', 'SIGXFSZ')
 -                                    for sig in signals:
 -                                        if hasattr(signal, sig):
 -                                            signal.signal(getattr(signal, sig),
 -                                                          signal.SIG_DFL)
 -
 -                                if start_new_session and hasattr(os, 'setsid'):
 -                                    os.setsid()
 -
 -                                if preexec_fn:
 -                                    preexec_fn()
 -
 -                                if env is None:
 -                                    os.execvp(executable, args)
 -                                else:
 -                                    os.execvpe(executable, args, env)
 -
 -                            except:
 -                                try:
 -                                    exc_type, exc_value = sys.exc_info()[:2]
 -                                    if isinstance(exc_value, OSError):
 -                                        errno_num = exc_value.errno
 -                                    else:
 -                                        errno_num = 0
 -                                    message = '%s:%x:%s' % (exc_type.__name__,
 -                                                            errno_num, exc_value)
 -                                    message = message.encode(errors="surrogatepass")
 -                                    os.write(errpipe_write, message)
 -                                except Exception:
 -                                    # We MUST not allow anything odd happening
 -                                    # above to prevent us from exiting below.
 -                                    pass
 -
 -                            # This exitcode won't be reported to applications
 -                            # so it really doesn't matter what we return.
 -                            os._exit(255)
 -
 -                        # Parent
 -                        if gc_was_enabled:
 -                            gc.enable()
 +                        env_list = None  # Use execv instead of execve.
 +                    executable = os.fsencode(executable)
 +                    if os.path.dirname(executable):
 +                        executable_list = (executable,)
 +                    else:
 +                        # This matches the behavior of os._execvpe().
 +                        executable_list = tuple(
 +                            os.path.join(os.fsencode(dir), executable)
 +                            for dir in os.get_exec_path(env))
 +                    fds_to_keep = set(pass_fds)
 +                    fds_to_keep.add(errpipe_write)
 +                    self.pid = _posixsubprocess.fork_exec(
 +                            args, executable_list,
 +                            close_fds, sorted(fds_to_keep), cwd, env_list,
 +                            p2cread, p2cwrite, c2pread, c2pwrite,
 +                            errread, errwrite,
 +                            errpipe_read, errpipe_write,
 +                            restore_signals, start_new_session, preexec_fn)
                  finally:
                      # be sure the FD is closed no matter what
                      os.close(errpipe_write)
Simple merge
diff --cc Misc/NEWS
index a793d0878bfec739cd1f6ded6c1024bd9130aef2,60405dd746483f7fa20954e89d167a96a400f0bb..272141fbeb643f466cc1df32d1a4088e886230b9
+++ b/Misc/NEWS
@@@ -196,13 -25,9 +196,16 @@@ Core and Builtin
  Library
  -------
  
+ - Issue #12383: Fix subprocess module with env={}: don't copy the environment
+   variables, start with an empty environment.
 +- Issue #11637: Fix support for importing packaging setup hooks from the
 +  project directory.
 +
 +- Issue #6771: Moved the curses.wrapper function from the single-function
 +  wrapper module into __init__, eliminating the module.  Since __init__ was
 +  already importing the function to curses.wrapper, there is no API change.
 +
  - Issue #11584: email.header.decode_header no longer fails if the header
    passed to it is a Header object, and Header/make_header no longer fail
    if given binary unknown-8bit input.