sh: Do not run callers' exception handlers in subshells.

Reset the exception handler in the child to main's.

This avoids inappropriate double cleanups or shell duplication when the
exception is caught, such as 'fc' and future 'command eval' and 'command .'.
This commit is contained in:
Jilles Tjoelker 2009-12-25 20:21:35 +00:00
parent b1625b09d9
commit 29d401c22d
4 changed files with 39 additions and 3 deletions

View File

@ -757,6 +757,7 @@ forkshell(struct job *jp, union node *n, int mode)
TRACE(("Child shell %d\n", (int)getpid()));
wasroot = rootshell;
rootshell = 0;
handler = &main_handler;
closescript();
INTON;
clear_traps();

View File

@ -75,6 +75,7 @@ __FBSDID("$FreeBSD$");
int rootpid;
int rootshell;
struct jmploc main_handler;
STATIC void read_profile(char *);
STATIC char *find_dot_file(char *);
@ -90,14 +91,13 @@ STATIC char *find_dot_file(char *);
int
main(int argc, char *argv[])
{
struct jmploc jmploc;
struct stackmark smark;
volatile int state;
char *shinit;
(void) setlocale(LC_ALL, "");
state = 0;
if (setjmp(jmploc.loc)) {
if (setjmp(main_handler.loc)) {
/*
* When a shell procedure is executed, we raise the
* exception EXSHELLPROC to clean up before executing
@ -143,7 +143,7 @@ main(int argc, char *argv[])
else
goto state4;
}
handler = &jmploc;
handler = &main_handler;
#ifdef DEBUG
opentrace();
trputs("Shell args: "); trargs(argv);

View File

@ -35,6 +35,7 @@
extern int rootpid; /* pid of main shell */
extern int rootshell; /* true if we aren't a child of the main shell */
extern struct jmploc main_handler; /* top level exception handler */
void readcmdfile(const char *);
void cmdloop(int);

View File

@ -0,0 +1,34 @@
# $FreeBSD$
set -e
trap 'echo Broken pipe -- test failed' pipe
P=${TMPDIR:-/tmp}
cd $P
T=$(mktemp -d sh-test.XXXXXX)
cd $T
mkfifo input output error
HISTFILE=/dev/null sh +m -i <input >output 2>error &
exec 3>input
{
# Command not found, containing slash
echo '/var/empty/nonexistent' >&3
# Read error message, shell will read new input now
read dummy <&5
# Execute bad command again
echo 'fc -e true; echo continued' >&3
read dummy <&5
read line <&4 && [ "$line" = continued ] && : ${rc:=0}
exec 3>&-
# Old sh duplicates itself after the fc, producing another line
# of output.
if read line <&4; then
echo "Extraneous output: $line"
rc=1
fi
} 4<output 5<error
exec 3>&-
rm input output error
rmdir ${P}/${T}
exit ${rc:-3}