diff options
Diffstat (limited to 'bin/sh')
-rw-r--r-- | bin/sh/eval.c | 16 | ||||
-rw-r--r-- | bin/sh/expand.c | 72 | ||||
-rw-r--r-- | bin/sh/expand.h | 1 |
3 files changed, 88 insertions, 1 deletions
diff --git a/bin/sh/eval.c b/bin/sh/eval.c index 596a86c..903f783 100644 --- a/bin/sh/eval.c +++ b/bin/sh/eval.c @@ -94,6 +94,7 @@ static void evalsubshell(union node *, int); static void evalredir(union node *, int); static void expredir(union node *); static void evalpipe(union node *); +static int is_valid_fast_cmdsubst(union node *n); static void evalcommand(union node *, int, struct backcmd *); static void prehash(union node *); @@ -565,6 +566,19 @@ evalpipe(union node *n) +static int +is_valid_fast_cmdsubst(union node *n) +{ + union node *argp; + + if (n->type != NCMD) + return 0; + for (argp = n->ncmd.args ; argp ; argp = argp->narg.next) + if (expandhassideeffects(argp->narg.text)) + return 0; + return 1; +} + /* * Execute a command inside back quotes. If it's a builtin command, we * want to save its output in a block obtained from malloc. Otherwise @@ -590,7 +604,7 @@ evalbackcmd(union node *n, struct backcmd *result) exitstatus = 0; goto out; } - if (n->type == NCMD) { + if (is_valid_fast_cmdsubst(n)) { exitstatus = oexitstatus; savehandler = handler; if (setjmp(jmploc.loc)) { diff --git a/bin/sh/expand.c b/bin/sh/expand.c index b03cc3b..b2046cc 100644 --- a/bin/sh/expand.c +++ b/bin/sh/expand.c @@ -1570,6 +1570,78 @@ cvtnum(int num, char *buf) } /* + * Check statically if expanding a string may have side effects. + */ +int +expandhassideeffects(const char *p) +{ + int c; + int arinest; + + arinest = 0; + while ((c = *p++) != '\0') { + switch (c) { + case CTLESC: + p++; + break; + case CTLVAR: + c = *p++; + /* Expanding $! sets the job to remembered. */ + if (*p == '!') + return 1; + if ((c & VSTYPE) == VSASSIGN) + return 1; + /* + * If we are in arithmetic, the parameter may contain + * '=' which may cause side effects. Exceptions are + * the length of a parameter and $$, $# and $? which + * are always numeric. + */ + if ((c & VSTYPE) == VSLENGTH) { + while (*p != '=') + p++; + p++; + break; + } + if ((*p == '$' || *p == '#' || *p == '?') && + p[1] == '=') { + p += 2; + break; + } + if (arinest > 0) + return 1; + break; + case CTLBACKQ: + case CTLBACKQ | CTLQUOTE: + if (arinest > 0) + return 1; + break; + case CTLARI: + arinest++; + break; + case CTLENDARI: + arinest--; + break; + case '=': + if (*p == '=') { + /* Allow '==' operator. */ + p++; + continue; + } + if (arinest > 0) + return 1; + break; + case '!': case '<': case '>': + /* Allow '!=', '<=', '>=' operators. */ + if (*p == '=') + p++; + break; + } + } + return 0; +} + +/* * Do most of the work for wordexp(3). */ diff --git a/bin/sh/expand.h b/bin/sh/expand.h index a4bb198..be08dec 100644 --- a/bin/sh/expand.h +++ b/bin/sh/expand.h @@ -63,4 +63,5 @@ void expari(int); int patmatch(const char *, const char *, int); void rmescapes(char *); int casematch(union node *, const char *); +int expandhassideeffects(const char *); int wordexpcmd(int, char **); |