bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bash signal during wait + read causes unkillable 100% CPU usage


From: hackerb9
Subject: bash signal during wait + read causes unkillable 100% CPU usage
Date: Sun, 16 Sep 2018 20:47:09 -0700 (PDT)

Configuration Information [Automatically generated, do not change]:
Machine: i686
OS: linux-gnu
Compiler: gcc
Compilation CFLAGS:  -DPROGRAM='bash' -DCONF_HOSTTYPE='i686' 
-DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='i686-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 -fdebug-prefix-map=/build/bash-u3hlEB/bash-4.4.18=. 
-fstack-protector-strong -Wformat -Werror=format-security -Wall 
-Wno-parentheses -Wno-format-security
uname output: Linux thomas 4.18.0-7-generic #8-Ubuntu SMP Tue Aug 28 18:22:50 
UTC 2018 i686 i686 i686 GNU/Linux
Machine Type: i686-pc-linux-gnu

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

Description:

I was trying to work around the problem of bash not being able to
cancel the read builtin command when a signal comes in and I stumbled
upon this (perhaps unrelated) bug. I'm not sure exactly what's going
on but I have a simple script that demonstrates the problem.

Repeat-By:

Run the following script. Quickly hit a key, then wait to be prompted
to hit Control C. When you hit Control C, the process should stop
responding and your CPU usage should go to 100%. The HUP, TERM and
QUIT signals are ignored.

----- 8< ----- 8< ----- 8< ----- CUT HERE ----- 8< ----- 8< ----- 8< ----- 
#!/bin/bash

trap cleanup EXIT
cleanup() {
    echo "Huh. There was supposed to be an earth-shattering kaboom."
    echo "The bug wasn't triggered. Did you hit the first key quickly?"
    echo "Or, perhaps Bash $BASH_VERSION isn't buggy?"
    echo "This test was designed for Bash 4.4.19(1) on Ubuntu Cosmic 
Cuttlefish."
}

trap huphandler SIGHUP
huphandler() {
    # This handler doesn't actually do anything.
    # The important thing is that HUP interrupts the wait.
    return
}

# Send a SIGHUP to ourselves to interrupt the wait and start "read".
(sleep 2;  kill -1 $$; sleep 2; echo -e "\nB: Now try ^C and see what breaks.") 
&

echo "A: Quickly press a key before part B! "
while true; do
    wait
    read -p "Kaboom? " -n1
    echo 
done
----- 8< ----- 8< ----- 8< ----- CUT HERE ----- 8< ----- 8< ----- 8< ----- 


I tried attaching to the process with GDB. The backtrace showed it
being in jobs.c:wait_sigint_handler() or zread.c:zread(). This may be
a red herring, but there is a comment in zread.c with an XXX and a
question that may be worth investigating:

60            check_signals_and_traps ();       /* XXX - should it be 
check_signals()? */

Here is a more extensive log of what gdb said:

$ gdb -p 27088
Attaching to process 27088
Reading symbols from /src/bash-4.4.18/bash...done.
Reading symbols from /lib/i386-linux-gnu/libtinfo.so.6...(no debugging symbols 
found)...done.
Reading symbols from /lib/i386-linux-gnu/libdl.so.2...Reading symbols from 
/usr/lib/debug//lib/i386-linux-gnu/libdl-2.28.so...done.
done.
Reading symbols from /lib/i386-linux-gnu/libc.so.6...Reading symbols from 
/usr/lib/debug//lib/i386-linux-gnu/libc-2.28.so...done.
done.
Reading symbols from /lib/ld-linux.so.2...Reading symbols from 
/usr/lib/debug//lib/i386-linux-gnu/ld-2.28.so...done.
done.

