diff options
author | jilles <jilles@FreeBSD.org> | 2016-01-10 16:31:28 +0000 |
---|---|---|
committer | jilles <jilles@FreeBSD.org> | 2016-01-10 16:31:28 +0000 |
commit | d42a26ab2089d53213cf28c22508023ea16e7efb (patch) | |
tree | 0b136c34e36d2b2c085d1618158aaa9df9b91c19 | |
parent | 21632a9bd96fd68b505602bfdd4850ab1e18574a (diff) | |
download | FreeBSD-src-d42a26ab2089d53213cf28c22508023ea16e7efb.zip FreeBSD-src-d42a26ab2089d53213cf28c22508023ea16e7efb.tar.gz |
sh: Update associated state when restoring locals while leaving a function.
Some variables like PATH call a function when modified. Make sure to call
this also when leaving a function where such a variable was made local.
Make sure to restore local variables before shellparam, so getopts state is
not clobbered.
-rw-r--r-- | bin/sh/eval.c | 4 | ||||
-rw-r--r-- | bin/sh/tests/builtins/Makefile | 1 | ||||
-rw-r--r-- | bin/sh/tests/builtins/local5.0 | 15 | ||||
-rw-r--r-- | bin/sh/var.c | 11 |
4 files changed, 29 insertions, 2 deletions
diff --git a/bin/sh/eval.c b/bin/sh/eval.c index 5a3f8e7..949157d 100644 --- a/bin/sh/eval.c +++ b/bin/sh/eval.c @@ -1039,12 +1039,12 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd) reffunc(cmdentry.u.func); savehandler = handler; if (setjmp(jmploc.loc)) { - freeparam(&shellparam); - shellparam = saveparam; popredir(); unreffunc(cmdentry.u.func); poplocalvars(); localvars = savelocalvars; + freeparam(&shellparam); + shellparam = saveparam; funcnest--; handler = savehandler; longjmp(handler->loc, 1); diff --git a/bin/sh/tests/builtins/Makefile b/bin/sh/tests/builtins/Makefile index 11240ca..1511f70 100644 --- a/bin/sh/tests/builtins/Makefile +++ b/bin/sh/tests/builtins/Makefile @@ -111,6 +111,7 @@ FILES+= local1.0 FILES+= local2.0 FILES+= local3.0 FILES+= local4.0 +FILES+= local5.0 .if ${MK_NLS} != "no" FILES+= locale1.0 .endif diff --git a/bin/sh/tests/builtins/local5.0 b/bin/sh/tests/builtins/local5.0 new file mode 100644 index 0000000..2f2a14e --- /dev/null +++ b/bin/sh/tests/builtins/local5.0 @@ -0,0 +1,15 @@ +# $FreeBSD$ + +f() { + local PATH IFS elem + IFS=: + for elem in ''$PATH''; do + PATH=/var/empty/$elem:$PATH + done + ls -d / >/dev/null +} + +p1=$(command -v ls) +f +p2=$(command -v ls) +[ "$p1" = "$p2" ] diff --git a/bin/sh/var.c b/bin/sh/var.c index d401361..3af7dbe 100644 --- a/bin/sh/var.c +++ b/bin/sh/var.c @@ -791,6 +791,7 @@ poplocalvars(void) { struct localvar *lvp; struct var *vp; + int islocalevar; INTOFF; while ((lvp = localvars) != NULL) { @@ -803,10 +804,20 @@ poplocalvars(void) } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) { (void)unsetvar(vp->text); } else { + islocalevar = (vp->flags | lvp->flags) & VEXPORT && + localevar(lvp->text); if ((vp->flags & VTEXTFIXED) == 0) ckfree(vp->text); vp->flags = lvp->flags; vp->text = lvp->text; + if (vp->func) + (*vp->func)(vp->text + vp->name_len + 1); + if (islocalevar) { + change_env(vp->text, vp->flags & VEXPORT && + (vp->flags & VUNSET) == 0); + setlocale(LC_ALL, ""); + updatecharset(); + } } ckfree(lvp); } |