mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-10-30 17:50:58 +01:00
fix autoloaded trap bug; rejig use of trapfuncs
(now traplists); improve trap tests
This commit is contained in:
parent
64c2db0ca2
commit
05b06b1c08
9 changed files with 129 additions and 41 deletions
|
|
@ -1,3 +1,12 @@
|
|||
2005-02-06 Peter Stephenson <pws@pwstephenson.fsnet.co.uk>
|
||||
|
||||
* (cheated and guessed) 20793: Src/builtin.c, Src/exec.c,
|
||||
Src/hashtable.c, Src/Modules/parameter.c, Src/Module/zftp.c,
|
||||
Src/parse.c, Src/signals.c, Test/C03traps.ztst: Fix bug that
|
||||
autoloaded TRAPEXIT wasn't restored properly after running an
|
||||
intermediate function; only use sigfuncs (renamed to siglists) for
|
||||
eval-style traps; augment and fix trap tests.
|
||||
|
||||
2005-02-04 Peter Stephenson <pws@csr.com>
|
||||
|
||||
* 20787: configure.ac, Config/defs.mk.in, Doc/.distfiles,
|
||||
|
|
|
|||
|
|
@ -332,13 +332,12 @@ setfunction(char *name, char *val, int dis)
|
|||
|
||||
if (!strncmp(name, "TRAP", 4) &&
|
||||
(sn = getsignum(name + 4)) != -1) {
|
||||
if (settrap(sn, shf->funcdef)) {
|
||||
if (settrap(sn, NULL, ZSIG_FUNC)) {
|
||||
freeeprog(shf->funcdef);
|
||||
zfree(shf, sizeof(*shf));
|
||||
zsfree(val);
|
||||
return;
|
||||
}
|
||||
sigtrapped[sn] |= ZSIG_FUNC;
|
||||
}
|
||||
shfunctab->addnode(shfunctab, ztrdup(name), shf);
|
||||
zsfree(val);
|
||||
|
|
|
|||
|
|
@ -436,7 +436,8 @@ zfunalarm(void)
|
|||
} else
|
||||
alarm(0);
|
||||
if (sigtrapped[SIGALRM] || interact) {
|
||||
if (sigfuncs[SIGALRM] || !sigtrapped[SIGALRM])
|
||||
if (siglists[SIGALRM] || !sigtrapped[SIGALRM] ||
|
||||
(sigtrapped[SIGALRM] & ZSIG_FUNC))
|
||||
install_handler(SIGALRM);
|
||||
else
|
||||
signal_ignore(SIGALRM);
|
||||
|
|
@ -452,7 +453,7 @@ static void
|
|||
zfunpipe()
|
||||
{
|
||||
if (sigtrapped[SIGPIPE]) {
|
||||
if (sigfuncs[SIGPIPE])
|
||||
if (siglists[SIGPIPE] || (sigtrapped[SIGPIPE] & ZSIG_FUNC))
|
||||
install_handler(SIGPIPE);
|
||||
else
|
||||
signal_ignore(SIGPIPE);
|
||||
|
|
|
|||
|
|
@ -2617,14 +2617,12 @@ bin_functions(char *name, char **argv, Options ops, int func)
|
|||
shfunctab->addnode(shfunctab, ztrdup(*argv), shf);
|
||||
|
||||
if (signum != -1) {
|
||||
if (settrap(signum, shf->funcdef)) {
|
||||
if (settrap(signum, NULL, ZSIG_FUNC)) {
|
||||
shfunctab->removenode(shfunctab, *argv);
|
||||
shfunctab->freenode((HashNode)shf);
|
||||
returnval = 1;
|
||||
ok = 0;
|
||||
}
|
||||
else
|
||||
sigtrapped[signum] |= ZSIG_FUNC;
|
||||
}
|
||||
|
||||
if (ok && OPT_ISSET(ops,'X') &&
|
||||
|
|
@ -4967,10 +4965,10 @@ bin_trap(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
|
|||
shfunctab->printnode(hn, 0);
|
||||
DPUTS(!hn, "BUG: I did not find any trap functions!");
|
||||
} else if (sigtrapped[sig]) {
|
||||
if (!sigfuncs[sig])
|
||||
if (!siglists[sig])
|
||||
printf("trap -- '' %s\n", sigs[sig]);
|
||||
else {
|
||||
s = getpermtext(sigfuncs[sig], NULL);
|
||||
s = getpermtext(siglists[sig], NULL);
|
||||
printf("trap -- ");
|
||||
quotedzputs(s, stdout);
|
||||
printf(" %s\n", sigs[sig]);
|
||||
|
|
@ -5013,7 +5011,7 @@ bin_trap(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
|
|||
break;
|
||||
}
|
||||
t = dupeprog(prog, 0);
|
||||
if (settrap(sig, t))
|
||||
if (settrap(sig, t, 0))
|
||||
freeeprog(t);
|
||||
}
|
||||
return *argv != NULL;
|
||||
|
|
|
|||
|
|
@ -2650,8 +2650,8 @@ entersubsh(int how, int cl, int fake, int revertpgrp)
|
|||
unsettrap(sig);
|
||||
if (!(monitor = isset(MONITOR))) {
|
||||
if (how & Z_ASYNC) {
|
||||
settrap(SIGINT, NULL);
|
||||
settrap(SIGQUIT, NULL);
|
||||
settrap(SIGINT, NULL, 0);
|
||||
settrap(SIGQUIT, NULL, 0);
|
||||
if (isatty(0)) {
|
||||
close(0);
|
||||
if (open("/dev/null", O_RDWR | O_NOCTTY)) {
|
||||
|
|
@ -3340,13 +3340,12 @@ execfuncdef(Estate state, UNUSED(int do_exec))
|
|||
/* is this shell function a signal trap? */
|
||||
if (!strncmp(s, "TRAP", 4) &&
|
||||
(signum = getsignum(s + 4)) != -1) {
|
||||
if (settrap(signum, shf->funcdef)) {
|
||||
if (settrap(signum, NULL, ZSIG_FUNC)) {
|
||||
freeeprog(shf->funcdef);
|
||||
zfree(shf, sizeof(*shf));
|
||||
state->pc = end;
|
||||
return 1;
|
||||
}
|
||||
sigtrapped[signum] |= ZSIG_FUNC;
|
||||
|
||||
/*
|
||||
* Remove the old node explicitly in case it has
|
||||
|
|
|
|||
|
|
@ -819,7 +819,6 @@ disableshfuncnode(HashNode hn, UNUSED(int flags))
|
|||
if (!strncmp(hn->nam, "TRAP", 4)) {
|
||||
int signum = getsignum(hn->nam + 4);
|
||||
sigtrapped[signum] &= ~ZSIG_FUNC;
|
||||
sigfuncs[signum] = NULL;
|
||||
unsettrap(signum);
|
||||
}
|
||||
}
|
||||
|
|
@ -838,8 +837,7 @@ enableshfuncnode(HashNode hn, UNUSED(int flags))
|
|||
if (!strncmp(shf->nam, "TRAP", 4)) {
|
||||
int signum = getsignum(shf->nam + 4);
|
||||
if (signum != -1) {
|
||||
settrap(signum, shf->funcdef);
|
||||
sigtrapped[signum] |= ZSIG_FUNC;
|
||||
settrap(signum, NULL, ZSIG_FUNC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
10
Src/parse.c
10
Src/parse.c
|
|
@ -2105,6 +2105,16 @@ yyerror(int noerr)
|
|||
errflag = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Duplicate a programme list, on the heap if heap is 1, else
|
||||
* in permanent storage.
|
||||
*
|
||||
* Be careful in case p is the Eprog for a function which will
|
||||
* later be autoloaded. The shf element of the returned Eprog
|
||||
* must be set appropriately by the caller. (Normally we create
|
||||
* the Eprog in this case by using mkautofn.)
|
||||
*/
|
||||
|
||||
/**/
|
||||
mod_export Eprog
|
||||
dupeprog(Eprog p, int heap)
|
||||
|
|
|
|||
|
|
@ -36,10 +36,19 @@
|
|||
/**/
|
||||
mod_export int sigtrapped[VSIGCOUNT];
|
||||
|
||||
/* trap functions for each signal */
|
||||
/*
|
||||
* Trap programme lists for each signal.
|
||||
*
|
||||
* If (sigtrapped[sig] & ZSIG_FUNC) is set, this isn't used.
|
||||
* The corresponding shell function is used instead.
|
||||
*
|
||||
* Otherwise, if sigtrapped[sig] is not zero, this is NULL when a signal
|
||||
* is to be ignored, and if not NULL contains the programme list to be
|
||||
* eval'd.
|
||||
*/
|
||||
|
||||
/**/
|
||||
mod_export Eprog sigfuncs[VSIGCOUNT];
|
||||
mod_export Eprog siglists[VSIGCOUNT];
|
||||
|
||||
/* Total count of trapped signals */
|
||||
|
||||
|
|
@ -682,7 +691,7 @@ static int dontsavetrap;
|
|||
|
||||
/*
|
||||
* Save the current trap by copying it. This does nothing to
|
||||
* the existing value of sigtrapped or sigfuncs.
|
||||
* the existing value of sigtrapped or siglists.
|
||||
*/
|
||||
|
||||
static void
|
||||
|
|
@ -704,15 +713,18 @@ dosavetrap(int sig, int level)
|
|||
newshf->nam = ztrdup(shf->nam);
|
||||
newshf->flags = shf->flags;
|
||||
newshf->funcdef = dupeprog(shf->funcdef, 0);
|
||||
if (shf->flags & PM_UNDEFINED)
|
||||
newshf->funcdef->shf = newshf;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
else dputs("BUG: no function present with function trap flag set.");
|
||||
#endif
|
||||
DPUTS(siglists[sig], "BUG: function signal has eval list, too.");
|
||||
st->list = newshf;
|
||||
} else if (sigtrapped[sig]) {
|
||||
st->list = sigfuncs[sig] ? dupeprog(sigfuncs[sig], 0) : NULL;
|
||||
st->list = siglists[sig] ? dupeprog(siglists[sig], 0) : NULL;
|
||||
} else {
|
||||
DPUTS(sigfuncs[sig], "BUG: sigfuncs not null for untrapped signal");
|
||||
DPUTS(siglists[sig], "BUG: siglists not null for untrapped signal");
|
||||
st->list = NULL;
|
||||
}
|
||||
if (!savetraps)
|
||||
|
|
@ -723,9 +735,24 @@ dosavetrap(int sig, int level)
|
|||
zinsertlinknode(savetraps, (LinkNode)savetraps, st);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set a trap: note this does not handle manipulation of
|
||||
* the function table for TRAPNAL functions.
|
||||
*
|
||||
* sig is the signal number.
|
||||
*
|
||||
* l is the list to be eval'd for a trap defined with the "trap"
|
||||
* builtin and should be NULL for a function trap.
|
||||
*
|
||||
* flags includes any additional flags to be or'd into sigtrapped[sig],
|
||||
* in particular ZSIG_FUNC; the basic flags will be assigned within
|
||||
* settrap.
|
||||
*/
|
||||
|
||||
/**/
|
||||
mod_export int
|
||||
settrap(int sig, Eprog l)
|
||||
settrap(int sig, Eprog l, int flags)
|
||||
{
|
||||
if (sig == -1)
|
||||
return 1;
|
||||
|
|
@ -741,8 +768,10 @@ settrap(int sig, Eprog l)
|
|||
queue_signals();
|
||||
unsettrap(sig);
|
||||
|
||||
sigfuncs[sig] = l;
|
||||
if (empty_eprog(l)) {
|
||||
DPUTS((flags & ZSIG_FUNC) && l,
|
||||
"BUG: trap function has passed eval list, too");
|
||||
siglists[sig] = l;
|
||||
if (!(flags & ZSIG_FUNC) && empty_eprog(l)) {
|
||||
sigtrapped[sig] = ZSIG_IGNORED;
|
||||
if (sig && sig <= SIGCOUNT &&
|
||||
#ifdef SIGWINCH
|
||||
|
|
@ -765,7 +794,7 @@ settrap(int sig, Eprog l)
|
|||
* sigtrapped[sig] is zero or not, i.e. a test without a mask
|
||||
* works just the same.
|
||||
*/
|
||||
sigtrapped[sig] |= (locallevel << ZSIG_SHIFT);
|
||||
sigtrapped[sig] |= (locallevel << ZSIG_SHIFT) | flags;
|
||||
unqueue_signals();
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -829,7 +858,7 @@ removetrap(int sig)
|
|||
/*
|
||||
* At this point we free the appropriate structs. If we don't
|
||||
* want that to happen then either the function should already have been
|
||||
* removed from shfunctab, or the entry in sigfuncs should have been set
|
||||
* removed from shfunctab, or the entry in siglists should have been set
|
||||
* to NULL. This is no longer necessary for saving traps as that
|
||||
* copies the structures, so here we are remove the originals.
|
||||
* That causes a little inefficiency, but a good deal more reliability.
|
||||
|
|
@ -841,15 +870,14 @@ removetrap(int sig)
|
|||
* As in dosavetrap(), don't call removeshfuncnode() because
|
||||
* that calls back into unsettrap();
|
||||
*/
|
||||
sigfuncs[sig] = NULL;
|
||||
if (node)
|
||||
removehashnode(shfunctab, node->nam);
|
||||
unqueue_signals();
|
||||
|
||||
return node;
|
||||
} else if (sigfuncs[sig]) {
|
||||
freeeprog(sigfuncs[sig]);
|
||||
sigfuncs[sig] = NULL;
|
||||
} else if (siglists[sig]) {
|
||||
freeeprog(siglists[sig]);
|
||||
siglists[sig] = NULL;
|
||||
}
|
||||
unqueue_signals();
|
||||
|
||||
|
|
@ -894,9 +922,9 @@ endtrapscope(void)
|
|||
if (exittr & ZSIG_FUNC) {
|
||||
exitfn = removehashnode(shfunctab, "TRAPEXIT");
|
||||
} else {
|
||||
exitfn = sigfuncs[SIGEXIT];
|
||||
exitfn = siglists[SIGEXIT];
|
||||
siglists[SIGEXIT] = NULL;
|
||||
}
|
||||
sigfuncs[SIGEXIT] = NULL;
|
||||
if (sigtrapped[SIGEXIT] & ZSIG_TRAPPED)
|
||||
nsigtrapped--;
|
||||
sigtrapped[SIGEXIT] = 0;
|
||||
|
|
@ -911,11 +939,12 @@ endtrapscope(void)
|
|||
remnode(savetraps, ln);
|
||||
|
||||
if (st->flags && (st->list != NULL)) {
|
||||
Eprog prog = (st->flags & ZSIG_FUNC) ?
|
||||
((Shfunc) st->list)->funcdef : (Eprog) st->list;
|
||||
/* prevent settrap from saving this */
|
||||
dontsavetrap++;
|
||||
settrap(sig, prog);
|
||||
if (st->flags & ZSIG_FUNC)
|
||||
settrap(sig, NULL, ZSIG_FUNC);
|
||||
else
|
||||
settrap(sig, (Eprog) st->list, 0);
|
||||
dontsavetrap--;
|
||||
/*
|
||||
* counting of nsigtrapped should presumably be handled
|
||||
|
|
@ -946,7 +975,7 @@ endtrapscope(void)
|
|||
}
|
||||
|
||||
/* Execute a trap function for a given signal, possibly
|
||||
* with non-standard sigtrapped & sigfuncs values
|
||||
* with non-standard sigtrapped & siglists values
|
||||
*/
|
||||
|
||||
/* Are we already executing a trap? */
|
||||
|
|
@ -1097,9 +1126,24 @@ dotrapargs(int sig, int *sigtr, void *sigfn)
|
|||
void
|
||||
dotrap(int sig)
|
||||
{
|
||||
Eprog funcprog;
|
||||
|
||||
if (sigtrapped[sig] & ZSIG_FUNC) {
|
||||
HashNode hn = gettrapnode(sig, 0);
|
||||
if (hn)
|
||||
funcprog = ((Shfunc)hn)->funcdef;
|
||||
else {
|
||||
#ifdef DEBUG
|
||||
dputs("BUG: running function trap which has escaped.");
|
||||
#endif
|
||||
funcprog = NULL;
|
||||
}
|
||||
} else
|
||||
funcprog = siglists[sig];
|
||||
|
||||
/* Copied from dotrapargs(). */
|
||||
if ((sigtrapped[sig] & ZSIG_IGNORED) || !sigfuncs[sig] || errflag)
|
||||
if ((sigtrapped[sig] & ZSIG_IGNORED) || !funcprog || errflag)
|
||||
return;
|
||||
|
||||
dotrapargs(sig, sigtrapped+sig, sigfuncs[sig]);
|
||||
dotrapargs(sig, sigtrapped+sig, funcprog);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -183,17 +183,21 @@
|
|||
}
|
||||
testunset
|
||||
f
|
||||
1: more sophisticated error trapping
|
||||
print status $?
|
||||
unfunction TRAPZERR
|
||||
0: more sophisticated error trapping
|
||||
>f
|
||||
>ERR-or!
|
||||
>f
|
||||
>t
|
||||
>f
|
||||
>t
|
||||
>f
|
||||
>ERR-or!
|
||||
>testunset
|
||||
>f
|
||||
>ERR-or!
|
||||
>status 1
|
||||
|
||||
f() {
|
||||
setopt localtraps
|
||||
|
|
@ -216,6 +220,32 @@
|
|||
fn
|
||||
1: ksh-style EXIT traps preserve return value
|
||||
|
||||
inner() { trap 'return 3' EXIT; return 2: }
|
||||
inner() { trap 'return 3' EXIT; return 2; }
|
||||
outer() { inner; return 1; }
|
||||
outer
|
||||
3: ksh-style EXIT traps can force return status of enclosing function
|
||||
|
||||
# Autoloaded traps are horrid, but unfortunately people expect
|
||||
# them to work if we support them.
|
||||
echo "print Running exit trap" >TRAPEXIT
|
||||
$ZTST_testdir/../Src/zsh -fc '
|
||||
fpath=(. $fpath)
|
||||
autoload TRAPEXIT
|
||||
print "Exiting, attempt 1"
|
||||
exit
|
||||
print "What?"
|
||||
'
|
||||
$ZTST_testdir/../Src/zsh -fc '
|
||||
fpath=(. $fpath)
|
||||
autoload TRAPEXIT;
|
||||
fn() { print Some function }
|
||||
fn
|
||||
print "Exiting, attempt 2"
|
||||
exit
|
||||
'
|
||||
0: autoloaded TRAPEXIT (exit status > 128 indicates an old bug is back)
|
||||
>Exiting, attempt 1
|
||||
>Running exit trap
|
||||
>Some function
|
||||
>Exiting, attempt 2
|
||||
>Running exit trap
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue