Python 3.3.3 Windows 7
Here is the full stack:
Traceback (most recent call last):
File \"Blah\\MyScript.py\", line 578, in Call
output = process.commun
Previously communicate
only ignored an EPIPE
error when writing to the process stdin
. Starting with 3.3.5, per issue 19612, it also ignores EINVAL
(22) if the child has already exited (see Lib/subprocess.py line 1199).
Background:
process.communiciate
calls process.stdin.write
, which calls io.FileIO.write
, which on Windows calls the C runtime _write, which calls Win32 WriteFile (which in this case calls NtWriteFile, which dispatches to the NamedPipe filesystem, as either an IRP_MJ_WRITE
or FastIoWrite
).
If the latter fails, it sets a Windows system error code in the thread. In this case the underlying Windows error is probably ERROR_NO_DATA (232) because the child process has already exited. The C runtime maps this to an errno
value of EINVAL
(22). Then since _write
failed, FileIO.write
raises OSError
based on the current value of errno
.
Addendum:
There wouldn't have been a problem at all if the CRT instead mapped ERROR_NO_DATA
to EPIPE
. Python's own Windows error translation generally follows the CRT's, but per issue 13063, it makes an exception to map ERROR_NO_DATA
to EPIPE
(32). Thus if the child has already exited, _winapi.WriteFile
raises BrokenPipeError
.
The following example replicates the EINVAL
error given the child process has already exited. It also shows how _winapi.WriteFile (3.3.3 source link) would instead map this error to EPIPE
. IMO, this should be considered a bug in Microsoft's CRT.
>>> cmd = 'reg query hkcu'
>>> process = Popen(cmd, stdin=PIPE, stdout=PIPE, universal_newlines=True)
>>> process.stdin.write(' ')
Traceback (most recent call last):
File "", line 1, in
OSError: [Errno 22] Invalid argument
>>> hstdin = msvcrt.get_osfhandle(process.stdin.fileno())
>>> _winapi.WriteFile(hstdin, b' ')
Traceback (most recent call last):
File "", line 1, in
BrokenPipeError: [WinError 232] The pipe is being closed