* Differences between "TRAPERR()" and "trap foo ERR"
@ 2021-07-28 3:47 Zach Riggle
2021-07-28 5:00 ` Bart Schaefer
0 siblings, 1 reply; 3+ messages in thread
From: Zach Riggle @ 2021-07-28 3:47 UTC (permalink / raw)
To: zsh-users
--------------------------------- BACKGROUND ---------------------------------
I've discovered some undocumented behavior of TRAPNAL functions, and
some divergence of behavior between TRAPNAL and "trap foo NAL".
Specifically, the former receives a $1 with the value of the signal
which invoked the routine, but the latter does not -- and that value
is the actual value of the signal (e.g. $1 == SIGSEGV == 11 for
TRAPSEGV).
For example, TRAPERR receives a value of 32, which is not a valid
signal value on my system (NSIG==32).
When setting via "trap 'my_trapfunc $@' SEGV", no argument is provided
to 'my_trapfunc'.
All of this is on ZSH v5.8.
---------------------------------- EXAMPLES ----------------------------------
So I've got two scripts, traperr and trapfunc.
$ cat traperr
#!/usr/bin/env zsh
TRAPERR() {
echo "Got ${(q-)@}"
}
false
$ cat trapfunc
#!/usr/bin/env zsh
trap_err() {
echo "Got ${(q-)@}"
}
trap trap_err ERR
false
Note that "traperr" declares an all-caps TRAPERR. "trapfunc" instead
uses the "trap" command to set the ERR trap.
Both generally work as expected, but the former ("TRAPERR") receives
an argument in "$1" that is undocumented.
$ ./traperr
Got 32
$ ./trapfunc
Got
------------------------------- DOCUMENTATION --------------------------------
I looked at the manual page (section 9.3.1) for trap functions:
https://zsh.sourceforge.io/Doc/Release/Functions.html#Trap-Functions
However, there's nothing mentioned about any parameters being
specified to TRAPNAL functions, and it generally seems that "TRAPNAL"
and "trap foo NAL" behave the same.
------------------------------ EXPERIMENTATION -------------------------------
At first, I thought the provenance of the value 32 comes from the
value of NSIG on my system (which on macOS is 32).
$ cat nsig.c
#include <stdio.h>
#include <signal.h>
int main() {
printf("NSIG = %d\n", NSIG);
}
$ gcc -o nsig nsig.c
$ ./nsig
NSIG = 32
Second, I thought that perhaps it might come from ZSH's own list of
signals. There is a ZERR entry, in any case.
$ echo $signals
EXIT HUP ... ZERR DEBUG
$ for i in {0..${#signals}}; do echo "$i: ${signals[$i]}"; done
0:
1: EXIT
2: HUP
...
31: USR1
32: USR2
33: ZERR
34: DEBUG
As we can see here, the value received by "33: ZERR", is not the 32'th
entry in the list of $signals. Since ZSH array indices start at 1,
this makes more sense and getting "32" for ZERR, is correct.
This is confirmed by setting e.g. TRAPSEGV, where SIGSEGV==11.
$ cat trapsegv
#!/usr/bin/env zsh
TRAPSEGV() {
echo "Got ${(q-)@}"
}
kill -s SEGV $$
$ ./trapsegv
Got 11
So we are receiving the actual value of the signal, when we declare a
TRAPNAL function. This corresponds to the NAL+1'th offset in the
$signals array.
--------------------- ATTEMPT TO CONVERGE FUNCTIONALITY ----------------------
Since arguments are being provided to TRAPNAL functions, I thought I
would try to modify the "trapfunc" script to include its arguments
when invoking trap_err (note the extra $@ inside the trap statement
versus before).
$ cat trapfunc_args
#!/usr/bin/env zsh
trap_err() {
echo "Got ${(q-)@}"
}
trap 'trap_err $@' ERR
false
$ ./trapfunc_args
Got
It seems this does not work to specify the signal number by including
e.g. $@ in the trap command list.
------------------------ CONCLUSION AND OBSERVATIONS -------------------------
Overall, there are two observations.
1. The behavior that TRAPNAL will receive NAL as its first argument,
where NAL corresponds to a the system-defined signal values (e.g.
SIGSEGV == 11). The name for this signal can be gotten from
${signals[x+1]}. This should be documented.
2. This behavior does not expand to "trap func NAL" statements, even
if we try to pass "$@" to some function. This seems like a bug.
Am I missing something in the docs (quite likely) -- and is the
behavior difference intended -- or are these bugs.
Thanks for reading!
Zach Riggle
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: Differences between "TRAPERR()" and "trap foo ERR"
2021-07-28 3:47 Differences between "TRAPERR()" and "trap foo ERR" Zach Riggle
@ 2021-07-28 5:00 ` Bart Schaefer
2021-07-28 5:04 ` Zach Riggle
0 siblings, 1 reply; 3+ messages in thread
From: Bart Schaefer @ 2021-07-28 5:00 UTC (permalink / raw)
To: Zach Riggle; +Cc: Zsh Users
On Tue, Jul 27, 2021 at 8:47 PM Zach Riggle <zachriggle@gmail.com> wrote:
>
> Overall, there are two observations.
>
> 1. The behavior that TRAPNAL will receive NAL as its first argument,
> where NAL corresponds to a the system-defined signal values (e.g.
> SIGSEGV == 11). The name for this signal can be gotten from
> ${signals[x+1]}. This should be documented.
9.3.2 Trap Functions:
TRAPNAL
If defined and non-null, this function will be executed whenever
the shell catches a signal SIGNAL, where NAL is a signal name as
specified for the kill builtin. The signal number will be passed
as the first parameter to the function.
> 2. This behavior does not expand to "trap func NAL" statements, even
> if we try to pass "$@" to some function. This seems like a bug.
It's not a bug; it's the normal behavior of the "trap" in the shell
language. The TRAPnal form and the argument it receives are a zsh
extension.
The "trap" builtin takes an arbitrary list of commands rather than a
function body. There is therefore no "argument list" where the signal
number can be passed. If you write
trap 'echo in a trap' USR2
functions
you will see that there is no TRAPUSR2 function created. "unfunction
TRAPUSR2" removes the USR2 trap as a side-effect, but also complains
"no such hash table element". That's a bit of an oddity, but is in
part why the doc for the "trap" builtin says:
Defining a trap under either name causes any trap under an
alternative name to be removed. However, it is recommended that
for consistency users stick exclusively to one name or another.
Other distinctions considered important are also mentioned there:
Note that traps defined with the trap builtin are slightly
different from those defined as 'TRAPNAL () { ... }', as the
latter have their own function environment (line numbers, local
variables, etc.) while the former use the environment of the
command in which they were called. For example,
trap 'print $LINENO' DEBUG
will print the line number of a command executed after it has run,
while
TRAPDEBUG() { print $LINENO; }
will always print the number zero.
You might also read about the POSIX_TRAPS and LOCAL_TRAPS setopts.
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: Differences between "TRAPERR()" and "trap foo ERR"
2021-07-28 5:00 ` Bart Schaefer
@ 2021-07-28 5:04 ` Zach Riggle
0 siblings, 0 replies; 3+ messages in thread
From: Zach Riggle @ 2021-07-28 5:04 UTC (permalink / raw)
To: Bart Schaefer; +Cc: Zsh Users
Thanks for the quick response, Bart!
> The signal number will be passed as the first parameter to the function.
Wow, I am dense and poor at reading documentation. Thanks for
pointing out the relevant portion to me.
> The TRAPnal form and the argument it receives are a zsh extension.
Welp, that explains the rest of it!
> You might also read about the POSIX_TRAPS and LOCAL_TRAPS setopts.
Thanks, I will definitely look up the docs for this.
Humbled and appreciative,
Zach Riggle
On Wed, Jul 28, 2021 at 12:00 AM Bart Schaefer
<schaefer@brasslantern.com> wrote:
>
> On Tue, Jul 27, 2021 at 8:47 PM Zach Riggle <zachriggle@gmail.com> wrote:
> >
> > Overall, there are two observations.
> >
> > 1. The behavior that TRAPNAL will receive NAL as its first argument,
> > where NAL corresponds to a the system-defined signal values (e.g.
> > SIGSEGV == 11). The name for this signal can be gotten from
> > ${signals[x+1]}. This should be documented.
>
> 9.3.2 Trap Functions:
>
> TRAPNAL
> If defined and non-null, this function will be executed whenever
> the shell catches a signal SIGNAL, where NAL is a signal name as
> specified for the kill builtin. The signal number will be passed
> as the first parameter to the function.
>
> > 2. This behavior does not expand to "trap func NAL" statements, even
> > if we try to pass "$@" to some function. This seems like a bug.
>
> It's not a bug; it's the normal behavior of the "trap" in the shell
> language. The TRAPnal form and the argument it receives are a zsh
> extension.
>
> The "trap" builtin takes an arbitrary list of commands rather than a
> function body. There is therefore no "argument list" where the signal
> number can be passed. If you write
>
> trap 'echo in a trap' USR2
> functions
>
> you will see that there is no TRAPUSR2 function created. "unfunction
> TRAPUSR2" removes the USR2 trap as a side-effect, but also complains
> "no such hash table element". That's a bit of an oddity, but is in
> part why the doc for the "trap" builtin says:
>
> Defining a trap under either name causes any trap under an
> alternative name to be removed. However, it is recommended that
> for consistency users stick exclusively to one name or another.
>
> Other distinctions considered important are also mentioned there:
>
> Note that traps defined with the trap builtin are slightly
> different from those defined as 'TRAPNAL () { ... }', as the
> latter have their own function environment (line numbers, local
> variables, etc.) while the former use the environment of the
> command in which they were called. For example,
>
> trap 'print $LINENO' DEBUG
>
> will print the line number of a command executed after it has run,
> while
>
> TRAPDEBUG() { print $LINENO; }
>
> will always print the number zero.
>
> You might also read about the POSIX_TRAPS and LOCAL_TRAPS setopts.
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2021-07-28 5:06 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-28 3:47 Differences between "TRAPERR()" and "trap foo ERR" Zach Riggle
2021-07-28 5:00 ` Bart Schaefer
2021-07-28 5:04 ` Zach Riggle
Code repositories for project(s) associated with this public inbox
https://git.vuxu.org/mirror/zsh/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).