Configuration Information [Automatically generated, do not change]:
Machine: x86_64
OS: linux-gnu
Compiler: gcc
Compilation CFLAGS: -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -fexceptions         -Wp,-D_FORTIFY_SOURCE=3 -Wformat -Werror=format-security         -fstack-clash-protection -fcf-protection         -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -g -ffile-prefix-map=/build/bash/src=/usr/src/debug/bash -flto=auto -DDEFAULT_PATH_VALUE='/usr/local/sbin:/usr/local/bin:/usr/bin' -DSTANDARD_UTILS_PATH='/usr/bin' -DSYS_BASHRC='/etc/bash.bashrc' -DSYS_BASH_LOGOUT='/etc/bash.bash_logout' -DNON_INTERACTIVE_LOGIN_SHELLS -std=gnu17 uname output: Linux ben-laptop 6.18.9-arch1-2 #1 SMP PREEMPT_DYNAMIC Mon, 09 Feb 2026 17:16:33 +0000 x86_64 GNU/Linux
Machine Type: x86_64-pc-linux-gnu

Bash Version: 5.3
Patch Level: 9
Release Status: release

Description:
    In the following script, we create a subshell that traps SIGINT and SIGTERM     and then uses setsid to run sleep    in a separate process group. We then wait     for sleep to finish (note setsid won't fork and immediately exit because job     control isn't inherited by the subshell so it doesn't start out as a process     group leader, instead it just calls setsid and execs sleep). We now have     sleep running as a child of the subshell as a process group leader. However     in certain, somewhat contrived, circumstances, bash's builtin kill will send     the signal to the WRONG process group. See the following strace output when
    running the script below:

    > Sending SIGTERM to process group: 5710 (kill -TERM -5710)
    [pid  5709] kill(-5709, SIGTERM)        = 0

    As you can see we ran `kill -TERM -5710`, but bash actually sent it to
    process group 5709 (the subshell itself). If you don't use the builtin kill     then it works as expected (note the syntax for killing process groups with     kill binaries seems to vary a lot. It seems like with procps-ng kill you need
    to do    `/bin/kill -TERM -- -PGID` instead)

    I also tested the following script with Dash/BusyBox/Zsh and it worked
    correctly. However it misbehaves in every version of Bash that I tested
    (POSIX mode or otherwise).

Repeat-By:
    Here is the script to reproduce the issue:

    #!/usr/bin/env sh
    set -u

    # Only happens with job control enabled
    set -m

    (
      echo "> In subshell"
      trap 'echo "> SIGTERM received in subshell SHOULD NOT HAPPEN!"' TERM
      trap 'echo "> SIGINT received in subshell"' INT

      setsid sleep 10 &
      pid=$!
      echo "> Started new process group $pid"
      # Wait for for sleep, SIGINT from main process will interrupt this
      wait "$pid"
      echo "> Sending SIGTERM to process group: $pid (kill -TERM -$pid)"
      kill -TERM -$pid
      wait "$pid"
    ) &
    subshell_pid=$!
    echo "Subshell pid $subshell_pid"

    sleep 5
    echo "Sending SIGINT to subshell $subshell_pid"
    kill -INT "$subshell_pid"
    wait "$subshell_pid"


Reply via email to