klibc-bot for Herbert Xu
2019-Jan-25 03:15 UTC
[klibc] [klibc:update-dash] eval: Return status in eval functions
Commit-ID: ef5fd2060f3c7d1a4a22a079bc1c32b61964bb5f Gitweb: http://git.kernel.org/?p=libs/klibc/klibc.git;a=commit;h=ef5fd2060f3c7d1a4a22a079bc1c32b61964bb5f Author: Herbert Xu <herbert at gondor.apana.org.au> AuthorDate: Tue, 7 Jun 2016 16:47:59 +0800 Committer: Ben Hutchings <ben at decadent.org.uk> CommitDate: Fri, 25 Jan 2019 02:57:21 +0000 [klibc] eval: Return status in eval functions The exit status is currently clobbered too early for case statements and loops. This patch fixes it by making the eval functions return the current exit status and setting them in one place -- evaltree. Harald van Dijk pointed out a number of bugs in the original patch. Signed-off-by: Herbert Xu <herbert at gondor.apana.org.au> Signed-off-by: Ben Hutchings <ben at decadent.org.uk> --- usr/dash/eval.c | 139 ++++++++++++++++++++++++++++++-------------------------- usr/dash/eval.h | 2 +- usr/dash/main.c | 6 ++- 3 files changed, 80 insertions(+), 67 deletions(-) diff --git a/usr/dash/eval.c b/usr/dash/eval.c index ef6ec0ef..6ba64b12 100644 --- a/usr/dash/eval.c +++ b/usr/dash/eval.c @@ -81,16 +81,16 @@ int savestatus = -1; /* exit status of last command outside traps */ STATIC #endif void evaltreenr(union node *, int) __attribute__ ((__noreturn__)); -STATIC void evalloop(union node *, int); -STATIC void evalfor(union node *, int); -STATIC void evalcase(union node *, int); -STATIC void evalsubshell(union node *, int); +STATIC int evalloop(union node *, int); +STATIC int evalfor(union node *, int); +STATIC int evalcase(union node *, int); +STATIC int evalsubshell(union node *, int); STATIC void expredir(union node *); -STATIC void evalpipe(union node *, int); +STATIC int evalpipe(union node *, int); #ifdef notyet -STATIC void evalcommand(union node *, int, struct backcmd *); +STATIC int evalcommand(union node *, int, struct backcmd *); #else -STATIC void evalcommand(union node *, int); +STATIC int evalcommand(union node *, int); #endif STATIC int evalbltin(const struct builtincmd *, int, char **, int); STATIC int evalfun(struct funcnode *, int, char **, int); @@ -170,11 +170,13 @@ evalstring(char *s, int flags) setstackmark(&smark); status = 0; - while ((n = parsecmd(0)) != NEOF) { - evaltree(n, flags & ~(parser_eof() ? 0 : EV_EXIT)); + for (; (n = parsecmd(0)) != NEOF; popstackmark(&smark)) { + int i; + + i = evaltree(n, flags & ~(parser_eof() ? 0 : EV_EXIT)); if (n) - status = exitstatus; - popstackmark(&smark); + status = i; + if (evalskip) break; } @@ -192,13 +194,13 @@ evalstring(char *s, int flags) * exitstatus. */ -void +int evaltree(union node *n, int flags) { int checkexit = 0; - void (*evalfn)(union node *, int); + int (*evalfn)(union node *, int); unsigned isor; - int status; + int status = 0; if (n == NULL) { TRACE(("evaltree(NULL) called\n")); goto out; @@ -221,8 +223,7 @@ evaltree(union node *n, int flags) break; #endif case NNOT: - evaltree(n->nnot.com, EV_TESTED); - status = !exitstatus; + status = !evaltree(n->nnot.com, EV_TESTED); goto setstatus; case NREDIR: errlinno = lineno = n->nredir.linno; @@ -230,11 +231,8 @@ evaltree(union node *n, int flags) lineno -= funcline - 1; expredir(n->nredir.redirect); pushredir(n->nredir.redirect); - status = redirectsafe(n->nredir.redirect, REDIR_PUSH); - if (!status) { - evaltree(n->nredir.n, flags & EV_TESTED); - status = exitstatus; - } + status = redirectsafe(n->nredir.redirect, REDIR_PUSH) ?: + evaltree(n->nredir.n, flags & EV_TESTED); if (n->nredir.redirect) popredir(0); goto setstatus; @@ -242,8 +240,8 @@ evaltree(union node *n, int flags) #ifdef notyet if (eflag && !(flags & EV_TESTED)) checkexit = ~0; - evalcommand(n, flags, (struct backcmd *)NULL); - break; + status = evalcommand(n, flags, (struct backcmd *)NULL); + goto setstatus; #else evalfn = evalcommand; checkexit: @@ -278,43 +276,37 @@ checkexit: #error NOR + 1 != NSEMI #endif isor = n->type - NAND; - evaltree( - n->nbinary.ch1, - (flags | ((isor >> 1) - 1)) & EV_TESTED - ); - if (!exitstatus == isor) + status = evaltree(n->nbinary.ch1, + (flags | ((isor >> 1) - 1)) & EV_TESTED); + if (!status == isor || evalskip) break; - if (!evalskip) { - n = n->nbinary.ch2; + n = n->nbinary.ch2; evaln: - evalfn = evaltree; + evalfn = evaltree; calleval: - evalfn(n, flags); - break; - } - break; + status = evalfn(n, flags); + goto setstatus; case NIF: - evaltree(n->nif.test, EV_TESTED); + status = evaltree(n->nif.test, EV_TESTED); if (evalskip) break; - if (exitstatus == 0) { + if (!status) { n = n->nif.ifpart; goto evaln; } else if (n->nif.elsepart) { n = n->nif.elsepart; goto evaln; } - goto success; + status = 0; + goto setstatus; case NDEFUN: defun(n); -success: - status = 0; setstatus: exitstatus = status; break; } out: - if (checkexit & exitstatus) + if (checkexit & status) goto exexit; dotrap(); @@ -323,6 +315,8 @@ out: exexit: exraise(EXEXIT); } + + return exitstatus; } @@ -363,7 +357,7 @@ static int skiploop(void) } -STATIC void +STATIC int evalloop(union node *n, int flags) { int skip; @@ -375,33 +369,34 @@ evalloop(union node *n, int flags) do { int i; - evaltree(n->nbinary.ch1, EV_TESTED); + i = evaltree(n->nbinary.ch1, EV_TESTED); skip = skiploop(); + if (skip == SKIPFUNC) + status = i; if (skip) continue; - i = exitstatus; if (n->type != NWHILE) i = !i; if (i != 0) break; - evaltree(n->nbinary.ch2, flags); - status = exitstatus; + status = evaltree(n->nbinary.ch2, flags); skip = skiploop(); } while (!(skip & ~SKIPCONT)); - if (skip != SKIPFUNC) - exitstatus = status; loopnest--; + + return status; } -STATIC void +STATIC int evalfor(union node *n, int flags) { struct arglist arglist; union node *argp; struct strlist *sp; struct stackmark smark; + int status; errlinno = lineno = n->nfor.linno; if (funcline) @@ -414,28 +409,31 @@ evalfor(union node *n, int flags) } *arglist.lastp = NULL; - exitstatus = 0; + status = 0; loopnest++; flags &= EV_TESTED; for (sp = arglist.list ; sp ; sp = sp->next) { setvar(n->nfor.var, sp->text, 0); - evaltree(n->nfor.body, flags); + status = evaltree(n->nfor.body, flags); if (skiploop() & ~SKIPCONT) break; } loopnest--; popstackmark(&smark); + + return status; } -STATIC void +STATIC int evalcase(union node *n, int flags) { union node *cp; union node *patp; struct arglist arglist; struct stackmark smark; + int status = 0; errlinno = lineno = n->ncase.linno; if (funcline) @@ -444,12 +442,16 @@ evalcase(union node *n, int flags) setstackmark(&smark); arglist.lastp = &arglist.list; expandarg(n->ncase.expr, &arglist, EXP_TILDE); - exitstatus = 0; for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) { for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) { if (casematch(patp, arglist.list->text)) { - if (evalskip == 0) { - evaltree(cp->nclist.body, flags); + /* Ensure body is non-empty as otherwise + * EV_EXIT may prevent us from setting the + * exit status. + */ + if (evalskip == 0 && cp->nclist.body) { + status = evaltree(cp->nclist.body, + flags); } goto out; } @@ -457,6 +459,8 @@ evalcase(union node *n, int flags) } out: popstackmark(&smark); + + return status; } @@ -465,7 +469,7 @@ out: * Kick off a subshell to evaluate a tree. */ -STATIC void +STATIC int evalsubshell(union node *n, int flags) { struct job *jp; @@ -494,8 +498,8 @@ nofork: status = 0; if (! backgnd) status = waitforjob(jp); - exitstatus = status; INTON; + return status; } @@ -541,7 +545,7 @@ expredir(union node *n) * of all the rest.) */ -STATIC void +STATIC int evalpipe(union node *n, int flags) { struct job *jp; @@ -549,6 +553,7 @@ evalpipe(union node *n, int flags) int pipelen; int prevfd; int pip[2]; + int status = 0; TRACE(("evalpipe(0x%lx) called\n", (long)n)); pipelen = 0; @@ -589,10 +594,12 @@ evalpipe(union node *n, int flags) close(pip[1]); } if (n->npipe.backgnd == 0) { - exitstatus = waitforjob(jp); - TRACE(("evalpipe: job done exit status %d\n", exitstatus)); + status = waitforjob(jp); + TRACE(("evalpipe: job done exit status %d\n", status)); } INTON; + + return status; } @@ -679,7 +686,7 @@ parse_command_args(char **argv, const char **path) * Execute a simple command. */ -STATIC void +STATIC int #ifdef notyet evalcommand(union node *cmd, int flags, struct backcmd *backcmd) #else @@ -849,7 +856,7 @@ bail: INTOFF; jp = makejob(cmd, 1); if (forkshell(jp, cmd, FORK_FG) != 0) { - exitstatus = waitforjob(jp); + status = waitforjob(jp); INTON; break; } @@ -868,17 +875,19 @@ bail: if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) { if (exception == EXERROR && spclbltin <= 0) { FORCEINTON; - break; + goto readstatus; } raise: longjmp(handler->loc, 1); } - break; + goto readstatus; case CMDFUNCTION: poplocalvars(1); if (evalfun(cmdentry.u.func, argc, argv, flags)) goto raise; +readstatus: + status = exitstatus; break; } @@ -894,6 +903,8 @@ out: */ setvar("_", lastarg, 0); popstackmark(&smark); + + return status; } STATIC int diff --git a/usr/dash/eval.h b/usr/dash/eval.h index 6e8acdaf..63e7d865 100644 --- a/usr/dash/eval.h +++ b/usr/dash/eval.h @@ -53,7 +53,7 @@ struct backcmd { /* result of evalbackcmd */ int evalstring(char *, int); union node; /* BLETCH for ansi C */ -void evaltree(union node *, int); +int evaltree(union node *, int); void evalbackcmd(union node *, struct backcmd *); extern int evalskip; diff --git a/usr/dash/main.c b/usr/dash/main.c index 497ac160..fcd3e7d2 100644 --- a/usr/dash/main.c +++ b/usr/dash/main.c @@ -225,11 +225,13 @@ cmdloop(int top) } numeof++; } else if (nflag == 0) { + int i; + job_warning = (job_warning == 2) ? 1 : 0; numeof = 0; - evaltree(n, 0); + i = evaltree(n, 0); if (n) - status = exitstatus; + status = i; } popstackmark(&smark);
Reasonably Related Threads
- [klibc:update-dash] dash: eval: Return status in eval functions
- [klibc:update-dash] dash: eval: avoid leaking memory associated with redirections
- [klibc:master] [EVAL] Remove unused EV_BACKCMD flag
- [klibc:update-dash] dash: eval: Reset handler when entering a subshell
- [klibc:update-dash] [EVAL] Move common skipcount logic into skiploop