wait_sigint_handler (sig=2) at jobs.c:2476
2476      if (interrupt_immediately ||

(gdb) list
2471    wait_sigint_handler (sig)
2472         int sig;
2473    {
2474      SigHandler *sigint_handler;
2475
2476      if (interrupt_immediately ||
2477          (this_shell_builtin && this_shell_builtin == wait_builtin))
2478        {
2479          last_command_exit_value = 128+SIGINT;
2480          restore_sigint_handler ();
2481          /* If we got a SIGINT while in `wait', and SIGINT is trapped, do
2482             what POSIX.2 says (see builtins/wait.def for more info). */
2483          if (this_shell_builtin && this_shell_builtin == wait_builtin &&
2484              signal_is_trapped (SIGINT) &&
2485              ((sigint_handler = trap_to_sighandler (SIGINT)) == 
trap_handler))
2486            {
2487              trap_handler (SIGINT);        /* set pending_traps[SIGINT] */
2488              wait_signal_received = SIGINT;
2489              if (interrupt_immediately && wait_intr_flag)
2490                {
(gdb) bt
#0  wait_sigint_handler (sig=2) at jobs.c:2476
#1  <signal handler called>
#2  0xb7f09d41 in __kernel_vsyscall ()
#3  0xb7dbc5a7 in __GI___libc_read (fd=0, buf=0xbf956a56, nbytes=1)
    at ../sysdeps/unix/sysv/linux/read.c:26
#4  0x0052dce1 in read (__nbytes=1, __buf=0xbf956a56, __fd=0)
    at /usr/include/i386-linux-gnu/bits/unistd.h:44
#5  zread (fd=0, buf=0xbf956a56 "V", len=1) at zread.c:56
#6  0x00519c23 in read_builtin (list=0x0) at ./read.def:585
#7  0x004bacc0 in execute_builtin (
    builtin=builtin@entry=0x519360 <read_builtin>, flags=flags@entry=0, 
    subshell=0, words=<optimized out>) at execute_cmd.c:4535
#8  0x004bd75a in execute_builtin_or_function (flags=<optimized out>, 
    fds_to_close=<optimized out>, redirects=<optimized out>, var=0x0, 
    builtin=0x519360 <read_builtin>, words=0x13367c8) at execute_cmd.c:5028
#9  execute_simple_command (simple_command=<optimized out>, 
    pipe_in=<optimized out>, pipe_in@entry=-1, pipe_out=<optimized out>, 
    pipe_out@entry=-1, async=0, fds_to_close=0x1335f68) at execute_cmd.c:4330
#10 0x004bf0e6 in execute_command_internal (command=0x1333be8, 
    asynchronous=<optimized out>, pipe_in=<optimized out>, 
    pipe_out=<optimized out>, fds_to_close=<optimized out>)
    at execute_cmd.c:807
#11 0x004bfb6f in execute_connection (fds_to_close=0x1335f68, 
    pipe_out=<optimized out>, pipe_in=<optimized out>, 
    asynchronous=<optimized out>, command=<optimized out>) at execute_cmd.c:2600
#12 execute_command_internal (command=<optimized out>, asynchronous=<optimized 
out>, pipe_in=<optimized out>, pipe_out=<optimized out>, 
fds_to_close=<optimized out>) at execute_cmd.c:976
#13 0x004c0ba4 in execute_command (command=0x13325a8) at execute_cmd.c:405
#14 0x004bfb28 in execute_connection (fds_to_close=0x1333de8, 
pipe_out=<optimized out>, pipe_in=<optimized out>, asynchronous=<optimized 
out>, command=<optimized out>) at execute_cmd.c:2598
#15 execute_command_internal (command=<optimized out>, asynchronous=<optimized 
out>, pipe_in=<optimized out>, pipe_out=<optimized out>, 
fds_to_close=0x1333de8) at execute_cmd.c:976
#16 0x004c0ba4 in execute_command (command=0x1332aa8) at execute_cmd.c:405
#17 0x004c0ccb in execute_while_or_until (while_command=0x1332a28, 
type=type@entry=0) at execute_cmd.c:3515
#18 0x004be819 in execute_while_command (while_command=<optimized out>) at 
execute_cmd.c:3456
#19 execute_command_internal (command=0x13326e8, asynchronous=<optimized out>, 
pipe_in=<optimized out>, pipe_out=<optimized out>, fds_to_close=0x1332748) at 
execute_cmd.c:916
#20 0x004c0ba4 in execute_command (command=0x13326e8) at execute_cmd.c:405
#21 0x004a617e in reader_loop () at eval.c:180
#22 0x004a42b5 in main (argc=<optimized out>, argv=<optimized out>, 
env=<optimized out>) at shell.c:792

(gdb)  c
Continuing.
Program received signal SIGINT, Interrupt.
0xb7f09d41 in __kernel_vsyscall ()
(gdb) up
#1  0xb7dbc5a7 in __GI___libc_read (fd=0, buf=0xbf956a56, nbytes=1)
    at ../sysdeps/unix/sysv/linux/read.c:26
26      ../sysdeps/unix/sysv/linux/read.c: No such file or directory.
(gdb) up
#2  0x0052dce1 in read (__nbytes=1, __buf=0xbf956a56, __fd=0)
    at /usr/include/i386-linux-gnu/bits/unistd.h:44
44        return __read_alias (__fd, __buf, __nbytes);
(gdb) up
#3  zread (fd=0, buf=0xbf956a56 "V", len=1) at zread.c:56
56        while ((r = read (fd, buf, len)) < 0 && errno == EINTR)
(gdb) list
51           char *buf;
52           size_t len;
53      {
54        ssize_t r;
55
56        while ((r = read (fd, buf, len)) < 0 && errno == EINTR)
57          /* XXX - bash-5.0 */
58          /* We check executing_builtin and run traps here for backwards 
compatibility */
59          if (executing_builtin)
60            check_signals_and_traps ();       /* XXX - should it be 
check_signals()? */
61          else
62            check_signals ();
63
64        return r;
65      }



reply via email to

[Prev in Thread] Current Thread [Next in Thread]