|
From: | Patrick Plagwitz |
Subject: | Re: Bug where SIGINT trap handler isn't called |
Date: | Thu, 16 Jul 2015 06:05:24 +0200 |
User-agent: | Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.0.1 |
On 30/06/15 02:27, Chet Ramey wrote: > On 6/29/15 3:41 PM, Patrick Plagwitz wrote: > >> Bash Version: 4.3 >> Patch Level: 39 >> Release Status: release >> >> Description: >> There's a bug that happens when waiting for a child process to complete >> (via wait_for in jobs.c) that isn't part of a job, like command >> substitution subshells. If a SIGINT is caught by the >> wait_sigint_handler, the handler sets the wait_sigint_received flag >> which is checked in set_job_status_and_cleanup. But >> set_job_status_and_cleanup is called from waitchld only if the pid >> belongs to a process that is part of a job. The result is that a SIGINT >> trap, if it exists, is not called if a SIGINT is received while waiting >> for a comsub subshell. > > This isn't exactly correct. The SIGINT trap will be called if the process > in the command substitution exits due to SIGINT. For instance, if you > change the assignment to something like: > > foo=$(sleep 20 >&- ) > or > foo=$(exec 2>&- ; sleep 20) > > both of which I think correctly reproduce the python command, the SIGINT > trap will execute. > > This is another case of the scenario most recently described in > > http://lists.gnu.org/archive/html/bug-bash/2014-03/msg00108.html > > In this case, python appears to catch the SIGINT (it looks like a > KeyboardInterrupt exception), print the message, and exit with status 1. > > Chet > Ok, I see. However, there appears to be some race condition when waiting for a command substitution. I have the attached combination of scripts. When run with $ bash run-until-end-of-loop.sh bash start-subst-loop.sh '2>/dev/null' , the script will try to launch and SIGINT subst-loop.sh repeatedly until the SIGINT trap is once *not* called which will happen in at most 200 repetitions on my machine. The script then ends after printing “end of loop”. The python script execute-with-sigint.py is only there to enable subst-loop.sh to receive a SIGINT at all. subst-loop.sh calls date(1) in a loop; date should have SIGINT set to SIG_DFL other than python initially. I analyzed the execution by inserting some debug output into the bash code. It seems that in the case that the SIGINT trap is not called subst-loop.sh gets the SIGINT while (or shortly before or after) calling waitpid in waitchld:jobs.c which will then return without errno == EINTR. The wait_sigint_handler will be called, though, and so wait_sigint_received will be true. If you try the script often enough, it will sometimes block. I saw that this is because wait_sigint_handler calls itself in an infinite loop. If I understand it correctly, this happens since wait_for:jobs.c calls old_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler); and if a SIGINT is caught after sigaction in set_signal_handler was called but before old_sigint_handler is set, restore_sigint_handler (); kill (getpid (), SIGINT); in wait_sigint_handler will leave wait_sigint_handler as handler.
run-until-end-of-loop.sh
Description: application/shellscript
start-subst-loop.sh
Description: application/shellscript
execute-with-sigint.py
Description: Text Data
subst-loop.sh
Description: application/shellscript
[Prev in Thread] | Current Thread | [Next in Thread] |