ash: hopefully close bug 4324. With testcase.

function                                             old     new   delta
evaltree                                             621     869    +248
popstring                                            134     140      +6
This commit is contained in:
Denis Vlasenko 2008-07-26 13:45:57 +00:00
parent 2b2e267b43
commit 4e19a9c81a
3 changed files with 57 additions and 17 deletions

View File

@ -203,7 +203,7 @@ struct globals_misc {
#define S_RESET 5 /* temporary - to reset a hard ignored sig */ #define S_RESET 5 /* temporary - to reset a hard ignored sig */
/* indicates specified signal received */ /* indicates specified signal received */
char gotsig[NSIG - 1]; char gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
char *trap[NSIG]; char *trap[NSIG];
/* Rarely referenced stuff */ /* Rarely referenced stuff */
@ -7846,12 +7846,12 @@ dotrap(void)
pendingsig = 0; pendingsig = 0;
xbarrier(); xbarrier();
for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) { for (i = 1, q = gotsig; i < NSIG; i++, q++) {
if (!*q) if (!*q)
continue; continue;
*q = '\0'; *q = '\0';
p = trap[i + 1]; p = trap[i];
if (!p) if (!p)
continue; continue;
skip = evalstring(p, SKIPEVAL); skip = evalstring(p, SKIPEVAL);
@ -7881,16 +7881,33 @@ static void prehash(union node *);
static void static void
evaltree(union node *n, int flags) evaltree(union node *n, int flags)
{ {
struct jmploc *volatile savehandler = exception_handler;
struct jmploc jmploc;
int checkexit = 0; int checkexit = 0;
void (*evalfn)(union node *, int); void (*evalfn)(union node *, int);
unsigned isor;
int status; int status;
if (n == NULL) { if (n == NULL) {
TRACE(("evaltree(NULL) called\n")); TRACE(("evaltree(NULL) called\n"));
goto out; goto out1;
} }
TRACE(("pid %d, evaltree(%p: %d, %d) called\n", TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
getpid(), n, n->type, flags)); getpid(), n, n->type, flags));
exception_handler = &jmploc;
{
int err = setjmp(jmploc.loc);
if (err) {
/* if it was a signal, check for trap handlers */
if (exception == EXSIG)
goto out;
/* continue on the way out */
exception_handler = savehandler;
longjmp(exception_handler->loc, err);
}
}
switch (n->type) { switch (n->type) {
default: default:
#if DEBUG #if DEBUG
@ -7936,19 +7953,20 @@ evaltree(union node *n, int flags)
goto calleval; goto calleval;
case NAND: case NAND:
case NOR: case NOR:
case NSEMI: case NSEMI: {
#if NAND + 1 != NOR #if NAND + 1 != NOR
#error NAND + 1 != NOR #error NAND + 1 != NOR
#endif #endif
#if NOR + 1 != NSEMI #if NOR + 1 != NSEMI
#error NOR + 1 != NSEMI #error NOR + 1 != NSEMI
#endif #endif
isor = n->type - NAND; unsigned is_or = is_or = n->type - NAND;
evaltree( evaltree(
n->nbinary.ch1, n->nbinary.ch1,
(flags | ((isor >> 1) - 1)) & EV_TESTED (flags | ((is_or >> 1) - 1)) & EV_TESTED
); );
if (!exitstatus == isor) if (!exitstatus == is_or)
break; break;
if (!evalskip) { if (!evalskip) {
n = n->nbinary.ch2; n = n->nbinary.ch2;
@ -7959,6 +7977,7 @@ evaltree(union node *n, int flags)
break; break;
} }
break; break;
}
case NIF: case NIF:
evaltree(n->nif.test, EV_TESTED); evaltree(n->nif.test, EV_TESTED);
if (evalskip) if (evalskip)
@ -7979,8 +7998,11 @@ evaltree(union node *n, int flags)
exitstatus = status; exitstatus = status;
break; break;
} }
out: out:
if ((checkexit & exitstatus)) exception_handler = savehandler;
out1:
if (checkexit & exitstatus)
evalskip |= SKIPEVAL; evalskip |= SKIPEVAL;
else if (pendingsig && dotrap()) else if (pendingsig && dotrap())
goto exexit; goto exexit;
@ -11907,18 +11929,15 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
if (!*ap) { if (!*ap) {
for (signo = 0; signo < NSIG; signo++) { for (signo = 0; signo < NSIG; signo++) {
if (trap[signo] != NULL) { if (trap[signo] != NULL) {
const char *sn;
sn = get_signame(signo);
out1fmt("trap -- %s %s\n", out1fmt("trap -- %s %s\n",
single_quote(trap[signo]), sn); single_quote(trap[signo]),
get_signame(signo));
} }
} }
return 0; return 0;
} }
if (!ap[1]) action = NULL;
action = NULL; if (ap[1])
else
action = *ap++; action = *ap++;
while (*ap) { while (*ap) {
signo = get_signum(*ap); signo = get_signum(*ap);

View File

@ -0,0 +1,3 @@
sleeping
child exits as expected
parent exits

View File

@ -0,0 +1,18 @@
#!/bin/sh
$THIS_SH -c '
cleanup() {
echo "child exits as expected"
exit
}
trap cleanup HUP
echo "sleeping"
sleep 1
echo "BAD exit from child!"
' &
child=$!
sleep 0.1 # let child install handler first
kill -HUP $child
wait
echo "parent exits"