diff options
author | David Mitchell <davem@iabyn.com> | 2019-11-11 16:06:26 +0000 |
---|---|---|
committer | David Mitchell <davem@iabyn.com> | 2019-11-18 09:34:40 +0000 |
commit | 19c9c2ee4a859f540f01b8d5592fd27d3fbfb253 (patch) | |
tree | e280456e2d95a909487e123b98ce1eab99444ec4 /ext/POSIX/POSIX.xs | |
parent | dc37125bb824744e1f528311ca37da59913cda7d (diff) | |
download | perl-19c9c2ee4a859f540f01b8d5592fd27d3fbfb253.tar.gz |
POSIX::sigaction(): use correct sig handler
Depending on whether sigaction() is called with the SA_SIGINFO flag set,
it should be setting either a 1-arg or 3-arg signal handler for the
kernel to call back. In fact it was always passing a 3-arg handler, and
telling the kernel that it was a 1-arg handler, which means that in
1-arg handler situations, the handler was being called with args 2 and 3
containing random garbage.
Instead, use the newly-added explicit-arg handler functions, which take
the specified number of args regardless of OS / configuration.`
There's a temporary hack included in the patch because perl core is
still claiming to use 3-arg handlers while actually supplying 1-arg
ones. This will be fixed shortly and the hack removed.
Diffstat (limited to 'ext/POSIX/POSIX.xs')
-rw-r--r-- | ext/POSIX/POSIX.xs | 53 |
1 files changed, 39 insertions, 14 deletions
diff --git a/ext/POSIX/POSIX.xs b/ext/POSIX/POSIX.xs index 311ed73c8b..3f7a2aafcf 100644 --- a/ext/POSIX/POSIX.xs +++ b/ext/POSIX/POSIX.xs @@ -3053,6 +3053,8 @@ sigaction(sig, optaction, oldaction = 0) /* Remember old disposition if desired. */ if (oldaction) { + int safe; + svp = hv_fetchs(oldaction, "HANDLER", TRUE); if(!svp) croak("Can't supply an oldaction without a HANDLER"); @@ -3083,24 +3085,51 @@ sigaction(sig, optaction, oldaction = 0) svp = hv_fetchs(oldaction, "FLAGS", TRUE); sv_setiv(*svp, oact.sa_flags); - /* Get back whether the old handler used safe signals. */ + /* Get back whether the old handler used safe signals; + * i.e. it used Perl_csighandler[13] rather than + * Perl_sighandler[13] + */ + safe = ((oact.sa_flags & SA_SIGINFO) + ? ( oact.sa_sigaction == PL_csighandler3p +#ifdef PERL_USE_3ARG_SIGHANDLER + || oact.sa_sigaction == PL_csighandlerp +#endif + ) + : ( oact.sa_handler == PL_csighandler1p + || oact.sa_handler == PL_csighandlerp /* XXX tmp */ +#ifndef PERL_USE_3ARG_SIGHANDLER + || oact.sa_handler == PL_csighandlerp +#endif + ) + ); + svp = hv_fetchs(oldaction, "SAFE", TRUE); - sv_setiv(*svp, - /* compare incompatible pointers by casting to integer */ - PTR2nat(oact.sa_handler) == PTR2nat(PL_csighandlerp)); + sv_setiv(*svp, safe); } if (action) { + int safe; + + /* Set up any desired flags. */ + svp = hv_fetchs(action, "FLAGS", FALSE); + act.sa_flags = svp ? SvIV(*svp) : 0; + /* Safe signals use "csighandler", which vectors through the PL_sighandlerp pointer when it's safe to do so. (BTW, "csighandler" is very different from "sighandler".) */ svp = hv_fetchs(action, "SAFE", FALSE); - act.sa_handler = - DPTR2FPTR( - void (*)(int), - (*svp && SvTRUE(*svp)) - ? PL_csighandlerp : PL_sighandlerp - ); + safe = *svp && SvTRUE(*svp); + + if (act.sa_flags & SA_SIGINFO) { + /* 3-arg handler */ + act.sa_sigaction = + safe ? PL_csighandler3p : PL_sighandler3p; + } + else { + /* 1-arg handler */ + act.sa_handler = + safe ? PL_csighandler1p : PL_sighandler1p; + } /* Vector new Perl handler through %SIG. (The core signal handlers read %SIG to dispatch.) */ @@ -3135,10 +3164,6 @@ sigaction(sig, optaction, oldaction = 0) else sigemptyset(& act.sa_mask); - /* Set up any desired flags. */ - svp = hv_fetchs(action, "FLAGS", FALSE); - act.sa_flags = svp ? SvIV(*svp) : 0; - /* Don't worry about cleaning up *sigsvp if this fails, * because that means we tried to disposition a * nonblockable signal, in which case *sigsvp is |