I am working with a large Bash code base where most scripts disable job control 
and the DEBUG trap is used extensively. I noticed that if I tried to run my 
scripts in the background, the interactive shell that started them would 
immediately exit on any keyboard input. A simple repro is to run

bash +m -c "/bin/echo ; trap 'trap DEBUG' DEBUG ; sleep 10" &
in an interactive shell with job control enabled. Hit Enter a few times. The 
shell that launched this background process exits. The background process 
itself appears to be killed by a signal. I was able to repro this with and 
under Bash-5.2.21 and 5.1.16 on Ubuntu 22.04.4, and with Bash-5.2.15 on MacOS.

The problem seems to be triggered by the following code in run_debug_trap():
if (pipeline_pgrp > 0 && ((subshell_environment & 
(SUBSHELL_ASYNC|SUBSHELL_PIPE)) == 0))
    give_terminal_to (pipeline_pgrp, 1);

give_terminal_to() calls tcsetpgrp (shell_tty, pgrp), which places the calling 
process in the foreground without the parent shell's knowledge. Since the 
parent shell's process group is no longer in the foreground, I suspect it 
receives an EIO from a read(2) and exits, although I was not able to confirm 
this with strace.
In my repro pipeline_pgrp is non-zero at the time of DEBUG trap execution. gdb 
shows that it was set to shell_pgrp in make_child() that forked /bin/echo 
without job control (+m). The other condition of the if statement is also 
satisfied.

-Mark

Reply via email to