On Sat, Mar 02, 2019 at 01:28:44PM +0000, Harald van Dijk wrote:
>
> That is *a* real bug here, not *the* real bug. This leaves the buggy
> behaviour of the "command" built-in intact in the test case I included in
> the message you replied to.

I don't quite understand.  Could you explain what is still buggy
after the following patch?

> For fixing the one bug, it is a sensible approach, but keep in mind that
> when a fork is omitted because of EV_EXIT, so too will the reset of handler.
> You may be able to get away with that as long as you do not propagate
> EV_EXIT in any cases where a cleanup action might cause problems.

Good point.  Here is a revised patch to fix the nofork case too.

---8<--
As it is a subshell can execute code that is only meant for the
parent shell when it executes a longjmp that is caught by something
like evalcommand.  This patch fixes it by resetting the handler
when entering a subshell.

Reported-by: Martijn Dekker <[email protected]>
Signed-off-by: Herbert Xu <[email protected]>

diff --git a/src/eval.c b/src/eval.c
index 1aad31a..6ee2e1a 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -41,6 +41,7 @@
  * Evaluate a command.
  */
 
+#include "main.h"
 #include "shell.h"
 #include "nodes.h"
 #include "syntax.h"
@@ -492,6 +493,7 @@ evalsubshell(union node *n, int flags)
                if (backgnd)
                        flags &=~ EV_TESTED;
 nofork:
+               reset_handler();
                redirect(n->nredir.redirect, 0);
                evaltreenr(n->nredir.n, flags);
                /* never returns */
@@ -574,6 +576,7 @@ evalpipe(union node *n, int flags)
                        }
                }
                if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
+                       reset_handler();
                        INTON;
                        if (pip[1] >= 0) {
                                close(pip[0]);
@@ -630,6 +633,7 @@ evalbackcmd(union node *n, struct backcmd *result)
                sh_error("Pipe call failed");
        jp = makejob(n, 1);
        if (forkshell(jp, n, FORK_NOJOB) == 0) {
+               reset_handler();
                FORCEINTON;
                close(pip[0]);
                if (pip[1] != 1) {
diff --git a/src/main.c b/src/main.c
index 6b3a090..b2712cb 100644
--- a/src/main.c
+++ b/src/main.c
@@ -71,6 +71,7 @@ int *dash_errno;
 short profile_buf[16384];
 extern int etext();
 #endif
+static struct jmploc main_handler;
 
 STATIC void read_profile(const char *);
 STATIC char *find_dot_file(char *);
@@ -90,7 +91,6 @@ main(int argc, char **argv)
 {
        char *shinit;
        volatile int state;
-       struct jmploc jmploc;
        struct stackmark smark;
        int login;
 
@@ -102,7 +102,7 @@ main(int argc, char **argv)
        monitor(4, etext, profile_buf, sizeof profile_buf, 50);
 #endif
        state = 0;
-       if (unlikely(setjmp(jmploc.loc))) {
+       if (unlikely(setjmp(main_handler.loc))) {
                int e;
                int s;
 
@@ -137,7 +137,7 @@ main(int argc, char **argv)
                else
                        goto state4;
        }
-       handler = &jmploc;
+       handler = &main_handler;
 #ifdef DEBUG
        opentrace();
        trputs("Shell args:  ");  trargs(argv);
@@ -353,3 +353,8 @@ exitcmd(int argc, char **argv)
        exraise(EXEXIT);
        /* NOTREACHED */
 }
+
+void reset_handler(void)
+{
+       handler = &main_handler;
+}
diff --git a/src/main.h b/src/main.h
index 19e4983..51f1604 100644
--- a/src/main.h
+++ b/src/main.h
@@ -52,3 +52,4 @@ extern int *dash_errno;
 void readcmdfile(char *);
 int dotcmd(int, char **);
 int exitcmd(int, char **);
+void reset_handler(void);
-- 
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

Reply via email to