ash: hopefully close bug 4324. With testcase.
authorDenis Vlasenko <vda.linux@googlemail.com>
Sat, 26 Jul 2008 13:45:57 +0000 (13:45 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Sat, 26 Jul 2008 13:45:57 +0000 (13:45 -0000)
function                                             old     new   delta
evaltree                                             621     869    +248
popstring                                            134     140      +6

shell/ash.c
shell/ash_test/ash-signals/signal2.right [new file with mode: 0644]
shell/ash_test/ash-signals/signal2.tests [new file with mode: 0755]

index 11174683e7766ec2b8b799bce24e7c1effad45d5..5348e957250fbdec07bba519c873ade0b3d35586 100644 (file)
@@ -203,7 +203,7 @@ struct globals_misc {
 #define S_RESET 5               /* temporary - to reset a hard ignored sig */
 
        /* indicates specified signal received */
-       char gotsig[NSIG - 1];
+       char gotsig[NSIG - 1]; /* offset by 1: "signal" 0 is meaningless */
        char *trap[NSIG];
 
        /* Rarely referenced stuff */
@@ -7846,12 +7846,12 @@ dotrap(void)
        pendingsig = 0;
        xbarrier();
 
-       for (i = 0, q = gotsig; i < NSIG - 1; i++, q++) {
+       for (i = 1, q = gotsig; i < NSIG; i++, q++) {
                if (!*q)
                        continue;
                *q = '\0';
 
-               p = trap[i + 1];
+               p = trap[i];
                if (!p)
                        continue;
                skip = evalstring(p, SKIPEVAL);
@@ -7881,16 +7881,33 @@ static void prehash(union node *);
 static void
 evaltree(union node *n, int flags)
 {
+
+       struct jmploc *volatile savehandler = exception_handler;
+       struct jmploc jmploc;
        int checkexit = 0;
        void (*evalfn)(union node *, int);
-       unsigned isor;
        int status;
+
        if (n == NULL) {
                TRACE(("evaltree(NULL) called\n"));
-               goto out;
+               goto out1;
        }
        TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
                        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) {
        default:
 #if DEBUG
@@ -7936,19 +7953,20 @@ evaltree(union node *n, int flags)
                goto calleval;
        case NAND:
        case NOR:
-       case NSEMI:
+       case NSEMI: {
+
 #if NAND + 1 != NOR
 #error NAND + 1 != NOR
 #endif
 #if NOR + 1 != NSEMI
 #error NOR + 1 != NSEMI
 #endif
-               isor = n->type - NAND;
+               unsigned is_or = is_or = n->type - NAND;
                evaltree(
                        n->nbinary.ch1,
-                       (flags | ((isor >> 1) - 1)) & EV_TESTED
+                       (flags | ((is_or >> 1) - 1)) & EV_TESTED
                );
-               if (!exitstatus == isor)
+               if (!exitstatus == is_or)
                        break;
                if (!evalskip) {
                        n = n->nbinary.ch2;
@@ -7959,6 +7977,7 @@ evaltree(union node *n, int flags)
                        break;
                }
                break;
+       }
        case NIF:
                evaltree(n->nif.test, EV_TESTED);
                if (evalskip)
@@ -7979,8 +7998,11 @@ evaltree(union node *n, int flags)
                exitstatus = status;
                break;
        }
+
  out:
-       if ((checkexit & exitstatus))
+       exception_handler = savehandler;
+ out1:
+       if (checkexit & exitstatus)
                evalskip |= SKIPEVAL;
        else if (pendingsig && dotrap())
                goto exexit;
@@ -11907,18 +11929,15 @@ trapcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
        if (!*ap) {
                for (signo = 0; signo < NSIG; signo++) {
                        if (trap[signo] != NULL) {
-                               const char *sn;
-
-                               sn = get_signame(signo);
                                out1fmt("trap -- %s %s\n",
-                                       single_quote(trap[signo]), sn);
+                                               single_quote(trap[signo]),
+                                               get_signame(signo));
                        }
                }
                return 0;
        }
-       if (!ap[1])
-               action = NULL;
-       else
+       action = NULL;
+       if (ap[1])
                action = *ap++;
        while (*ap) {
                signo = get_signum(*ap);
diff --git a/shell/ash_test/ash-signals/signal2.right b/shell/ash_test/ash-signals/signal2.right
new file mode 100644 (file)
index 0000000..96d2d6a
--- /dev/null
@@ -0,0 +1,3 @@
+sleeping
+child exits as expected
+parent exits
diff --git a/shell/ash_test/ash-signals/signal2.tests b/shell/ash_test/ash-signals/signal2.tests
new file mode 100755 (executable)
index 0000000..04f981c
--- /dev/null
@@ -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"