> Hmm. I get neither a seg fault nor a loop on my amd64 Lenove E595. The > cursor moves to different spots in X/i3 xterm vs console and in either > case doesn't do any replacement.
I can reproduce both behaviors reliably as follows both on console and in xterm. $ echo 'a\n\n\nb' > /tmp/test $ mg /tmp/test Don't move the cursor, just do the following (what is between quotation marks is what you are supposed to type, the other bits are prompts): "M-x query-replace-regexp<enter>" RE Query replace: "^<enter>" Query replace ^ with: "a<enter>" Query replacing ^ with a: "<enter>" <SP> replace, [.] rep-end, <DEL> don't, [!] repl rest <ESC> quit "!" After hitting "!" here, it will enter a loop and eventually print panic: Out of memory in undo code (record) and exit. If I do the exact same dance after moving the cursor to the second (empty) line, it will segfault. With the diff below (which is what I understood to be Hiltjo's suggestion), I get more or less what I would expect. I think it should not replace the empty line after the last newline... So I think both diffs are not quite right :) Index: line.c =================================================================== RCS file: /var/cvs/src/usr.bin/mg/line.c,v retrieving revision 1.61 diff -u -p -r1.61 line.c --- line.c 29 Aug 2018 07:50:16 -0000 1.61 +++ line.c 21 Jul 2020 14:58:49 -0000 @@ -556,6 +556,8 @@ lreplace(RSIZE plen, char *st) goto done; lp = curwp->w_dotp; + if (ltext(lp) == NULL) + goto done; doto = curwp->w_doto; n = plen; Index: re_search.c =================================================================== RCS file: /var/cvs/src/usr.bin/mg/re_search.c,v retrieving revision 1.34 diff -u -p -r1.34 re_search.c --- re_search.c 9 Jul 2020 10:42:24 -0000 1.34 +++ re_search.c 21 Jul 2020 15:00:08 -0000 @@ -308,7 +308,7 @@ re_doreplace(RSIZE plen, char *st) static int re_forwsrch(void) { - int tbo, tdotline, error; + int re_flags, tbo, tdotline, error; struct line *clp; clp = curwp->w_dotp; @@ -330,10 +330,13 @@ re_forwsrch(void) * always makes the last line empty so this is good. */ while (clp != (curbp->b_headp)) { + re_flags = REG_STARTEND; + if (tbo != 0) + re_flags |= REG_NOTBOL; regex_match[0].rm_so = tbo; regex_match[0].rm_eo = llength(clp); error = regexec(®ex_buff, ltext(clp) ? ltext(clp) : "", - RE_NMATCH, regex_match, REG_STARTEND); + RE_NMATCH, regex_match, re_flags); if (error != 0) { clp = lforw(clp); tdotline++;