write() not retried after EINTR in printf and echo

2018-01-12 Thread Serge van den Boom
Configuration Information [Automatically generated, do not change]:
Machine: x86_64
OS: linux-gnu
Compiler: gcc
Compilation CFLAGS:  -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64' 
-DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='x86_64-unknown-linux-gnu' 
-DCONF_VENDOR='unknown' -DLOCALEDIR='/opt/bash-4.4.12/share/locale' 
-DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H   -I.  -I. -I./include -I./lib   -g 
-O2 -Wno-parentheses -Wno-format-security
uname output: Linux test 4.4.0-98-generic #121-Ubuntu SMP Tue Oct 10 14:24:03 
UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
Machine Type: x86_64-unknown-linux-gnu

Bash Version: 4.4
Patch Level: 12
Release Status: release

Description:
If during an 'echo' or 'printf', the write() system call returns an
EINTR error, the write() call is not retried.
This can can happen when a system call is interrupted when a
signal is received, which can happen when the user resized the
terminal while the write() call is blocked.

As a consequence, the intended output of 'echo' or 'printf' will be
missing.

Repeat-By:
1. Run the following command in a terminal (at least xterm works):
while :; do builtin echo foo; done | sleep 100
2. Wait a few seconds
3. Resize the terminal (try again if this does not work immediately)
   This will send a 'SIGWINCH' signal to bash. (You can also send
   it manually.)
4. "bash: echo: write error: Interrupted system call" will appear.

The same thing happens with 'printf' instead of 'echo'. There may be
other bash functionality which suffers from this.

The pipe, the 'sleep 100', and the waiting in step 2, are to fill up
the buffer of the pipe, so that the call to write() will block.

To see that data is actually omitted from the output (and that this
is not only a warning), you could run something like this instead
of step 1:
I=0
while :; do
builtin echo "$I"
I=$(($I + 1))
done | { sleep 5; cat > /tmp/test; }
Trigger the sending of the signal in the first 5 seconds, and then let
it run for a few seconds after. Inspecting /tmp/test will show that
certain numbers in the sequence are missing.

Fix:
I have not examined the actual Bash code, but typically, code
which causes such a problem will look like this:
int writeResult = write(fd, buf, toWrite);
if (writeResult == -1) {
perror("write");
// Handle error here.
}

It should be replaced by something like:
const char *bufPtr = buf;
int leftToWrite = toWrite;
while (leftToWrite > 0) {
int writeResult = write(fd, bufPtr, leftToWrite);
if (writeResult == -1) {
if (errno == EINTR)
continue;

perror("write");
// Handle error here.
}

leftToWrite -= writeResult;
bufPtr += writeResult;
}




Re: write() not retried after EINTR in printf and echo

2018-01-12 Thread Chet Ramey
On 1/12/18 12:05 PM, Serge van den Boom wrote:

> Bash Version: 4.4
> Patch Level: 12
> Release Status: release
> 
> Description:
>   If during an 'echo' or 'printf', the write() system call returns an
>   EINTR error, the write() call is not retried.
>   This can can happen when a system call is interrupted when a
>   signal is received, which can happen when the user resized the
>   terminal while the write() call is blocked.

There are a couple of signals for which this is the appropriate behavior.
The right fix is to install handlers with the SA_RESTART flag set. The
next version of bash will install its SIGWINCH handler with SA_RESTART.

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



misleading text in `help declare` leads to serious wrong translations (e.g. German)

2018-01-12 Thread dirk
Configuration Information [Automatically generated, do not change]:
Machine: x86_64
OS: linux-gnu
Compiler: gcc
Compilation CFLAGS:  -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64' 
-DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='x86_64-pc-linux-gnu' 
-DCONF_VENDOR='pc' -DLOCALEDIR='/usr/share/locale' -DPACKAGE='bash' -DSHELL 
-DHAVE_CONFIG_H   -I.  -I../. -I.././include -I.././lib  -Wdate-time 
-D_FORTIFY_SOURCE=2 -g -O2 -fstack-protector-strong -Wformat 
-Werror=format-security -Wall -no-pie -Wno-parentheses -Wno-format-security
uname output: Linux -- CENSORED for security reasons!
Machine Type: x86_64-pc-linux-gnu

Bash Version: 4.4
Patch Level: 12
Release Status: release

Description:
  See `help declare`:
> -l  to convert NAMEs to lower case on assignment
> -u  to convert NAMEs to upper case on assignment

Is translated in German locale to:

> -l  Konvertiert die Variabennmamen in Kleinbuchstaben.
> -u  Konvertiert die Variablennamen in Großbuchstaben.

Translating this back to English is:
> -l  Converts the name of the variable to lowercase characters.
> -u  Converts the name of the variable to uppercase characters.

Fix:

Use the following text:
> -l to convert the content of NAMEs to lowercase characters
> -l to convert the content of NAMEs to uppercase characters

Check all supported languages for similar buggy translations.