Download raw body.
vi crash whilst global search running (and nvi too?)
On 2026-01-28 00:52:06 +0000, Jeremy Mates wrote:
> $ printf 'foo\nfoo\nfoo\n' > foo
> $ /usr/bin/ex foo
> foo: unmodified: line 3
> :g/foo/vi
So a problem is that ex_cmd() has been entered into due to the "global
/^/ visual" command (for each matching line, enter visual mode), and
there is some notice in the code, probably not very important,
/*
* We always start running the command on the top of the stack.
* This means that *everything* must be resolved when we leave
* this function for any reason.
*/
and then in visual mode if you type in ":quit" or any other ex command
ex_cmd is entered for a second time (uh oh?), whereupon it sees "vi" on
the top of the gp->ecq command stack, and the "quit" or whatever ex
command you typed is ignored. Usually the "Global/v command running when
the file/screen changed" message appears as the global started in ex
mode is noticed.
A subsequent ":quit" actually works and will probably cause vi to exit,
sometimes with a crash, probably on account of ex_cmd having been
entered more than once and the cleanup code maybe trying to do things
more than once.
As a horrible kluge one can use a patch such as the following, which
appears to at least let you enter ":quit" the first time and have vi
exit, probably with some error messages and maybe crashes from the
cleanup code. A less bad patch would need to figure out how to make
ex_cmd reentrant, or to ensure that the cleanup code does not close
ep->db twice or free already freed memory, and to confirm that making
ex_cmd reentrant does not cause problems anywhere else, which the robust
test suite for vi will doubtless help with.
--- usr.bin/vi/ex/ex.c
+++ usr.bin/vi/ex/ex.c
@@ -206,6 +206,7 @@ ex_cmd(SCR *sp)
int ch, cnt, delim, isaddr, namelen;
int newscreen, notempty, tmp, vi_address;
char *arg1, *p, *s, *t;
+ static int level = 0;
gp = sp->gp;
exp = EXP(sp);
@@ -214,8 +215,14 @@ ex_cmd(SCR *sp)
* We always start running the command on the top of the stack.
* This means that *everything* must be resolved when we leave
* this function for any reason.
+ *
+ * !!! Not everything is resolved if from ex mode "g/^/vi" is
+ * run, and then an ex command is entered in visual mode.
*/
+ ++level;
loop: ecp = LIST_FIRST(&gp->ecq);
+ if (level > 1)
+ ecp = LIST_NEXT(ecp, q);
/* If we're reading a command from a file, set up error information. */
if (ecp->if_name != NULL) {
@@ -1603,6 +1610,8 @@ rsuccess: tmp = 0;
/* Turn off the global bit. */
F_CLR(sp, SC_EX_GLOBAL);
+ --level;
+
return (tmp);
}
vi crash whilst global search running (and nvi too?)