From adba77a62e7254b58df4e32a5142e1ee3a062aa7 Mon Sep 17 00:00:00 2001 From: Jilles Tjoelker Date: Thu, 7 Jan 2016 20:48:24 +0000 Subject: [PATCH] sh: Ensure OPTIND=1 in subshell without forking does not affect outer env. Command substitutions containing a single simple command and here-document expansion are performed in a subshell environment, but may not fork. Any modified state of the shell environment should be restored afterward. The state that OPTIND=1 had been done was not saved and restored here. Note that the other parts of shellparam need not be saved and restored, since they are not modified in these situations (a fork is done before such modifications). --- bin/sh/eval.c | 7 +++++++ bin/sh/tests/builtins/Makefile | 1 + bin/sh/tests/builtins/getopts10.0 | 11 +++++++++++ 3 files changed, 19 insertions(+) create mode 100644 bin/sh/tests/builtins/getopts10.0 diff --git a/bin/sh/eval.c b/bin/sh/eval.c index 46c00de75b99..5a3f8e71883b 100644 --- a/bin/sh/eval.c +++ b/bin/sh/eval.c @@ -496,10 +496,12 @@ exphere(union node *redir, struct arglist *fn) struct jmploc *savehandler; struct localvar *savelocalvars; int need_longjmp = 0; + unsigned char saveoptreset; redir->nhere.expdoc = ""; savelocalvars = localvars; localvars = NULL; + saveoptreset = shellparam.reset; forcelocal++; savehandler = handler; if (setjmp(jmploc.loc)) @@ -514,6 +516,7 @@ exphere(union node *redir, struct arglist *fn) forcelocal--; poplocalvars(); localvars = savelocalvars; + shellparam.reset = saveoptreset; if (need_longjmp) longjmp(handler->loc, 1); INTON; @@ -647,6 +650,7 @@ evalbackcmd(union node *n, struct backcmd *result) struct jmploc jmploc; struct jmploc *savehandler; struct localvar *savelocalvars; + unsigned char saveoptreset; result->fd = -1; result->buf = NULL; @@ -661,6 +665,7 @@ evalbackcmd(union node *n, struct backcmd *result) if (is_valid_fast_cmdsubst(n)) { savelocalvars = localvars; localvars = NULL; + saveoptreset = shellparam.reset; forcelocal++; savehandler = handler; if (setjmp(jmploc.loc)) { @@ -671,6 +676,7 @@ evalbackcmd(union node *n, struct backcmd *result) forcelocal--; poplocalvars(); localvars = savelocalvars; + shellparam.reset = saveoptreset; longjmp(handler->loc, 1); } } else { @@ -681,6 +687,7 @@ evalbackcmd(union node *n, struct backcmd *result) forcelocal--; poplocalvars(); localvars = savelocalvars; + shellparam.reset = saveoptreset; } else { if (pipe(pip) < 0) error("Pipe call failed: %s", strerror(errno)); diff --git a/bin/sh/tests/builtins/Makefile b/bin/sh/tests/builtins/Makefile index 63e6ab56514d..750e61569de0 100644 --- a/bin/sh/tests/builtins/Makefile +++ b/bin/sh/tests/builtins/Makefile @@ -95,6 +95,7 @@ FILES+= getopts6.0 FILES+= getopts7.0 FILES+= getopts8.0 getopts8.0.stdout FILES+= getopts9.0 getopts9.0.stdout +FILES+= getopts10.0 FILES+= hash1.0 hash1.0.stdout FILES+= hash2.0 hash2.0.stdout FILES+= hash3.0 hash3.0.stdout diff --git a/bin/sh/tests/builtins/getopts10.0 b/bin/sh/tests/builtins/getopts10.0 new file mode 100644 index 000000000000..a88e6ca3e85e --- /dev/null +++ b/bin/sh/tests/builtins/getopts10.0 @@ -0,0 +1,11 @@ +# $FreeBSD$ + +set -- -x arg +opt=not +getopts x opt +r1=$? OPTIND1=$OPTIND opt1=$opt +: $(: $((OPTIND = 1))) +getopts x opt +r2=$? OPTIND2=$OPTIND +[ "$r1" = 0 ] && [ "$OPTIND1" = 2 ] && [ "$opt1" = x ] && [ "$r2" != 0 ] && + [ "$OPTIND2" = 2 ]