Skip to content

trap -p omits signals ignored at shell entry, failing OS target tests on six distros #6

Description

@cataggar

Summary

trap -p omits signals that were already ignored (SIG_IGN) when the shell started. bash reports these as trap -- '' SIGNAME; brush prints nothing for them.

This is what makes the OS target tests matrix red. All six containers (Arch, Azure Linux 4.0, Debian testing, Fedora, NixOS, openSUSE Tumbleweed) fail on exactly one case, [trap -p - with no args shows all traps], and always with the same diff:

      stdout DIFFERS:
          ------ Oracle <> Test: stdout ---------------------------------
          - trap -- '' SIGRTMIN
            trap -- 'echo a' SIGINT
            trap -- 'echo b' SIGTERM
            trap -- 'echo c' EXIT

Those containers start the shell with SIGRTMIN inherited as ignored — glibc/systemd reserve the first real-time signals — so the distro bash acting as oracle lists it and brush does not.

job ran succeeded failed
Arch Linux 2189 1809 1
Azure Linux 4.0 2185 1805 1
Debian testing 2189 1809 1
Fedora 2187 1807 1
NixOS 2187 1807 1
openSUSE Tumbleweed 2188 1808 1

The Ubuntu-based Test (linux/*) jobs pass because nothing ignores SIGRTMIN there, so the missing line never appears in the oracle's output.

Not actually about SIGRTMIN

The real-time signal is incidental. The same gap reproduces with an ordinary signal — ignore it in a parent and inspect the child:

$ bash -c "trap '' SIGUSR1; exec bash  -c 'trap -p'"
trap -- '' SIGUSR1

$ bash -c "trap '' SIGUSR1; exec brush -c 'trap -p'"
             # nothing

So this is "brush does not track signals ignored at entry", not "brush lacks SIGRTMIN".

Three separable gaps

Splitting these out because only the first is needed to turn CI green, and they can land independently.

1. Signals ignored at entry are not recorded or reported. Shown above. This alone is what the failing test observes.

2. Signals ignored at entry are not protected from being trapped. POSIX and bash both hold that a signal ignored on entry to the shell cannot be trapped or reset — bash silently declines, brush installs the handler:

$ bash -c "trap '' SIGUSR1; exec bash  -c \"trap 'echo caught' SIGUSR1; trap -p\""
trap -- '' SIGUSR1              # refused; still ignored

$ bash -c "trap '' SIGUSR1; exec brush -c \"trap 'echo caught' SIGUSR1; trap -p\""
trap -- 'echo caught' SIGUSR1   # accepted

This one has practical consequences beyond trap -p output: a script run under nohup, or from a supervisor that ignores a signal, can install a handler in brush that bash would have refused, so the two shells genuinely behave differently at runtime.

3. Real-time signals are not known at all. SIGRTMIN, SIGRTMAX, the SIGRTMIN+n/SIGRTMAX-n forms, and the corresponding numbers are all rejected:

$ brush -c "trap 'echo x' SIGRTMIN"
error: trap: SIGRTMIN: invalid signal specification    # exit 1
$ brush -c "trap 'echo x' 34"
error: trap: 34: invalid signal specification          # exit 1

kill -l agrees — comparing the name sets, brush is missing exactly 31 entries and has no spurious ones:

SIGRTMIN SIGRTMIN+1 .. SIGRTMIN+15  SIGRTMAX SIGRTMAX-1 .. SIGRTMAX-14

(31 names in bash's list, 62 total vs brush's 31.) Worth noting these are Linux-specific and the SIGRTMIN+n names are relative to a value that varies by libc, so this is the least portable of the three and probably wants to be #[cfg]-gated.

Suggested fix for (1)

At startup, query the disposition of each known signal and record the ones already set to SIG_IGN, so trap -p can report them. On unix, sigaction(2) with a null action reads the current handler without installing one. That is enough to make the six OS target tests jobs green; (2) and (3) can follow separately.

Reproducing without a container

$ bash -c "trap '' SIGUSR1; exec brush -c 'trap -p'"     # expect: trap -- '' SIGUSR1

Found while running a ~95k-line real-world bash script under brush. Not a blocker for that work — filing it because it is currently the only thing standing between the OS target tests matrix and green, and it was initially easy to mistake for a CI infrastructure problem.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions