python / python/cpython

Inconsistent `Popen.communicate()` behavior if stdin/stdout/stderr is closed `PIPE`

Aperta
#131,064 2 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

stdlib type-bug
Lingua principale
Python
Stelle
77.2k
Fork
35.9k
Metriche di merge delle PR
Metriche PR in attesa

Descrizione

Bug report

Bug description:

The behavior with Popen.communicate() if stdin/stdout/stderr are PIPEs and they are closed before calling communicate() is rather strange.

If both stdout and stderr are PIPEs and one (or both) is closed, communicate() succeeds. If only one of them is a PIPE and it is closed, the behavior changes and there's a ValueError instead:

>>> from subprocess import Popen, PIPE
>>>
>>> p = Popen(['python', '-V'], stdout=PIPE, stderr=PIPE)
>>> p.stdout.close()
>>> p.communicate()
(b'', b'')
>>>
>>> p = Popen(['python', '-V'], stdout=PIPE)
>>> p.stdout.close()
>>> p.communicate()
Traceback (most recent call last):
  File "<python-input-7>", line 1, in <module>
    p.communicate()
    ~~~~~~~~~~~~~^^
  File "/usr/lib/python3.14/subprocess.py", line 1207, in communicate
    stdout = self.stdout.read()
ValueError: read of closed file

If stdin is a closed PIPE, the behavior is pretty much the opposite of the above. If other streams are not PIPEs, communicate() succeeds, but if the are other PIPEs, we get a ValueError:

>>> from subprocess import Popen, PIPE
>>>
>>> p = Popen(['python', '-c', 'pass'], stdin=PIPE)
>>> p.stdin.close()
>>> p.communicate()
(None, None)
>>> 
>>> p = Popen(['python', '-c', 'pass'], stdin=PIPE, stdout=PIPE)
>>> p.stdin.close()
>>> p.communicate()
Traceback (most recent call last):
  File "<python-input-14>", line 1, in <module>
    p.communicate()
    ~~~~~~~~~~~~~^^
  File "/usr/lib/python3.14/subprocess.py", line 1220, in communicate
    stdout, stderr = self._communicate(input, endtime, timeout)
                     ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.14/subprocess.py", line 2081, in _communicate
    self.stdin.flush()
    ~~~~~~~~~~~~~~~~^^
ValueError: flush of closed file

This inconsistency seems to be caused by an optimization that leads to two different code paths depending on the number of PIPEs. I needed to spend some time to understand why our tests behaved seemingly inconsistently after code was refactored.

It would be easy to fix problems by changing code like if self.stdout: to if self.stdout and not self.stdout.closed:. I guess it could be argued that raising a ValueError is the correct way to handle these situations, but in that case it should be raised always.

Tested with Python 3.14 alpha 5. Occurs also with earlier ones.

CPython versions tested on:

3.14

Operating systems tested on:

Linux

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Direzione di ricerca

Riproduci prima gli esempi di closed-PIPE, quindi esamina in Lib/subprocess.py l’ottimizzazione di communicate() collegata vicino alla riga 1194 e la gestione di stdin/stdout mostrata nel traceback. Decidi e conferma il comportamento coerente previsto per gli stream chiusi, quindi aggiungi una copertura di regressione per le combinazioni interessate e verifica i test subprocess esistenti.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
python
Ambito
operating-systems
Tipo di issue
Bug
Difficoltà
3/5
Tempo stimato
1-2 giorni
Stato di attività
Ferma
Chiarezza
Abbastanza chiara
Idoneità per principianti
42/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.