Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
Re: 'while do done' hangs interactive zsh
- X-seq: zsh-workers 48840
- From: Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx>
- To: Arseny Maslennikov <ar@xxxxxxxxx>
- Cc: Zsh hackers list <zsh-workers@xxxxxxx>
- Subject: Re: 'while do done' hangs interactive zsh
- Date: Sun, 16 May 2021 08:46:00 -0700
- Archived-at: <https://zsh.org/workers/48840>
- In-reply-to: <CAH+w=7a-B+Zm4NWXS9bd1owjePHoS_O2dQT7dkEi3iU8DArPuQ@mail.gmail.com>
- List-id: <zsh-workers.zsh.org>
- References: <YKDi6GYtnBt1ZYTU@cello> <CAH+w=7a-B+Zm4NWXS9bd1owjePHoS_O2dQT7dkEi3iU8DArPuQ@mail.gmail.com>
On Sun, May 16, 2021 at 7:28 AM Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx> wrote:
>
> > Even more, if the user enters "while do; done" in an interactive zsh
> > instance, the busy loop is not interruptible by ^C, ^\ or ^Z; the shell
> > has to be killed via some external means.
>
> I can NOT reproduce this in the latest revision from git, but I can
> reproduce it in zsh-5.8.
Specifically, the shell is interruptible by ^C. I haven't attempted
to bisect where this was introduced; there are no obvious deltas to
signals.c, loop.c, or parse.c to explain it.
It is impossible to interrupt the parser with SIGINT. zhandler is
entered with signal queueing enabled; when signals are allowed again,
zhandler is called again and we pass through this code:
675 if (list_pipe || chline || simple_pline) {
676 breaks = loops;
677 errflag |= ERRFLAG_INT;
678 inerrflush();
679 check_cursh_sig(SIGINT);
680 }
681 lastval = 128 + SIGINT;
Because we're still in the parser, none of (list_pipe || chline ||
simple_pline) is true, so we never set breaks or errflag, only
lastval. I'm not immediately sure what to do about that; perhaps just
move the errflag setting outside that test?
The attached makes both "while do" and "do done" into parse errors; I
didn't want to try messing with the tokenizer, so better solutions are
welcome.
I mention tokenizing because in "for do" the string "do" is not a
token; "while do;" could conceivably mean to execute the command "do"
as the test condition.
diff --git a/Src/parse.c b/Src/parse.c
index b09c7989a..153633bb1 100644
--- a/Src/parse.c
+++ b/Src/parse.c
@@ -1525,10 +1525,16 @@ par_while(int *cmplx)
incmdpos = 1;
while (tok == SEPER)
zshlex();
- if (tok == DOLOOP) {
+ /*
+ * If the very first thing after "while" is "do",
+ * ecused has advanced only two positions. This
+ * is not a valid while-do construction.
+ */
+ if (tok == DOLOOP && (ecused - oecused) > 2) {
zshlex();
par_save_list(cmplx);
- if (tok != DONE)
+ /* As above but "do done" is not valid */
+ if (tok != DONE || (ecused - oecused) < 8)
YYERRORV(oecused);
incmdpos = 0;
zshlex();
Messages sorted by:
Reverse Date,
Date,
Thread,
Author