stank
stank copied to clipboard
trap considered harmful
We could implement a crude, multiline regex scanner to warn on the use of traps in concert with exec, which presents a hazard. The script author should be made aware that traps do not persist into exec environments.
Related: https://github.com/koalaman/shellcheck/issues/2631
Frankly, trap is such an unwieldy tool that we may even recommend against writing reusable traps and recommend instead the use of <failable command> || <backup command> and/or if [ ! <failable command> ]; then ... fi.
Instead of subshells, the script author can redirect output to a file, then read the file back.
Sadly, the simple die / panic command is unavailable in most shells.
Another hazard of traps is that many authors forget to implement them for conditions other than EXIT. Ultimately, it may be prudent to recommend rewriting a script with any traps, in a more competent application language such as Go or Ruby. We can then use a simple, single line regex to scan for uncommented arbitrary indentation, trap commands.
Note the more common interpolated subshells "$(...)" and backticks, whose failure may not trigger the desired traps.
Note that zsh function traps still present a conflict with exec, and require a separate, multiline regex to detect. (Though two single line regexes used in tandem will be more efficient.)
That leaves parenthesis subshells as the last trigger for warnings, when not prefixed by a string interpolation dollar sign. That includes nested subshells within larger string interpolation. Anyway, subshells should trigger warnings when list traps are used, unless the interpreter is zsh, or bash with set -E enabled.
POSIX sh traps do not persist across subshell boundaries.
bash traps can persist if set -E is enabled.
zsh function traps persist but not classic list traps.
ash and dash: -E indicates the Emacs text editor. Traps do not persist across subshell boundaries.
posh: Traps do not persist across subshell boundaries.
ksh: Traps do not persist across subshell boundaries.
mksh, oksh, pdksh, rksh: Missing functionality for the ERR, EXIT, and DEBUG signals. Traps do not persist across subshell boundaries.
Thompson sh, tsh, etsh: No documented support for traps.
yash: Traps do not persist across subshells.
lksh: Unknown trap, subshell support. Predates bash. Implementation retrofitted using mksh. No interactive support. Traps do not persist across subshell boundaries.
fish, ion, PowerShell: Lack of scoped subshells, although command interpolated incidental subshells may be available. Traps may not persist across interpolated incidental subshell boundaries.
ion appears to lack traps for error and exit signals.
Not POSIX, but noting for posterity.
Note also that the ERR is not a POSIX signal for use when configuring traps.
https://www.shellcheck.net/wiki/SC3047
Note that interpolated strings (both dollar paren and backtick) introduce subshells, but not arithmetic expressions.
Note that a pipe also creates a subshell.
Unknown whether the three operators ;, && and/or || technically create subshells or not.
Ditching checking for subshells entirely. A modern shell script of medium size is very likely to invoke a subshell, so we might as well warn for traps regardless.
For non-bash, non-zsh shells, we simply warn that any and all traps are reset in subshells. Rather than document an exhaustive list of alternatives, we leave it to the user to decide how to resolve this. Bash and zsh get more specific warnings, due to their ability to enable certain trap safety features.
Reopening.
Plan to mark all classic POSIX traps as risky due to implicit reset behavior.