INADA Naoki <songofaca...@gmail.com> added the comment:

>
> where the *child* process (`self.pid == 0`) get stuck while calling 
> _dup2(c2pwrite = 4, 1) which in turn calls os.dup2(a = 4, b = 1).
>

Doesn't child process get stuck while writing stdout?

>
> It would also be interesting to understand exactly what causes the stall.  Is 
> it indeed the pipe that gets filled up?  Is that because the kernel does 
> *not* respect the pipe limit and just dumps all output at once (> 65,536 
> bytes), i.e. it is a bug?  Or is it that Python or one of its dependencies 
> runs into a race condition because, say, it does not have a chance to set up 
> the parent-child communication before the child (== the kernel) dumps too 
> much data?
>

In a normal case, when child process succeeded to `exec`,
`errpipe_write` must be closed, by CLOEXEC flag.
Then, parent process `_eintr_retry_call(os.read, errpipe_read,
1048576)` returns b"".
So parent process can read from stdio pipes, and child process can
write to stdio pipes more than 65536 bytes.

In your case, `errpipe_write` is not closed when `exec` is succeeded.
That's kernel bug.
Parent process `_eintr_retry_call(os.read, errpipe_read, 1048576)`
does not return until child process exits.
But child process is blocked when writing to stdout/err more than 65536 bytes.
Deadlock happened.

>
> A BROKEN DESIGN?
>
> Finally, I don't know if the fact that `/sbin/ldconfig` does not exist but 
> you can yet call it is (i) poorly designed kernel, or (ii) a valid design in 
> the Unix world.  I don't know the answer to this and I don't claim one is 
> more correct than the other.  I also don't know if there are other kernels 
> out there that does this type of interception.  If it is indeed a valid 
> design, then one could argue that Python and other software tools should be 
> able to handle it.  FYI, this far I've/we've only hit this issue with Python 
> (>= 2.7.13), maybe because of pure luck.  It did not cause a problem in 
> Python (< 2.7.13) and it does not cause a problem if we use 
> subprocess.Popen(..., 'shell = True').  On the other hand, if one would argue 
> that it is a poor design, then would it make sense to protect against by for 
> instance asserting that the executable actually exists before calling it:
>

I don't know (i) or (II).
But I don't think the assertion makes sense.  I expect OSError rather
than RuntimeError.

----------

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue35305>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to