GNU bug report logs - #79200
31.0.50; Duplicated elements for '#<marker at' in buffer-undo-list

Previous Next

Package: emacs;

Reported by: Óscar Fuentes <oscarfv <at> eclipso.eu>

Date: Fri, 8 Aug 2025 16:45:03 UTC

Severity: normal

Found in version 31.0.50

Full log


Message #179 received at 79200 <at> debbugs.gnu.org (full text, mbox):

From: Alan Mackenzie <acm <at> muc.de>
To: Gerd Möllmann <gerd.moellmann <at> gmail.com>
Cc: Óscar Fuentes <oscarfv <at> eclipso.eu>,
 Pip Cet <pipcet <at> protonmail.com>, acm <at> muc.de,
 Stefan Monnier <monnier <at> iro.umontreal.ca>, 79200 <at> debbugs.gnu.org
Subject: Re: bug#79200: 31.0.50; Duplicated elements for '#<marker at' in
 buffer-undo-list
Date: Sun, 10 Aug 2025 14:41:43 +0000
Hello, Gerd.

On Sun, Aug 10, 2025 at 15:11:24 +0200, Gerd Möllmann wrote:
> Alan Mackenzie <acm <at> muc.de> writes:

> >> > I think it may make more sense to find out who goes around creating
> >> > markers and not cleaning up after them. But I suspect many places cannot
> >> > easily be fixed because the markers might be exposed to Lisp.

> >> Probably. Good question is how to find these places, especially when
> >> they are created in Lisp :-/.

> > I've made a start on this (see patch below).  It's mainly in the C files,
> > where I grepped for Fpoint_marker and Fcopy_marker, and tidied up the
> > uses which didn't tidy up their uses of markers.  But also in some Lisp
> > files, which are directly part of the command loop (simple.el), or called
> > from it in hooks (jit.el, electric.el).

> Hi Alan,

> Thanks.

> > Unfortunately, this hasn't helped much.  When I type "asdfasdf" into
> > *scratch* on emacs -Q, then <BACKSPACE>, I still see five point markers
> > in buffer-undo-list.  If I <BACKSPACE> a second time, this adds on a
> > further ten point markers to b-u-list.

> > It's worth mentioning that these markers aren't eq to eachother.  At
> > least, not all of them.  I have a strong suspicion that there are
> > duplicates in the 15 markers in buffer-undo-list after my two
> > deletions.

> Hm, you mean eq markers inside the same undo group has duplicates? That
> I haven't seen yet. There is code in primitive-undo for that case,
> though, so it seems to be expected in some case. No idea.

Ah, OK.

> If the same marker appears twice in different undo groups, then that's
> normal. The entries for markers mean something like "add some delta to
> the marker's position when we undo this record".

Yes

> > It is unclear whether the <BACKSPACE> creates these markers, or just puts
> > existing markers into buffer-undo-list.  Maybe we could do with a
> > primitive in marker.c which would print out the current buffer's list of
> > markers.

Yes, I've called it buffer-marker-list, and it looks like this:



diff --git a/src/lisp.h b/src/lisp.h
index 64b5c227583..bc5a404c261 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -1400,6 +1400,9 @@ #define XSETTHREAD(a, b) XSETPSEUDOVECTOR (a, b, PVEC_THREAD)
 #define XSETMUTEX(a, b) XSETPSEUDOVECTOR (a, b, PVEC_MUTEX)
 #define XSETCONDVAR(a, b) XSETPSEUDOVECTOR (a, b, PVEC_CONDVAR)
 #define XSETNATIVE_COMP_UNIT(a, b) XSETPSEUDOVECTOR (a, b, PVEC_NATIVE_COMP_UNIT)
+/* EXPERIMENTAL STOUGH, 2025-08-10 */
+#define XSETMARKER(a, b) XSETPSEUDOVECTOR (a, b, PVEC_MARKER)
+/* END OF EXPERIMENTAL STOUGH */
 
 /* Efficiently convert a pointer to a Lisp object and back.  The
    pointer is represented as a fixnum, so the garbage collector
diff --git a/src/marker.c b/src/marker.c
index 4ab68ec7bbe..c5be58d1d7a 100644
--- a/src/marker.c
+++ b/src/marker.c
@@ -424,6 +424,24 @@ buf_bytepos_to_charpos (struct buffer *b, ptrdiff_t bytepos)
 
 /* Operations on markers. */
 
+/* EXPERIMENTAL STOUGH, 2025-08-10 */
+DEFUN ("buffer-marker-list", Fbuffer_marker_list, Sbuffer_marker_list, 0, 0, 0,
+       doc: /* Return (a copy of) the list of markers in the current buffer.  */)
+  (void)
+{
+  Lisp_Object markers = Qnil;
+  Lisp_Object mk;
+
+  for (struct Lisp_Marker *ma = BUF_MARKERS (current_buffer); ma; ma = ma->next)
+    {
+      XSETMARKER (mk, ma);
+      markers = (Fcons (mk, markers));
+    }
+  return Fnreverse (markers);
+}
+
+/* END OF EXPERIMENTAL STOUGH */
+
 DEFUN ("marker-buffer", Fmarker_buffer, Smarker_buffer, 1, 1, 0,
        doc: /* Return the buffer that MARKER points into, or nil if none.
 Returns nil if MARKER points into a dead buffer.  */)
@@ -833,6 +851,9 @@ verify_bytepos (ptrdiff_t charpos)
 void
 syms_of_marker (void)
 {
+  /* EXPERIMENTAL STOUGH, 2025-08-10 */
+  defsubr (&Sbuffer_marker_list);
+  /* END OF EXPERIMENTAL STOUGH */
   defsubr (&Smarker_position);
   defsubr (&Smarker_last_position);
   defsubr (&Smarker_buffer);


> I don't believe it creates the markers. But I'm pretty sure that
> record_change can put a lot of markers to a buffer's undo list. It just
> considers all markers in a buffer's markers list as relevant for undo.
> IOW, when we undo, all these markers need their positions changed. It
> has no way to recognize markers that are only used temporarily. 

In emacs -Q, C-x b foo <RET>.

Now do M-: (length (buffer-marker-list)).  It returns 9.  Repeat.  It
now returns 14.  Then, successively, 19, 26, 31, 36, ....  OK, between
the 19 and 26 I had finger trouble.

But it would appear that the command loop, or something close to it, is
adding five frivolous point markers at each iteration.  This is in my
"EXPERIMENTAL"ly patched master.  It may be even worse in a vanilla
master.

> ...

> > This might be a silly question, but why do we have to put markers into
> > buffer-undo-list at all?  Surely they should "fix themselves" as other
> > changes in the buffer get undone?

> Please see above. I hope that explains it. 

Thanks.  I'll study it more carefully when I'm in a less hacky mood.

-- 
Alan Mackenzie (Nuremberg, Germany).




This bug report was last modified today.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.