coproc state wrongly inherited by subshell

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

coproc state wrongly inherited by subshell

Tobias Hoffmann
Configuration Information [Automatically generated, do not change]:
Machine: i586
OS: linux-gnu
Compiler: gcc
Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='i586'
-DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='i586-pc-linux-gnu'
-DCONF_VENDOR='pc' -DLOCALEDIR='/usr/share/locale' -DPACKAGE='bash'
-DSHELL -DHAVE_CONFIG_H -I. -I../. -I.././include -I.././lib
-D_FORTIFY_SOURCE=2 -g -O2 -fstack-protector-strong -Wformat
-Werror=format-security -Wall
uname output: Linux worker 4.13.0-rc7 #41 SMP PREEMPT Sat Sep 2 12:42:52
CEST 2017 x86_64 GNU/Linux
Machine Type: i586-pc-linux-gnu

Bash Version: 4.3
Patch Level: 33
Release Status: release

Description:
As stated in the man page, bash will only allow a single coproc at a time.
Thus, when a first coproc has already ended, a second one can be created.
This can e.g. be verified by commenting out the upper #sleep line, below.
Alternatively, you can remove the parens that start the subshell.

But if we start a subshell while the coproc still runs, then wait inside
the subshell
until the first coproc has ended and then try to start another coproc,
bash prints the
infamous warning:
./test_sp1.sh: line 10: warning: execute_coproc: coproc [11030:COPROC]
still exists

The process id 11030 does (verifyably - e.g. add `ps a`) not exist the
time the warning is printed.░

Repeat-By:
coproc { echo "Start 1" >&2; sleep 1; echo "Stop 1" >&2; }

#sleep 1.1 # use this instead and the warning will disapped
sleep 0.9

(
sleep 0.5
coproc { echo "Start 2" >&2; sleep 1; echo "Stop 2" >&2; }
)

sleep 1.5

echo "Done"

Fix:
Probably some internal variables have to be reset on fork().

Reply | Threaded
Open this post in threaded view
|

Re: coproc state wrongly inherited by subshell

Chet Ramey
On 11/29/17 5:36 PM, Tobias Hoffmann wrote:

> Description:
> As stated in the man page, bash will only allow a single coproc at a time.
> Thus, when a first coproc has already ended, a second one can be created.
> This can e.g. be verified by commenting out the upper #sleep line, below.
> Alternatively, you can remove the parens that start the subshell.
>
> But if we start a subshell while the coproc still runs, then wait inside
> the subshell
> until the first coproc has ended and then try to start another coproc, bash
> prints the
> infamous warning:
> ./test_sp1.sh: line 10: warning: execute_coproc: coproc [11030:COPROC]
> still exists
>
> The process id 11030 does (verifyably - e.g. add `ps a`) not exist the time
> the warning is printed.░

The question is how much to reset, and when to do it. A child process can
legitimately expect to inherit the coproc file descriptors from its parent
and read and write them under circumstances that have been valid
historically. The pid will never be valid for waiting in the child, because
it's not a child of the current shell, but simply testing whether or not
the process is alive isn't sufficient.

I think the best thing to do is to invalidate the pid whenever a child
process invalidates the coproc FDs.

Chet


--
``The lyf so short, the craft so long to lerne.'' - Chaucer
                 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU    [hidden email]    http://cnswww.cns.cwru.edu/~chet/

Reply | Threaded
Open this post in threaded view
|

Re: coproc state wrongly inherited by subshell

Tobias Hoffmann
On 03/12/17 21:14, Chet Ramey wrote:

> On 11/29/17 5:36 PM, Tobias Hoffmann wrote:
>
>> Description:
>> As stated in the man page, bash will only allow a single coproc at a time.
>> Thus, when a first coproc has already ended, a second one can be created.
>> This can e.g. be verified by commenting out the upper #sleep line, below.
>> Alternatively, you can remove the parens that start the subshell.
>>
>> But if we start a subshell while the coproc still runs, then wait inside
>> the subshell
>> until the first coproc has ended and then try to start another coproc, bash
>> prints the
>> infamous warning:
>> ./test_sp1.sh: line 10: warning: execute_coproc: coproc [11030:COPROC]
>> still exists
>>
>> The process id 11030 does (verifyably - e.g. add `ps a`) not exist the time
>> the warning is printed.░
> The question is how much to reset, and when to do it. A child process can
> legitimately expect to inherit the coproc file descriptors from its parent
> and read and write them under circumstances that have been valid
> historically.
Well, there seem to be two types of subshells: Those spawned with (...
), &, or | -- and those coming from $(...) and <( ... ).

In both of them $COPROC[] and $COPROC_PID are available, but only in the
second kind you can actually use the file descriptors. In the first
kind, you'll get (e.g.)
   ${COPROC[1]}: Bad file descriptor
(i.e. does not work, as documented).

You can, however, make them available even in the first kind, by duping
them first, e.g. by using
   exec {fd}>&${COPROC[1]}

I'm not sure whether using them directly in the first kind of subshell
is actually a good idea. Some things seem to work better when duping
them first, but I have not investigated those cases further.

   Tobias

> The pid will never be valid for waiting in the child, because
> it's not a child of the current shell, but simply testing whether or not
> the process is alive isn't sufficient.
>
> I think the best thing to do is to invalidate the pid whenever a child
> process invalidates the coproc FDs.
>
> Chet