[Top][All Lists]

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

Re: Signal ignore flags unexpectedly reset after "trap ... EXIT"

From: Chet Ramey
Subject: Re: Signal ignore flags unexpectedly reset after "trap ... EXIT"
Date: Wed, 16 Oct 2019 09:36:35 -0400
User-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:60.0) Gecko/20100101 Thunderbird/60.9.0

On 10/15/19 5:22 AM, Isaac To wrote:

> Bash Version: 5.0
> Patch Level: 3
> Release Status: release
> Description:
> When trying to write a program and start it in an initrc script, I observed
> a strange behavior: if a subshell is started by a subshell of that script,
> and the inner subshell runs "trap ... EXIT", it unsets the signal ignore
> flag of other signals.  I'm not sure whether this should be called a bug,
> or whether it is a problem caused by my own configuration.  Anyway here is
> how I reproduce my problem.

OK, let's go through what happens to signals when you run this.

> $ cat t.sh
> echo t $BASHPID
> trap '' USR1

This bash process, lets say pid 806, sets the disposition of SIGUSR1 to

> grep SigIgn /proc/$BASHPID/status

Presumably this reflects it; I don't know how to interpret the output.

> bash --rcfile t2.sh

You start an interactive shell, say pid 809. This means that the shell
remembers that SIGUSR1 was ignored when it started but sets the handler
to a fatal signal catcher function. It will set the disposition to SIG_IGN
in a child proess immediately after it forks. This means, for instance,
that the greps run with SIGUSR1 set to SIG_IGN.

The other thing an interactive shell does is catch all fatal signals so it
can clean up. This means that a subshell has to undo this by setting all
these signals to SIG_DFL when it starts.

Since this shell is interactive, all subshells it runs know they are
children of an interactive shell.

> $ cat t2.sh
> echo t2 $BASHPID
> grep SigIgn /proc/$BASHPID/status

This gives you the normal set of ignored signals for an interactive shell:
SIGQUIT/SIGTSTP/SIGTTOU/SIGTTIN. SIGUSR1, a fatal signal, is caught.

> (
>     echo subshell $BASHPID
>     grep SigIgn /proc/$BASHPID/status

After setting all the caught signals back to SIG_DFL, this shell, call it
pid 811, sets SIGUSR1 to SIG_IGN, since that is the disposition it had when
its parent was started. This happens before pretty much anything else.

Bash will install signal handlers for everything it needs to catch, and,
since this is still an interactive shell, it will catch signals that are
ignored when it starts. It does this lazily -- when it needs to do
something with signal handlers. This turns out to matter; see below.

>     (
>         echo subsubshell $BASHPID

Let's say this process has pid 813. In this subshell, there shouldn't be
any ignored signals after the shell initializes (it's interactive), but it
does this lazily.

This is probably where the confusion arises. It's arguably a bug that bash
doesn't change the signals to caught right away.

>         grep SigIgn /proc/$BASHPID/status

>         echo trap $BASHPID
>         trap 'echo hello' EXIT

When the exit trap is installed, bash needs to install handlers for all the
fatal signals, so it can run the exit trap (if possible) if it receives
one. Since it's an interactive shell, it installs handlers for everything,
even signals, like SIGUSR1, that were ignored when the shell started. Once
it's done that, there are no longer any ignored signals.

> Note that the final SigIgn flag is completely reset, which is what I won't
> expect.  The same problem won't occur if --rcfile is not used in t.sh.  And
> the problem also didn't show up in bash 4.4.

I get exactly the same results in bash-4.4 running on RHEL7.

``The lyf so short, the craft so long to lerne.'' - Chaucer
                 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU    address@hidden    http://tiswww.cwru.edu/~chet/

reply via email to

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