From: Peter Avalos Date: Sun, 21 Aug 2011 20:54:19 +0000 (-0700) Subject: sh: Save/restore changed variables in optimized command substitution. X-Git-Tag: v2.12.0~150 X-Git-Url: https://gitweb.dragonflybsd.org/~nant/dragonfly.git/commitdiff_plain/329310630e302987fe923eb19b075d3cdd16a9f6 sh: Save/restore changed variables in optimized command substitution. In optimized command substitution, save and restore any variables changed by expansions (${var=value} and $((var=assigned))), instead of trying to determine if an expansion may cause such changes. If $! is referenced in optimized command substitution, do not cause jobs to be remembered longer. This fixes $(jobs $!) again, simplifies the man page and shortens the code. Obtained-from: FreeBSD 223024 --- diff --git a/bin/sh/eval.c b/bin/sh/eval.c index 1bf6a0a57b..6f0615e096 100644 --- a/bin/sh/eval.c +++ b/bin/sh/eval.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)eval.c 8.9 (Berkeley) 6/8/95 - * $FreeBSD: src/bin/sh/eval.c,v 1.108 2011/06/09 23:12:23 jilles Exp $ + * $FreeBSD: src/bin/sh/eval.c,v 1.109 2011/06/12 23:06:04 jilles Exp $ */ #include @@ -573,14 +573,8 @@ 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; + return (n->type == NCMD); } /* @@ -598,6 +592,7 @@ evalbackcmd(union node *n, struct backcmd *result) struct stackmark smark; /* unnecessary */ struct jmploc jmploc; struct jmploc *savehandler; + struct localvar *savelocalvars; setstackmark(&smark); result->fd = -1; @@ -610,12 +605,18 @@ evalbackcmd(union node *n, struct backcmd *result) } if (is_valid_fast_cmdsubst(n)) { exitstatus = oexitstatus; + savelocalvars = localvars; + localvars = NULL; + forcelocal++; savehandler = handler; if (setjmp(jmploc.loc)) { if (exception == EXERROR || exception == EXEXEC) exitstatus = 2; else if (exception != 0) { handler = savehandler; + forcelocal--; + poplocalvars(); + localvars = savelocalvars; longjmp(handler->loc, 1); } } else { @@ -623,6 +624,9 @@ evalbackcmd(union node *n, struct backcmd *result) evalcommand(n, EV_BACKCMD, result); } handler = savehandler; + forcelocal--; + poplocalvars(); + localvars = savelocalvars; } else { exitstatus = 0; if (pipe(pip) < 0) diff --git a/bin/sh/expand.c b/bin/sh/expand.c index 1f8298548c..4293319e90 100644 --- a/bin/sh/expand.c +++ b/bin/sh/expand.c @@ -36,7 +36,7 @@ * SUCH DAMAGE. * * @(#)expand.c 8.5 (Berkeley) 5/15/95 - * $FreeBSD: src/bin/sh/expand.c,v 1.87 2011/06/09 23:12:23 jilles Exp $ + * $FreeBSD: src/bin/sh/expand.c,v 1.89 2011/06/12 23:06:04 jilles Exp $ */ #include @@ -1619,78 +1619,6 @@ cvtnum(int num, char *buf) return 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 3de59b501e..34c3a597aa 100644 --- a/bin/sh/expand.h +++ b/bin/sh/expand.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)expand.h 8.2 (Berkeley) 5/4/95 - * $FreeBSD: src/bin/sh/expand.h,v 1.15 2010/12/28 21:27:08 jilles Exp $ + * $FreeBSD: src/bin/sh/expand.h,v 1.16 2011/06/12 23:06:04 jilles Exp $ */ struct strlist { @@ -67,5 +67,4 @@ 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 **); diff --git a/bin/sh/jobs.c b/bin/sh/jobs.c index ae3bd03896..39dba1929b 100644 --- a/bin/sh/jobs.c +++ b/bin/sh/jobs.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)jobs.c 8.5 (Berkeley) 5/4/95 - * $FreeBSD: src/bin/sh/jobs.c,v 1.93 2011/06/04 15:05:52 jilles Exp $ + * $FreeBSD: src/bin/sh/jobs.c,v 1.94 2011/06/12 23:06:04 jilles Exp $ */ #include @@ -69,6 +69,7 @@ #include "memalloc.h" #include "error.h" #include "mystring.h" +#include "var.h" static struct job *jobtab; /* array of jobs */ @@ -797,6 +798,7 @@ forkshell(struct job *jp, union node *n, int mode) handler = &main_handler; closescript(); INTON; + forcelocal = 0; clear_traps(); #if JOBS jobctl = 0; /* do job control only in root shell */ @@ -1124,7 +1126,7 @@ backgndpidset(void) pid_t backgndpidval(void) { - if (bgjob != NULL) + if (bgjob != NULL && !forcelocal) bgjob->remembered = 1; return backgndpid; } diff --git a/bin/sh/sh.1 b/bin/sh/sh.1 index 6a5b05195c..eecb026833 100644 --- a/bin/sh/sh.1 +++ b/bin/sh/sh.1 @@ -34,7 +34,7 @@ .\" SUCH DAMAGE. .\" .\" from: @(#)sh.1 8.6 (Berkeley) 5/4/95 -.\" $FreeBSD: src/bin/sh/sh.1,v 1.167 2011/06/10 22:42:00 jilles Exp $ +.\" $FreeBSD: src/bin/sh/sh.1,v 1.168 2011/06/12 23:06:04 jilles Exp $ .\" .Dd August 21, 2011 .Dt SH 1 @@ -1547,10 +1547,7 @@ except that the built-in commands and .Ic trap return information about the main shell environment -if they are the only command in a command substitution -and the substitutions in the command cannot cause side effects -(such as from assigning values to variables or referencing -.Li $! ). +if they are the only command in a command substitution. .Ss Arithmetic Expansion Arithmetic expansion provides a mechanism for evaluating an arithmetic expression and substituting its value. diff --git a/bin/sh/var.c b/bin/sh/var.c index 16552a39f6..54420b6128 100644 --- a/bin/sh/var.c +++ b/bin/sh/var.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)var.c 8.3 (Berkeley) 5/4/95 - * $FreeBSD: src/bin/sh/var.c,v 1.60 2011/05/15 22:09:27 jilles Exp $ + * $FreeBSD: src/bin/sh/var.c,v 1.61 2011/06/12 23:06:04 jilles Exp $ */ #include @@ -93,6 +93,8 @@ struct var vps4; struct var vvers; static struct var voptind; +int forcelocal; + static const struct varinit varinit[] = { #ifndef NO_HISTORY { &vhistsize, VUNSET, "HISTSIZE=", @@ -322,6 +324,8 @@ setvareq(char *s, int flags) if (aflag) flags |= VEXPORT; + if (forcelocal && !(flags & (VNOSET | VNOLOCAL))) + mklocal(s); vp = find_var(s, &vpp, &nlen); if (vp != NULL) { if (vp->flags & VREADONLY) @@ -737,9 +741,9 @@ mklocal(char *name) vp = find_var(name, &vpp, NULL); if (vp == NULL) { if (strchr(name, '=')) - setvareq(savestr(name), VSTRFIXED); + setvareq(savestr(name), VSTRFIXED | VNOLOCAL); else - setvar(name, NULL, VSTRFIXED); + setvar(name, NULL, VSTRFIXED | VNOLOCAL); vp = *vpp; /* the new variable */ lvp->text = NULL; lvp->flags = VUNSET; @@ -748,7 +752,7 @@ mklocal(char *name) lvp->flags = vp->flags; vp->flags |= VSTRFIXED|VTEXTFIXED; if (name[vp->name_len] == '=') - setvareq(savestr(name), 0); + setvareq(savestr(name), VNOLOCAL); } } lvp->vp = vp; diff --git a/bin/sh/var.h b/bin/sh/var.h index d23ae32c76..7274b2b7b9 100644 --- a/bin/sh/var.h +++ b/bin/sh/var.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)var.h 8.2 (Berkeley) 5/4/95 - * $FreeBSD: src/bin/sh/var.h,v 1.22 2011/05/08 17:40:10 jilles Exp $ + * $FreeBSD: src/bin/sh/var.h,v 1.23 2011/06/12 23:06:04 jilles Exp $ */ /* @@ -50,6 +50,7 @@ #define VUNSET 0x20 /* the variable is not set */ #define VNOFUNC 0x40 /* don't call the callback function */ #define VNOSET 0x80 /* do not set variable - just readonly test */ +#define VNOLOCAL 0x100 /* ignore forcelocal */ struct var { @@ -72,6 +73,7 @@ struct localvar { struct localvar *localvars; +extern int forcelocal; extern struct var vifs; extern struct var vmail;