aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2020-02-20 16:54:29 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2020-02-20 16:54:29 +0100
commitf977e004cefe46e8010c3d29681d77da50e380a9 (patch)
tree39c1afc6b44350bd56fe03ed59afb8f4bfae645e
parentcd24a506336f84ff2bb3318bc4f2f82dd025f318 (diff)
downloadbusybox-w32-f977e004cefe46e8010c3d29681d77da50e380a9.tar.gz
busybox-w32-f977e004cefe46e8010c3d29681d77da50e380a9.tar.bz2
busybox-w32-f977e004cefe46e8010c3d29681d77da50e380a9.zip
ash: eval: Only restore exit status on exit/return
Upstream commit: Date: Fri, 14 Dec 2018 13:52:02 +0800 eval: Only restore exit status on exit/return We unconditionally restore the saved status in exitreset, which is incorrect as we only want to do it for exitcmd and returncmd. This patch fixes the problem by introducing EXEND. Reported-by: Martijn Dekker <martijn@inlv.org> Fixes: da30b4b78769 ("[BUILTIN] Exit without arguments in a trap...") Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--shell/ash.c99
1 files changed, 51 insertions, 48 deletions
diff --git a/shell/ash.c b/shell/ash.c
index bea24601c..fd2fc9f23 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -404,11 +404,11 @@ struct globals_misc {
404 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */ 404 volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
405 volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */ 405 volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */
406 volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */ 406 volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */
407 smallint exception_type; /* kind of exception (0..5) */ 407 smallint exception_type; /* kind of exception: */
408 /* exceptions */
409#define EXINT 0 /* SIGINT received */ 408#define EXINT 0 /* SIGINT received */
410#define EXERROR 1 /* a generic error */ 409#define EXERROR 1 /* a generic error */
411#define EXEXIT 4 /* exit the shell */ 410#define EXEND 3 /* exit the shell */
411#define EXEXIT 4 /* exit the shell via exitcmd */
412 412
413 char nullstr[1]; /* zero length string */ 413 char nullstr[1]; /* zero length string */
414 414
@@ -8237,7 +8237,7 @@ static void shellexec(char *prog, char **argv, const char *path, int idx)
8237 exitstatus = exerrno; 8237 exitstatus = exerrno;
8238 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n", 8238 TRACE(("shellexec failed for %s, errno %d, suppress_int %d\n",
8239 prog, e, suppress_int)); 8239 prog, e, suppress_int));
8240 ash_msg_and_raise(EXEXIT, "%s: %s", prog, errmsg(e, "not found")); 8240 ash_msg_and_raise(EXEND, "%s: %s", prog, errmsg(e, "not found"));
8241 /* NOTREACHED */ 8241 /* NOTREACHED */
8242} 8242}
8243 8243
@@ -9291,9 +9291,9 @@ evaltree(union node *n, int flags)
9291 dotrap(); 9291 dotrap();
9292 9292
9293 if (checkexit & status) 9293 if (checkexit & status)
9294 raise_exception(EXEXIT); 9294 raise_exception(EXEND);
9295 if (flags & EV_EXIT) 9295 if (flags & EV_EXIT)
9296 raise_exception(EXEXIT); 9296 raise_exception(EXEND);
9297 9297
9298 popstackmark(&smark); 9298 popstackmark(&smark);
9299 TRACE(("leaving evaltree (no interrupts)\n")); 9299 TRACE(("leaving evaltree (no interrupts)\n"));
@@ -14147,6 +14147,47 @@ ulimitcmd(int argc UNUSED_PARAM, char **argv)
14147/* ============ main() and helpers */ 14147/* ============ main() and helpers */
14148 14148
14149/* 14149/*
14150 * This routine is called when an error or an interrupt occurs in an
14151 * interactive shell and control is returned to the main command loop
14152 * but prior to exitshell.
14153 */
14154static void
14155exitreset(void)
14156{
14157 /* from eval.c: */
14158 if (savestatus >= 0) {
14159 if (exception_type == EXEXIT || evalskip == SKIPFUNCDEF)
14160 exitstatus = savestatus;
14161 savestatus = -1;
14162 }
14163 evalskip = 0;
14164 loopnest = 0;
14165
14166 /* from expand.c: */
14167 ifsfree();
14168
14169 /* from redir.c: */
14170 unwindredir(NULL);
14171}
14172
14173/*
14174 * This routine is called when an error or an interrupt occurs in an
14175 * interactive shell and control is returned to the main command loop.
14176 * (In dash, this function is auto-generated by build machinery).
14177 */
14178static void
14179reset(void)
14180{
14181 /* from input.c: */
14182 g_parsefile->left_in_buffer = 0;
14183 g_parsefile->left_in_line = 0; /* clear input buffer */
14184 popallfiles();
14185
14186 /* from var.c: */
14187 unwindlocalvars(NULL);
14188}
14189
14190/*
14150 * Called to exit the shell. 14191 * Called to exit the shell.
14151 */ 14192 */
14152static void 14193static void
@@ -14169,15 +14210,17 @@ exitshell(void)
14169 trap[0] = NULL; 14210 trap[0] = NULL;
14170 evalskip = 0; 14211 evalskip = 0;
14171 evalstring(p, 0); 14212 evalstring(p, 0);
14213 evalskip = SKIPFUNCDEF;
14172 /*free(p); - we'll exit soon */ 14214 /*free(p); - we'll exit soon */
14173 } 14215 }
14174 out: 14216 out:
14217 exitreset();
14175 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}". 14218 /* dash wraps setjobctl(0) in "if (setjmp(loc.loc) == 0) {...}".
14176 * our setjobctl(0) does not panic if tcsetpgrp fails inside it. 14219 * our setjobctl(0) does not panic if tcsetpgrp fails inside it.
14177 */ 14220 */
14178 setjobctl(0); 14221 setjobctl(0);
14179 flush_stdout_stderr(); 14222 flush_stdout_stderr();
14180 _exit(savestatus); 14223 _exit(exitstatus);
14181 /* NOTREACHED */ 14224 /* NOTREACHED */
14182} 14225}
14183 14226
@@ -14337,46 +14380,6 @@ read_profile(const char *name)
14337 popfile(); 14380 popfile();
14338} 14381}
14339 14382
14340/*
14341 * This routine is called when an error or an interrupt occurs in an
14342 * interactive shell and control is returned to the main command loop
14343 * but prior to exitshell.
14344 */
14345static void
14346exitreset(void)
14347{
14348 /* from eval.c: */
14349 evalskip = 0;
14350 loopnest = 0;
14351 if (savestatus >= 0) {
14352 exitstatus = savestatus;
14353 savestatus = -1;
14354 }
14355
14356 /* from expand.c: */
14357 ifsfree();
14358
14359 /* from redir.c: */
14360 unwindredir(NULL);
14361}
14362
14363/*
14364 * This routine is called when an error or an interrupt occurs in an
14365 * interactive shell and control is returned to the main command loop.
14366 * (In dash, this function is auto-generated by build machinery).
14367 */
14368static void
14369reset(void)
14370{
14371 /* from input.c: */
14372 g_parsefile->left_in_buffer = 0;
14373 g_parsefile->left_in_line = 0; /* clear input buffer */
14374 popallfiles();
14375
14376 /* from var.c: */
14377 unwindlocalvars(NULL);
14378}
14379
14380#if PROFILE 14383#if PROFILE
14381static short profile_buf[16384]; 14384static short profile_buf[16384];
14382extern int etext(); 14385extern int etext();
@@ -14424,7 +14427,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
14424 14427
14425 e = exception_type; 14428 e = exception_type;
14426 s = state; 14429 s = state;
14427 if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) { 14430 if (e == EXEND || e == EXEXIT || s == 0 || iflag == 0 || shlvl) {
14428 exitshell(); 14431 exitshell();
14429 } 14432 }
14430 14433