mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
Fix two more PS2/SIGINT crashing bugs (re: 3023d53b)
*** Crash 1: *** ksh crashed if the PS1 prompt contains one or more command substitutions and you enter a multi-line command substitution on the command line, then interrupt while on the PS2 prompt. $ ENV=/./dev/null /usr/local/bin/ksh -o emacs $ PS1='$(echo foo) $(echo bar) $(echo baz) ! % ' foo bar baz 16999 % echo $( > true <-- here, press Ctrl+C instead of Return Memory fault The crash occurred due to a corrupted lexer state while trying to display the PS1 prompt. Analysis: My fix for the crashing bug with Ctrl+C in commit 3023d53b is incorrect and only worked accidentally. sh_fault() is not the right place to reset the lexer state because, when we press Ctrl+C on a PS2 prompt, ksh had been waiting for input to finish lexing a multi-line command, so sh_lex() and other lexer functions are on the function call stack and will be returned to. src/cmd/ksh93/sh/fault.c: sh_fault(): - Remove incorrect SIGINT fix. src/cmd/ksh93/sh/io.c: io_prompt(): - Reset the lexer state immediately before printing every PS1 prompt. Even in situations where this is redundant it should be perfectly safe, the overhead is negligible, and it resolves this crash. It may pre-empt other problems as well. *** Crash 2: *** If an INT trap is set, and you start entering a multi-line command substitution, then press Ctrl+C on the PS2 prompt to trigger the crash, the lexer state is corrupted because the lexer is invoked to eval the trap action. A crash then occurs on entering the final ')' of the command substitution. $ trap 'echo TRAPPED' INT $ echo $( > trueTRAPPED <-- press Ctrl+C to output "TRAPPED" > ) Memory fault Technically, as SIGINT is trapped, it should not interrupt, so ksh should execute the trap, then continue with the PS2 prompt to let the user finish inputting the command. But I have been unsuccessful in many different attempts to make this work properly. I managed to get multi-line command substitutions to lex correctly by saving and restoring the lexer state, but command substitutions were still corrupted at the parser and/or execution level and I have not managed to trace the cause of that. My testing showed that all other shells interrupt the PS2 prompt and return to PS1 when the user presses Ctrl+C, even if SIGINT is trapped. I think that is a reasonable alternative, and it is something I managed to make work. src/cmd/ksh93/sh/fault.c: sh_chktrap(): - Immediately after invoking sh_trap() to run a trap action, check if we're in a PS2 prompt (sh.nextprompt == 2). If so, assume the lexer state is now overwritten. Closing the fcin stream with fcclose() seems to reliably force the lexer to stop doing anything else. Then we can just reset the prompt to PS1 and invoke sh_exit() to start new command line, which will now reset the lexer state as per above.
This commit is contained in:
parent
0180a65bbf
commit
65feb9641a
5 changed files with 19 additions and 4 deletions
|
@ -68,9 +68,6 @@ void sh_fault(register int sig)
|
|||
register char *trap;
|
||||
register struct checkpt *pp = (struct checkpt*)shp->jmplist;
|
||||
int action=0;
|
||||
/* reset lexer state on Ctrl+C */
|
||||
if(sh_isstate(SH_INTERACTIVE) && sig==SIGINT)
|
||||
sh_lexopen(sh.lex_context, &sh, 0);
|
||||
/* reset handler */
|
||||
if(!(sig&SH_TRAP))
|
||||
signal(sig, sh_fault);
|
||||
|
@ -437,6 +434,15 @@ void sh_chktrap(Shell_t* shp)
|
|||
cursig = sig;
|
||||
sh_trap(trap,0);
|
||||
cursig = -1;
|
||||
/* If we're in a PS2 prompt, then we just parsed and executed a trap in the middle of parsing
|
||||
* another command, so the lexer state is overwritten. Escape to avoid crashing the lexer. */
|
||||
if(sh.nextprompt == 2)
|
||||
{
|
||||
fcclose(); /* force lexer to abort partial command */
|
||||
sh.nextprompt = 1; /* next display prompt is PS1 */
|
||||
sh.lastsig = sig; /* make sh_exit() set $? to signal exit status */
|
||||
sh_exit(SH_EXITSIG); /* start a new command line */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue