title: subprocess's Popen closes stdout/stderr filedescriptors used in another thread when Popen errors
body: <p>An internal library that heavily uses subprocess.Popen() started failing its automated tests when we upgraded from Python 2.7.3 to Python 2.7.5. This library is used in a threaded environment. After debugging the issue, I was able to create a short Python script that demonstrates the error seen as in the failing tests.</p>
  
  <p>This is the script (called "threadedsubprocess.py"):</p>
  
  <pre><code>import time
  import threading
  import subprocess
  
  def subprocesscall():
      p = subprocess.Popen(
          ['ls', '-l'],
          stdin=subprocess.PIPE,
          stdout=subprocess.PIPE,
          stderr=subprocess.PIPE,
          )
      time.sleep(2) # simulate the Popen call takes some time to complete.
      out, err = p.communicate()
      print 'succeeding command in thread:', threading.current_thread().ident
  
  def failingsubprocesscall():
      try:
          p = subprocess.Popen(
              ['thiscommandsurelydoesnotexist'],
              stdin=subprocess.PIPE,
              stdout=subprocess.PIPE,
              stderr=subprocess.PIPE,
              )
      except Exception as e:
          print 'failing command:', e, 'in thread:', threading.current_thread().ident
  
  print 'main thread is:', threading.current_thread().ident
  
  subprocesscall_thread = threading.Thread(target=subprocesscall)
  subprocesscall_thread.start()
  failingsubprocesscall()
  subprocesscall_thread.join()
  </code></pre>
  
  <p>Note: this script does not exit with an IOError when ran from Python 2.7.3. It does fail at least 50% of the times when ran from Python 2.7.5 (both on the same Ubuntu 12.04 64-bit VM).</p>
  
  <p>The error that is raised on Python 2.7.5 is this:</p>
  
  <pre><code>/opt/python/2.7.5/bin/python ./threadedsubprocess.py 
  main thread is: 139899583563520
  failing command: [Errno 2] No such file or directory 139899583563520
  Exception in thread Thread-1:
  Traceback (most recent call last):
    File "/opt/python/2.7.5/lib/python2.7/threading.py", line 808, in __bootstrap_inner
      self.run()
    File "/opt/python/2.7.5/lib/python2.7/threading.py", line 761, in run
      self.__target(*self.__args, **self.__kwargs)
    File "./threadedsubprocess.py", line 13, in subprocesscall
      out, err = p.communicate()
    File "/opt/python/2.7.5/lib/python2.7/subprocess.py", line 806, in communicate
      return self._communicate(input)
    File "/opt/python/2.7.5/lib/python2.7/subprocess.py", line 1379, in _communicate
      self.stdin.close()
  IOError: [Errno 9] Bad file descriptor
  
  close failed in file object destructor:
  IOError: [Errno 9] Bad file descriptor
  </code></pre>
  
  <p>When comparing the subprocess module from Python 2.7.3 to Python 2.7.5 I see the Popen()'s __init__() call indeed now explicitly closes the stdin, stdout and stderr file descriptors in case executing the command somehow fails. This seems to be an intended fix applied in Python 2.7.4 to prevent leaking file descriptors (<a href="http://hg.python.org/cpython/file/ab05e7dd2788/Misc/NEWS#l629">http://hg.python.org/cpython/file/ab05e7dd2788/Misc/NEWS#l629</a>).</p>
  
  <p>The diff between Python 2.7.3 and Python 2.7.5 that seems to be relevant to this issue is in the Popen __init__():</p>
  
  <pre><code>@@ -671,12 +702,33 @@
            c2pread, c2pwrite,
            errread, errwrite) = self._get_handles(stdin, stdout, stderr)
  
  -        self._execute_child(args, executable, preexec_fn, close_fds,
  -                            cwd, env, universal_newlines,
  -                            startupinfo, creationflags, shell,
  -                            p2cread, p2cwrite,
  -                            c2pread, c2pwrite,
  -                            errread, errwrite)
  +        try:
  +            self._execute_child(args, executable, preexec_fn, close_fds,
  +                                cwd, env, universal_newlines,
  +                                startupinfo, creationflags, shell,
  +                                p2cread, p2cwrite,
  +                                c2pread, c2pwrite,
  +                                errread, errwrite)
  +        except Exception:
  +            # Preserve original exception in case os.close raises.
  +            exc_type, exc_value, exc_trace = sys.exc_info()
  +
  +            to_close = []
  +            # Only close the pipes we created.
  +            if stdin == PIPE:
  +                to_close.extend((p2cread, p2cwrite))
  +            if stdout == PIPE:
  +                to_close.extend((c2pread, c2pwrite))
  +            if stderr == PIPE:
  +                to_close.extend((errread, errwrite))
  +
  +            for fd in to_close:
  +                try:
  +                    os.close(fd)
  +                except EnvironmentError:
  +                    pass
  +
  +            raise exc_type, exc_value, exc_trace
  </code></pre>
  
  <p>I think I have three questions:</p>
  
  <p>1) Is it true it should principally possible to use subprocess.Popen, with PIPE for stdin, stdout and stderr, in a threaded environment?</p>
  
  <p>2) How do I prevent the file descriptors for stdin, stdout and stderr to be closed when the Popen() fails in one of the threads?</p>
  
  <p>3) Am I doing something wrong here? </p>