mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-02-15 04:32:24 +00:00
This should fix various crashes that remain, at least: * when running a PS2 discipline at parse time * when pressing Ctrl+C on a PS2 prompt * when a special builtin within a discipline throws an error within a virtual subshell src/cmd/ksh93/sh/nvdisc.c: - In both assign() which handles .set disciplines and lookup() which handles .get disciplines, to stop errors in discipline functions from wreaking havoc: - Save, reinitialise and restore the lexer state in case the discipline is run at parse time. This happens with PS2; I'm not currently aware of other contexts but that doesn't mean there aren't any or that there won't be any. Plus, I determined by experimenting that doing this here seems to be the only way to make it work reliably. Thankfully the overhead is low. - Check the topfd redirection state and run sh_iorestore() if needed. Without this, if a special builtin with a redirection throws an error in a discipline function, its redirection(s) remain permanent. For example, 'trap --bad-option 2>/dev/null' in a PS2.get() discipline would kill standard error, including all your prompts. src/cmd/ksh93/sh/io.c: io_prompt(): - Before getting the value of the PS2 prompt, save the stack state and restore it after. This stops a PS2.get discipline function from corrupting a command substitution that the user is typing. Doing this in assign()/lookup() is ineffective, so do it here. Fixes: https://github.com/ksh93/ksh/issues/347
This commit is contained in:
parent
1f5ad85cd4
commit
a2bc49bed1
4 changed files with 61 additions and 11 deletions
|
@ -669,6 +669,8 @@ make install
|
|||
done main.o generated
|
||||
make nvdisc.o
|
||||
make sh/nvdisc.c
|
||||
prev include/shlex.h implicit
|
||||
prev include/io.h implicit
|
||||
prev include/path.h implicit
|
||||
prev include/builtins.h implicit
|
||||
prev include/variables.h implicit
|
||||
|
|
|
@ -2186,8 +2186,15 @@ static int io_prompt(Shell_t *shp,Sfio_t *iop,register int flag)
|
|||
goto done;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
/* PS2 prompt. Save stack state to avoid corrupting command substitutions
|
||||
* in case we're executing a PS2.get discipline function at parse time. */
|
||||
int savestacktop = staktell();
|
||||
char *savestackptr = stakfreeze(0);
|
||||
cp = nv_getval(sh_scoped(shp,PS2NOD));
|
||||
stakset(savestackptr, savestacktop);
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
cp = nv_getval(sh_scoped(shp,PS3NOD));
|
||||
break;
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
#include "variables.h"
|
||||
#include "builtins.h"
|
||||
#include "path.h"
|
||||
#include "io.h"
|
||||
#include "shlex.h"
|
||||
|
||||
static void assign(Namval_t*,const char*,int,Namfun_t*);
|
||||
|
||||
|
@ -283,21 +285,30 @@ static void assign(Namval_t *np,const char* val,int flags,Namfun_t *handle)
|
|||
nq = vp->disc[type=UNASSIGN];
|
||||
if(nq && !isblocked(bp,type))
|
||||
{
|
||||
int bflag=0, savexit=sh.savexit, jmpval=0;
|
||||
struct checkpt buff;
|
||||
struct checkpt checkpoint;
|
||||
int jmpval;
|
||||
int savexit = sh.savexit;
|
||||
Lex_t *lexp = (Lex_t*)sh.lex_context, savelex;
|
||||
int bflag;
|
||||
/* disciplines like PS2 may run at parse time; save, reinit and restore the lexer state */
|
||||
savelex = *lexp;
|
||||
sh_lexopen(lexp, &sh, 0); /* needs full init (0), not what it calls reinit (1) */
|
||||
block(bp,type);
|
||||
if (type==APPEND && (bflag= !isblocked(bp,LOOKUPS)))
|
||||
if(bflag = (type==APPEND && !isblocked(bp,LOOKUPS)))
|
||||
block(bp,LOOKUPS);
|
||||
sh_pushcontext(&sh,&buff,1);
|
||||
jmpval = sigsetjmp(buff.buff,0);
|
||||
sh_pushcontext(&sh, &checkpoint, 1);
|
||||
jmpval = sigsetjmp(checkpoint.buff, 0);
|
||||
if(!jmpval)
|
||||
sh_fun(nq,np,(char**)0);
|
||||
sh_popcontext(&sh,&buff);
|
||||
sh_popcontext(&sh, &checkpoint);
|
||||
if(sh.topfd != checkpoint.topfd)
|
||||
sh_iorestore(&sh, checkpoint.topfd, jmpval);
|
||||
unblock(bp,type);
|
||||
if(bflag)
|
||||
unblock(bp,LOOKUPS);
|
||||
if(!vp->disc[type])
|
||||
chktfree(np,vp);
|
||||
*lexp = savelex;
|
||||
sh.savexit = savexit; /* avoid influencing $? */
|
||||
}
|
||||
if(nv_isarray(np))
|
||||
|
@ -381,8 +392,13 @@ static char* lookup(Namval_t *np, int type, Sfdouble_t *dp,Namfun_t *handle)
|
|||
union Value *up = np->nvalue.up;
|
||||
if(nq && !isblocked(bp,type))
|
||||
{
|
||||
int savexit = sh.savexit, jmpval = 0;
|
||||
struct checkpt buff;
|
||||
struct checkpt checkpoint;
|
||||
int jmpval;
|
||||
int savexit = sh.savexit;
|
||||
Lex_t *lexp = (Lex_t*)sh.lex_context, savelex;
|
||||
/* disciplines like PS2 may run at parse time; save, reinit and restore the lexer state */
|
||||
savelex = *lexp;
|
||||
sh_lexopen(lexp, &sh, 0); /* needs full init (0), not what it calls reinit (1) */
|
||||
node = *SH_VALNOD;
|
||||
if(!nv_isnull(SH_VALNOD))
|
||||
{
|
||||
|
@ -395,11 +411,13 @@ static char* lookup(Namval_t *np, int type, Sfdouble_t *dp,Namfun_t *handle)
|
|||
nv_setsize(SH_VALNOD,10);
|
||||
}
|
||||
block(bp,type);
|
||||
sh_pushcontext(&sh,&buff,1);
|
||||
jmpval = sigsetjmp(buff.buff,0);
|
||||
sh_pushcontext(&sh, &checkpoint, 1);
|
||||
jmpval = sigsetjmp(checkpoint.buff, 0);
|
||||
if(!jmpval)
|
||||
sh_fun(nq,np,(char**)0);
|
||||
sh_popcontext(&sh,&buff);
|
||||
sh_popcontext(&sh, &checkpoint);
|
||||
if(sh.topfd != checkpoint.topfd)
|
||||
sh_iorestore(&sh, checkpoint.topfd, jmpval);
|
||||
unblock(bp,type);
|
||||
if(!vp->disc[type])
|
||||
chktfree(np,vp);
|
||||
|
@ -416,6 +434,7 @@ static char* lookup(Namval_t *np, int type, Sfdouble_t *dp,Namfun_t *handle)
|
|||
/* restore everything but the nvlink field */
|
||||
memcpy(&SH_VALNOD->nvname, &node.nvname, sizeof(node)-sizeof(node.nvlink));
|
||||
}
|
||||
*lexp = savelex;
|
||||
sh.savexit = savexit; /* avoid influencing $? */
|
||||
}
|
||||
if(nv_isarray(np))
|
||||
|
|
|
@ -889,5 +889,27 @@ w true); echo "Exit status is $?"
|
|||
u Exit status is 0
|
||||
!
|
||||
|
||||
# err_exit #
|
||||
tst $LINENO <<"!"
|
||||
L interrupted PS2 discipline function
|
||||
# https://github.com/ksh93/ksh/issues/347
|
||||
|
||||
d 15
|
||||
p :test-1:
|
||||
w PS2.get() { trap --bad-option 2>/dev/null; .sh.value="NOT REACHED"; }
|
||||
p :test-2:
|
||||
w echo \$\(
|
||||
r :test-2: echo \$\(
|
||||
w echo one \\
|
||||
r > echo one \\
|
||||
w two three
|
||||
r > two three
|
||||
w echo end
|
||||
r > echo end
|
||||
w \)
|
||||
r > \)
|
||||
r one two three end
|
||||
!
|
||||
|
||||
# ======
|
||||
exit $((Errors<125?Errors:125))
|
||||
|
|
Loading…
Reference in a new issue