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.
This commit is contained in:
jilles 2016-01-10 16:31:28 +00:00
parent 21632a9bd9
commit d42a26ab20
4 changed files with 29 additions and 2 deletions

View File

@ -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);

View File

@ -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

View File

@ -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" ]

View File

@ -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);
}