diff --git a/NEWS b/NEWS index 9f00893ae..91083160c 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,9 @@ Any uppercase BUG_* names are modernish shell bug IDs. - A bug that caused the time keyword to override the errexit shell option has been fixed. +- Fixed a crash that could occur when a KEYBD trap was set and a multi-line + command substitution was input in an interactive shell. + 2021-11-24: - The --posix mode was amended to stop the '.' command (but not 'source') from diff --git a/src/cmd/ksh93/edit/edit.c b/src/cmd/ksh93/edit/edit.c index d09aa32f4..7cea1e3bb 100644 --- a/src/cmd/ksh93/edit/edit.c +++ b/src/cmd/ksh93/edit/edit.c @@ -52,10 +52,11 @@ #include "terminal.h" #include "history.h" #include "edit.h" +#include "shlex.h" static char CURSOR_UP[20] = { ESC, '[', 'A', 0 }; static char KILL_LINE[20] = { ESC, '[', 'J', 0 }; - +static Lex_t *savelex; #if SHOPT_MULTIBYTE @@ -230,6 +231,8 @@ int tty_set(int fd, int action, struct termios *tty) void tty_cooked(register int fd) { register Edit_t *ep = (Edit_t*)(shgd->ed_context); + if(ep->sh->st.trap[SH_KEYTRAP] && savelex) + memcpy(ep->sh->lex_context,savelex,sizeof(Lex_t)); ep->e_keytrap = 0; if(ep->e_raw==0) return; @@ -845,6 +848,12 @@ void ed_setup(register Edit_t *ep, int fd, int reedit) ep->e_lbuf[n] = *pp++; ep->e_default = 0; } + if(ep->sh->st.trap[SH_KEYTRAP]) + { + if(!savelex) + savelex = (Lex_t*)sh_malloc(sizeof(Lex_t)); + memcpy(savelex, ep->sh->lex_context, sizeof(Lex_t)); + } } #endif /* SHOPT_ESH || SHOPT_VSH */ diff --git a/src/cmd/ksh93/include/shlex.h b/src/cmd/ksh93/include/shlex.h index 9b59c7c13..28d1304e9 100644 --- a/src/cmd/ksh93/include/shlex.h +++ b/src/cmd/ksh93/include/shlex.h @@ -32,7 +32,48 @@ #include "shtable.h" #include "lexstates.h" +/* + * This structure allows for arbitrary depth nesting of (...), {...}, [...] + */ +struct _shlex_pvt_lexstate_ +{ + char incase; /* 1 for case pattern, 2 after case */ + char intest; /* 1 inside [[ ... ]] */ + char testop1; /* 1 when unary test op legal */ + char testop2; /* 1 when binary test op legal */ + char reservok; /* >0 for reserved word legal */ + char skipword; /* next word can't be reserved */ + char last_quote; /* last multi-line quote character */ + char nestedbrace; /* ${var op {...}} */ +}; +struct _shlex_pvt_lexdata_ +{ + char nocopy; + char paren; + char dolparen; + char nest; + char docword; + char nested_tilde; + char *docend; + char noarg; + char warn; + char message; + char arith; + char *first; + int level; + int lastc; + int lex_max; + int *lex_match; + int lex_state; + int docextra; +#if SHOPT_KIA + off_t kiaoff; +#endif +}; +/* + * Main lexer struct. + */ typedef struct _shlex_ { Shell_t *sh; /* pointer to the interpreter */ @@ -62,9 +103,9 @@ typedef struct _shlex_ char *scriptname; /* name of script file */ Dt_t *entity_tree; /* for entity ids */ #endif /* SHOPT_KIA */ -#ifdef _SHLEX_PRIVATE - _SHLEX_PRIVATE -#endif + /* The following two struct members are considered private to lex.c */ + struct _shlex_pvt_lexdata_ lexd; \ + struct _shlex_pvt_lexstate_ lex; } Lex_t; /* symbols for parsing */ diff --git a/src/cmd/ksh93/sh/lex.c b/src/cmd/ksh93/sh/lex.c index c30c2d849..073162bc2 100644 --- a/src/cmd/ksh93/sh/lex.c +++ b/src/cmd/ksh93/sh/lex.c @@ -45,6 +45,7 @@ #include "test.h" #include "lexstates.h" #include "io.h" +#include "shlex.h" #define TEST_RE 3 #define SYNBAD 3 /* exit value for syntax errors */ @@ -68,53 +69,6 @@ local_iswblank(wchar_t wc) #endif -/* - * This structure allows for arbitrary depth nesting of (...), {...}, [...] - */ -struct lexstate -{ - char incase; /* 1 for case pattern, 2 after case */ - char intest; /* 1 inside [[ ... ]] */ - char testop1; /* 1 when unary test op legal */ - char testop2; /* 1 when binary test op legal */ - char reservok; /* >0 for reserved word legal */ - char skipword; /* next word can't be reserved */ - char last_quote; /* last multi-line quote character */ - char nestedbrace; /* ${var op {...}} */ -}; - -struct lexdata -{ - char nocopy; - char paren; - char dolparen; - char nest; - char docword; - char nested_tilde; - char *docend; - char noarg; - char warn; - char message; - char arith; - char *first; - int level; - int lastc; - int lex_max; - int *lex_match; - int lex_state; - int docextra; -#if SHOPT_KIA - off_t kiaoff; -#endif -}; - -#define _SHLEX_PRIVATE \ - struct lexdata lexd; \ - struct lexstate lex; - -#include "shlex.h" - - #define pushlevel(lp,c,s) ((lp->lexd.level>=lp->lexd.lex_max?stack_grow(lp):1) &&\ ((lp->lexd.lex_match[lp->lexd.level++]=lp->lexd.lastc),\ lp->lexd.lastc=(((s)<heredoc; char *first,*cp=fcseek(0),word[5]; int off, messages=0, assignok=lp->assignok, csub; - struct lexstate save; + struct _shlex_pvt_lexstate_ save; save = lp->lex; csub = lp->comsub; sh_lexopen(lp,lp->sh,1); diff --git a/src/cmd/ksh93/tests/pty.sh b/src/cmd/ksh93/tests/pty.sh index 7180ea181..00fbaf7b8 100755 --- a/src/cmd/ksh93/tests/pty.sh +++ b/src/cmd/ksh93/tests/pty.sh @@ -878,5 +878,16 @@ w : test_string\1\E6\E[C\4 r ^:test-4: : teststring\r\n$ ! +# err_exit # +tst $LINENO <<"!" +L crash with KEYBD trap after entering multi-line command substitution +# https://www.mail-archive.com/ast-users@lists.research.att.com/msg00313.html + +w trap : KEYBD +w : $( +w true); echo "Exit status is $?" +u Exit status is 0 +! + # ====== exit $((Errors<125?Errors:125))