[Top][All Lists]

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

Re: Bug where SIGINT trap handler isn't called

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.

Attachment: run-until-end-of-loop.sh
Description: application/shellscript

Attachment: start-subst-loop.sh
Description: application/shellscript

Attachment: execute-with-sigint.py
Description: Text Data

Attachment: subst-loop.sh
Description: application/shellscript

reply via email to

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