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 }