mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-02-15 04:32:24 +00:00
Fix KEYBD
trap crash when inputting a command substitution (#355)
This change fixes a crash that can occur after setting a KEYBD trap then inputting a multi-line command substitution. The crash is similar to issue #347, but it's easier to reproduce since it doesn't require you to setup a kshrc file. Reproducer for the crash: $ ENV=/./dev/null ksh $ trap : KEYBD $ : $( > true) Memory fault(coredump) The bugfix was backported (with considerable changes) from ksh93v- 2013-10-08. The crash was first reported on the old mailing list: https://www.mail-archive.com/ast-users@lists.research.att.com/msg00313.html src/cmd/ksh93/{include/shlex.h,sh/lex.c}: - To fix this properly, we need sizeof(Lex_t) to work as expected in edit.c, but that is thwarted by the _SHLEX_PRIVATE macro in lex.c which shlex.h uses to add private structs to the Lex_t type in lex.c only. So get rid of that _SHLEX_PRIVATE macro and make those members part of the centrally defined struct, renaming them to make it clear they're considered private to lex.c. src/cmd/ksh93/edit/edit.c: - Now that we can get its size, save and restore the shell lexing context when a KEYBD trap is present. src/cmd/ksh93/tests/pty.sh: - Add a regression test for the KEYBD trap crash. Co-authored-by: Martijn Dekker <martijn@inlv.org>
This commit is contained in:
parent
bfad44e56d
commit
370440473e
5 changed files with 70 additions and 52 deletions
3
NEWS
3
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
|
- A bug that caused the time keyword to override the errexit shell option has
|
||||||
been fixed.
|
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:
|
2021-11-24:
|
||||||
|
|
||||||
- The --posix mode was amended to stop the '.' command (but not 'source') from
|
- The --posix mode was amended to stop the '.' command (but not 'source') from
|
||||||
|
|
|
@ -52,10 +52,11 @@
|
||||||
#include "terminal.h"
|
#include "terminal.h"
|
||||||
#include "history.h"
|
#include "history.h"
|
||||||
#include "edit.h"
|
#include "edit.h"
|
||||||
|
#include "shlex.h"
|
||||||
|
|
||||||
static char CURSOR_UP[20] = { ESC, '[', 'A', 0 };
|
static char CURSOR_UP[20] = { ESC, '[', 'A', 0 };
|
||||||
static char KILL_LINE[20] = { ESC, '[', 'J', 0 };
|
static char KILL_LINE[20] = { ESC, '[', 'J', 0 };
|
||||||
|
static Lex_t *savelex;
|
||||||
|
|
||||||
|
|
||||||
#if SHOPT_MULTIBYTE
|
#if SHOPT_MULTIBYTE
|
||||||
|
@ -230,6 +231,8 @@ int tty_set(int fd, int action, struct termios *tty)
|
||||||
void tty_cooked(register int fd)
|
void tty_cooked(register int fd)
|
||||||
{
|
{
|
||||||
register Edit_t *ep = (Edit_t*)(shgd->ed_context);
|
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;
|
ep->e_keytrap = 0;
|
||||||
if(ep->e_raw==0)
|
if(ep->e_raw==0)
|
||||||
return;
|
return;
|
||||||
|
@ -845,6 +848,12 @@ void ed_setup(register Edit_t *ep, int fd, int reedit)
|
||||||
ep->e_lbuf[n] = *pp++;
|
ep->e_lbuf[n] = *pp++;
|
||||||
ep->e_default = 0;
|
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 */
|
#endif /* SHOPT_ESH || SHOPT_VSH */
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,48 @@
|
||||||
#include "shtable.h"
|
#include "shtable.h"
|
||||||
#include "lexstates.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_
|
typedef struct _shlex_
|
||||||
{
|
{
|
||||||
Shell_t *sh; /* pointer to the interpreter */
|
Shell_t *sh; /* pointer to the interpreter */
|
||||||
|
@ -62,9 +103,9 @@ typedef struct _shlex_
|
||||||
char *scriptname; /* name of script file */
|
char *scriptname; /* name of script file */
|
||||||
Dt_t *entity_tree; /* for entity ids */
|
Dt_t *entity_tree; /* for entity ids */
|
||||||
#endif /* SHOPT_KIA */
|
#endif /* SHOPT_KIA */
|
||||||
#ifdef _SHLEX_PRIVATE
|
/* The following two struct members are considered private to lex.c */
|
||||||
_SHLEX_PRIVATE
|
struct _shlex_pvt_lexdata_ lexd; \
|
||||||
#endif
|
struct _shlex_pvt_lexstate_ lex;
|
||||||
} Lex_t;
|
} Lex_t;
|
||||||
|
|
||||||
/* symbols for parsing */
|
/* symbols for parsing */
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
#include "test.h"
|
#include "test.h"
|
||||||
#include "lexstates.h"
|
#include "lexstates.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
#include "shlex.h"
|
||||||
|
|
||||||
#define TEST_RE 3
|
#define TEST_RE 3
|
||||||
#define SYNBAD 3 /* exit value for syntax errors */
|
#define SYNBAD 3 /* exit value for syntax errors */
|
||||||
|
@ -68,53 +69,6 @@ local_iswblank(wchar_t wc)
|
||||||
|
|
||||||
#endif
|
#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) &&\
|
#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.lex_match[lp->lexd.level++]=lp->lexd.lastc),\
|
||||||
lp->lexd.lastc=(((s)<<CHAR_BIT)|(c))))
|
lp->lexd.lastc=(((s)<<CHAR_BIT)|(c))))
|
||||||
|
@ -1542,7 +1496,7 @@ static int comsub(register Lex_t *lp, int endtok)
|
||||||
struct ionod *inheredoc = lp->heredoc;
|
struct ionod *inheredoc = lp->heredoc;
|
||||||
char *first,*cp=fcseek(0),word[5];
|
char *first,*cp=fcseek(0),word[5];
|
||||||
int off, messages=0, assignok=lp->assignok, csub;
|
int off, messages=0, assignok=lp->assignok, csub;
|
||||||
struct lexstate save;
|
struct _shlex_pvt_lexstate_ save;
|
||||||
save = lp->lex;
|
save = lp->lex;
|
||||||
csub = lp->comsub;
|
csub = lp->comsub;
|
||||||
sh_lexopen(lp,lp->sh,1);
|
sh_lexopen(lp,lp->sh,1);
|
||||||
|
|
|
@ -878,5 +878,16 @@ w : test_string\1\E6\E[C\4
|
||||||
r ^:test-4: : teststring\r\n$
|
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))
|
exit $((Errors<125?Errors:125))
|
||||||
|
|
Loading…
Reference in a new issue