Re: bash incorrectly handles 'echo' + SIGPIPE under some situations on Linux

2016-01-06 Thread Chet Ramey
On 1/5/16 11:47 AM, c...@cs.toronto.edu wrote:

> Bash Version: 4.3
> Patch Level: 11
> Release Status: release
> 
> Description:
> 
> If Bash writes to stdout with the built in echo and gets a SIGPIPE,
> it can incorrectly buffer and then repeat this would-have-been output
> in at least $(...) things invoked in a cleanup function and in fact
> in some other contexts as well. To see this in action, create the
> following script as /tmp/repro:
> 
>   #!/bin/bash
>   function cleanup() {
>   r1=$(/bin/echo one)
>   r2=$(/bin/echo two)
>   echo $r1 '!' $r2 1>&2
>   #echo $r1 '!' $r2 >>/tmp/logout
>   }
>   trap cleanup EXIT
>   sleep 1
>   echo final
> 
> Run it as '/tmp/repro | false'. The output produced is the clearly
> incorrect:
>   $ /tmp/repro | false
>   final
>   one final ! two final

Thanks for the report.  This appears to be easily reproducible on Linux.

Adding a call to fpurge() to discard buffered output on stdout before
dup2() replaces file descriptor 1 in the child process fixes it.

Chet
-- 
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/



Re: bash incorrectly handles 'echo' + SIGPIPE under some situations on Linux

2016-01-06 Thread Chris Siebenmann
> > If Bash writes to stdout with the built in echo and gets a SIGPIPE,
> > it can incorrectly buffer and then repeat this would-have-been output
> > in at least $(...) things invoked in a cleanup function and in fact
> > in some other contexts as well. To see this in action, create the
> > following script as /tmp/repro:
> > 
> > #!/bin/bash
> > function cleanup() {
> > r1=$(/bin/echo one)
> > r2=$(/bin/echo two)
> > echo $r1 '!' $r2 1>&2
> > #echo $r1 '!' $r2 >>/tmp/logout
> > }
> > trap cleanup EXIT
> > sleep 1
> > echo final
> > 
> > Run it as '/tmp/repro | false'. The output produced is the clearly
> > incorrect:
> > $ /tmp/repro | false
> > final
> > one final ! two final
> 
> Thanks for the report.  This appears to be easily reproducible on Linux.
> 
> Adding a call to fpurge() to discard buffered output on stdout before
> dup2() replaces file descriptor 1 in the child process fixes it.

 Note that the problem isn't only in the children; the parent process
itself has a problem too, as the 'final' by itself should not be printed
either (and comes entirely from the parent).

$ cat repro2
#!/bin/bash
function cleanup() {
echo end 1>&2
}
trap cleanup EXIT
sleep 1
echo final

$ ./repro2 | false
final
end

 Strace on Linux confirms that this only fork()s to do the sleep; the
entire sequence from returning from sleep through the end happens in the
main Bash process.

- cks



'official function declaration format' doesn't work if alias defined

2016-01-06 Thread Linda Walsh

I had an alias referring to printf that I wanted to replace
with a function.

instead of using the function declarator
'function' (or my alias 'sub'), I remembered that the official
way was to use:

 P () {
   ...
 }

But then ran into problems with the alias taking precedence over the
function.

Even in the file where the function was defined and exported, I got
an error in the export statement about "P" not being a function.
I also tried unaliasing it:

 unalias P >& /dev/null || ((1))

 export -f P Pe

But still got the "not a function" ... then I realized
I had used the official, POSIX format for function declarations,
above, but guess it had silently been changed into
 printf () {
   ...
 }
by the 'alias'. 


Sure enough, using the old form:

 function P () {
   ...
 }

caused "P" to be defined as a function -- so when it was
unaliased and exported, the export statement found the function.

I am not sure how one would catch a problem like that other than
by make sure the defined function is never the 1st argument on the line
(by adding function).  Seems like using 'function' is safer.

Perhaps the idea of leaving off "function" at the beginning of a function
isn't such a good practice?

(bash, version 4.3.39)

-l