Index | Thread | Search

From:
Mark Willson <mark.willson@hydrus.org.uk>
Subject:
mg(1): regexp: infinite loop; over-eager anchor replacement [PATCH]
To:
<tech@openbsd.org>
Date:
Wed, 27 Aug 2025 16:30:16 +0100

Download raw body.

Thread
  • Mark Willson:

    mg(1): regexp: infinite loop; over-eager anchor replacement [PATCH]

Hi Folks,

The patch below fixes the following issues with the mg(1) editor:

1. An infinite loop with (replace-regexp "^" ""). replace-regexp does
   not advance to the next line. This also occurs when the search text
   is "^.*$".

2. replace-regexp replaces all occurances of ^pat on a line. For
   example, (replace-regexp "^#" "") will delete every occurance of
   "#" in the line "#############################". This is unexpected
   (at least to me) and is not the behaviour of emacs.

I'd be very grateful if someone could apply this patch (or a more
acceptable version) to the source tree.

Best Regards,
Mark

--- re_search.c.orig	Wed Aug 27 14:42:51 2025
+++ re_search.c	Wed Aug 27 14:42:49 2025
@@ -191,6 +191,12 @@
 			ewprintf("<SP> replace, [.] rep-end, <DEL> don't, [!] repl rest <ESC> quit");
 			goto retry;
 		}
+		/* Prevent:
+		 *  infinite loop when replacing ^ with ""
+		 *  multiple replacements of ^pat on same line
+		 */
+		if (re_pat[0] == '^' && news[0] == '\0')
+		    curwp->w_doto = curwp->w_dotp->l_used;
 	}
 
 stopsearch:
@@ -224,6 +230,12 @@
 		plen = regex_match[0].rm_eo - regex_match[0].rm_so;
 		if (re_doreplace((RSIZE)plen, news) == FALSE)
 			return (FALSE);
+		/* Prevent:
+		 *  infinite loop when replacing ^ with ""
+		 *  multiple replacements of ^pat on same line
+		 */
+		if (re_pat[0] == '^' && news[0] == '\0')
+		    curwp->w_doto = curwp->w_dotp->l_used;
 		rcnt++;
 	}
 
@@ -342,10 +354,9 @@
 	if (tbo == clp->l_used)
 		/*
 		 * Don't start matching past end of line -- must move to
-		 * beginning of next line, unless line is empty or at
-		 * end of file.
+		 * beginning of next line, unless at end of file.
 		 */
-		if (clp != curbp->b_headp && llength(clp) != 0) {
+		if (clp != curbp->b_headp) {
 			clp = lforw(clp);
 			tdotline++;
 			tbo = 0;

--
Mark Willson
mark.willson@hydrus.org.uk