This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: pipe read sometimes returns EOF but returncode is still None
Type: behavior Stage: resolved
Components: Library (Lib) Versions: Python 3.8
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: Dormouse759, martin.panter, pmoravec, vstinner
Priority: normal Keywords:

Created on 2018-09-03 12:06 by Dormouse759, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
script.py Dormouse759, 2018-09-03 12:06
Messages (5)
msg324508 - (view) Author: Marcel Plch (Dormouse759) * Date: 2018-09-03 12:06
TL;DR: For reproducer, please see attached file and the end of this description for a runner script.

It seems that when pipe is being read it has a chance of returning EOF and not setting the return code.
This bug affects all (or at least a broad set of) architectures and is present in all versions. (2.7 and 3.8 were tested).
This bug is not reproducible when configured using --with-pydebug flag.
As a result, any code relying on proper setting of the returncode attribute might (and probably is going to) fail.
-----------
$ for i in $(seq 1 1000); do ./python script.py; done | grep poll | sort | uniq -c

Actual output:
630 output: '', return code: 0, pollstatus=0
370 output: '', return code: None, pollstatus=None

Expected output:
1000 output: '', return code: 0, pollstatus=0
msg324510 - (view) Author: Marcel Plch (Dormouse759) * Date: 2018-09-03 12:17
original downstream issue - https://bugzilla.redhat.com/show_bug.cgi?id=1623070
msg324547 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2018-09-04 00:49
The "grep" process may be closing its end of the pipe before it exits. Or if Grep leaves the pipe open when it exits, the OS may close the pipe before it makes the child exit status available. Either way, I suspect "p.stdout.read()" returns an empty string indicating the pipe is closed, but "p.poll()" returns None because the exit status is not yet ready. Even if it is the OS closing the pipe after the child exits, I doubt there is any guarantee about when that happens relative to the child's exit status becoming available.

The "poll" method does not wait for the child to exit. Normally you use the "wait" method in this situation. I suspect this is a bug in the application, not in Python.
msg324620 - (view) Author: pmoravec (pmoravec) Date: 2018-09-05 09:53
> The "poll" method does not wait for the child to exit. Normally you use the "wait" method in this situation. I suspect this is a bug in the application, not in Python.

Thanks for clarification. Could you please confirm what code change in that script is safe, then?

1) looping "while p.poll() == None   pass" to really ensure some status is returned.

2) calling p.wait() before p.poll()

From a blackbox perspective, I would expect either to provide similar fixing mechanism of my script. But as we call this code snippet concurrently, for random commands that randomly terminates with random outcome / status, can't either fix attempt cause e.g. a deadlock?

Thanks in advance for help / advice.

(just for context if it matters: the snippet is from https://github.com/sosreport/sos/blob/master/sos/utilities.py#L158 where the sos_get_command_output method is called concurrently by more threads)
msg324659 - (view) Author: Martin Panter (martin.panter) * (Python committer) Date: 2018-09-06 04:33
You probably only need to call "wait" once. That blocks the thread until it gets a result, so it is more CPU-efficient than calling "poll" in a busy loop.

Since you open a separate pipe for "stderr" in script.py, but don't do anything with it, there could be a deadlock with the child writing to the stderr pipe versus the parent reading from "stdout" or waiting for the exit status.

I guess your script is an approximation of the "sos" application. I don't have time to understand everything it is trying to do, but I added some comments at <https://github.com/sosreport/sos/commit/2fcf5f0#r30410300>.
History
Date User Action Args
2022-04-11 14:59:05adminsetgithub: 78747
2018-09-06 04:33:02martin.pantersetstatus: open -> closed
resolution: not a bug
messages: + msg324659

stage: resolved
2018-09-05 09:53:19pmoravecsetnosy: + pmoravec
messages: + msg324620
2018-09-04 00:49:40martin.pantersetnosy: + martin.panter
messages: + msg324547
2018-09-03 13:48:01Dormouse759settype: behavior
2018-09-03 12:19:24vstinnersetnosy: + vstinner
2018-09-03 12:17:33Dormouse759setmessages: + msg324510
title: pipe read sometimmes returns EOF but returncode is still None -> pipe read sometimes returns EOF but returncode is still None
2018-09-03 12:06:40Dormouse759create