ash: fix var_leak.tests so that it actually catches the NOFORK bug
+ document the bug better Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
c7f95d23f6
commit
42c4b2e3b5
22
shell/ash.c
22
shell/ash.c
@ -9179,12 +9179,14 @@ evalcommand(union node *cmd, int flags)
|
|||||||
|
|
||||||
/* Execute the command. */
|
/* Execute the command. */
|
||||||
switch (cmdentry.cmdtype) {
|
switch (cmdentry.cmdtype) {
|
||||||
default:
|
default: {
|
||||||
|
|
||||||
#if ENABLE_FEATURE_SH_NOFORK
|
#if ENABLE_FEATURE_SH_NOFORK
|
||||||
/* Hmmm... shouldn't it happen somewhere in forkshell() instead?
|
/* (1) BUG: if variables are set, we need to fork, or save/restore them
|
||||||
* Why "fork off a child process if necessary" doesn't apply to NOFORK? */
|
* around run_nofork_applet() call.
|
||||||
{
|
* (2) Should this check also be done in forkshell()?
|
||||||
|
* (perhaps it should, so that "VAR=VAL nofork" at least avoids exec...)
|
||||||
|
*/
|
||||||
/* find_command() encodes applet_no as (-2 - applet_no) */
|
/* find_command() encodes applet_no as (-2 - applet_no) */
|
||||||
int applet_no = (- cmdentry.u.index - 2);
|
int applet_no = (- cmdentry.u.index - 2);
|
||||||
if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
|
if (applet_no >= 0 && APPLET_IS_NOFORK(applet_no)) {
|
||||||
@ -9193,10 +9195,13 @@ evalcommand(union node *cmd, int flags)
|
|||||||
exitstatus = run_nofork_applet(applet_no, argv);
|
exitstatus = run_nofork_applet(applet_no, argv);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
/* Fork off a child process if necessary. */
|
/* Can we avoid forking off? For example, very last command
|
||||||
|
* in a script or a subshell does not need forking,
|
||||||
|
* we can just exec it.
|
||||||
|
*/
|
||||||
if (!(flags & EV_EXIT) || may_have_traps) {
|
if (!(flags & EV_EXIT) || may_have_traps) {
|
||||||
|
/* No, forking off a child is necessary */
|
||||||
INT_OFF;
|
INT_OFF;
|
||||||
jp = makejob(/*cmd,*/ 1);
|
jp = makejob(/*cmd,*/ 1);
|
||||||
if (forkshell(jp, cmd, FORK_FG) != 0) {
|
if (forkshell(jp, cmd, FORK_FG) != 0) {
|
||||||
@ -9213,7 +9218,7 @@ evalcommand(union node *cmd, int flags)
|
|||||||
listsetvar(varlist.list, VEXPORT|VSTACK);
|
listsetvar(varlist.list, VEXPORT|VSTACK);
|
||||||
shellexec(argv, path, cmdentry.u.index);
|
shellexec(argv, path, cmdentry.u.index);
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
|
} /* default */
|
||||||
case CMDBUILTIN:
|
case CMDBUILTIN:
|
||||||
cmdenviron = varlist.list;
|
cmdenviron = varlist.list;
|
||||||
if (cmdenviron) {
|
if (cmdenviron) {
|
||||||
@ -9258,7 +9263,8 @@ evalcommand(union node *cmd, int flags)
|
|||||||
if (evalfun(cmdentry.u.func, argc, argv, flags))
|
if (evalfun(cmdentry.u.func, argc, argv, flags))
|
||||||
goto raise;
|
goto raise;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
} /* switch */
|
||||||
|
|
||||||
out:
|
out:
|
||||||
popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
|
popredir(/*drop:*/ cmd_is_exec, /*restore:*/ cmd_is_exec);
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
should be empty: ''
|
should be empty: ''
|
||||||
|
should be empty: ''
|
||||||
should be not empty: 'val2'
|
should be not empty: 'val2'
|
||||||
should be not empty: 'val3'
|
should be not empty: 'val3'
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
# true is a regular builtin, varibale should not leak out of it
|
# cat is an external program, variable should not leak out of it.
|
||||||
# this currently fails with CONFIG_FEATURE_SH_NOFORK=y
|
# this currently fails with CONFIG_FEATURE_SH_NOFORK=y
|
||||||
VAR=''
|
VAR=''
|
||||||
|
VAR=val0 cat /dev/null
|
||||||
|
echo "should be empty: '$VAR'"
|
||||||
|
|
||||||
|
# true is a regular builtin, variable should not leak out of it.
|
||||||
|
VAR=''
|
||||||
VAR=val1 true
|
VAR=val1 true
|
||||||
echo "should be empty: '$VAR'"
|
echo "should be empty: '$VAR'"
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user