"re-replace-region: Match data clobbered by buffer modification hooks"

1.2k views Asked by At

After upgrading to Aquamacs Version 3.3 (emacs 25.1.1), I'm getting the error mentioned in the title when running re-replace-region (as defined below), trying to change a string of 9s in a region (e.g. "99" or "999") to 0s. I've never had this problem with prior versions of Aquamacs (or emacs generally), and there is nothing I can think of, either in the emacs environment or the machine environment generally (Mac OS 10.9.5), that might be associated with the problem.

In fact, I have an emacs executable (version 22.1.1) on the same machine, and after invoking it in the same environment (e.g., same ~/.emacs etc), re-replace-region works as it should.

The only other clue I can offer is that when running re-replace-region on a region with say three 9s (999) in it, trying to change 9 to 0, the first 9 is altered before the error condition is raised.

Here is the defun:

;;; RE-REPLACE-REGION replaces OLD (a regular expression) with NEW
;;; throughout the region indicated by BEGIN and END.
;;; For example, to insert a prefix ">" at the beginning of each line
;;; in the region:
;;;   M-x re-replace-regionRET^RET>RET
;;; I don't know who wrote this function!
(defun re-replace-region (begin end old new)
"Replace occurrences of REGEXP with TO-STRING in region."
  (interactive "*r\nsReplace string: \nswith: ")
  (save-excursion
    (save-restriction
      (narrow-to-region begin end)
      (goto-char (point-min))
      (while (re-search-forward old (point-max) t)
        (replace-match new nil nil)))))
2

There are 2 answers

2
peak On BEST ANSWER

The problem seems to arise because the variable before-change-functions is (aquamacs-undo--rec-region-when-buffer-changes) in the affected buffers.

A simple workaround is to use replace-regexp instead of re-replace-region. Indeed, it's better than a mere workaround, because when used as intended (i.e., when used interactively), replace-regexp is called as follows:

 (replace-regexp REGEX TOSTRING nil
   (if (use-region-p) (region-beginning)) 
   (if (use-region-p) (region-end)) nil)

That is, if a region is defined, replace-regexp only affects the region -- which is of course the rationale for re-replace-region in the first place.

I'd still be interested to know more about (aquamacs-undo--rec-region-when-buffer-changes). Meanwhile, thanks especially to @phils.

2
phils On

I can tell you that this error message was introduced in July 2016, which explains why older versions of Emacs did not raise it:

commit 3a9d6296b35e5317c497674d5725eb52699bd3b8
Author: Eli Zaretskii
Date:   Mon Jul 4 18:34:40 2016 +0300

Avoid crashes when buffer modification hooks clobber match data

* src/search.c (Freplace_match): Error out if buffer modification
hooks triggered by buffer changes in replace_range, upcase-region,
and upcase-initials-region clobber the match data needed to be
adjusted for the replacement.  (Bug#23869)

So I would firstly assume that the information in the error is correct, and try to confirm it. Check your values for the before-change-functions and after-change-functions variables (in the buffer in question), and establish whether one of the functions listed is responsible.

Presumably one of them does indeed clobber the match data, and that should then be addressed as a bug for the function in question. If it's custom, you most likely just need to wrap a call to save-match-data around the relevant code.