Subject: bug#79200: 31.0.50; Duplicated elements for '#<marker at' in buffer-undo-list

From: Gerd Möllmann <[email-masked]>
Date: Tue, 12 Aug 2025 20:22:05 +0200

Gerd Möllmann <[email-masked]> writes:

Please find a port to feature/igc attached, for testing if you like.
I'll run with these changes in my Emacs and see what happens.

>From f769f8133efc75101589761bfe05db47e6beb987 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= <[email-masked]>
Date: Tue, 12 Aug 2025 15:58:54 +0200
Subject: [PATCH 1/4] Use adjust-marker entries in undo-lists

* src/alloc.c (next_marker_id): Return the next marker id to use.
(Fmake_marker, build_marker): Assign ids to markers.
* src/lisp.h (Lisp_Marker): Add id member.
* src/marker-vector.c (marker_vector_adjust_for_replace): New function.
* src/marker-vector.h: Declare it.
* src/marker.c (Fmarker_id): New DEFUN.
(Fmarker_with_id): New DEFUN.
(syms_of_marker): defsubr new DEFUNs
* src/pdumper.c (dump_marker): Dump marker id as negative number.
* src/undo.c (record_marker_adjustments): Produce adust-marker entries.
(syms_of_undo): New DEFSYM.
* lisp/simple.el (primitive-undo): Use adjust-marker entries.
---
 lisp/simple.el | 17 ++++++++++-------
 src/alloc.c    |  9 +++++++++
 src/lisp.h     |  2 ++
 src/marker.c   | 22 ++++++++++++++++++++++
 src/pdumper.c  |  2 ++
 src/undo.c     |  5 +++--
 6 files changed, 48 insertions(+), 9 deletions(-)

diff --git a/lisp/simple.el b/lisp/simple.el
index f7f059793ca..42541a952fe 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -3727,13 +3727,16 @@ primitive-undo
              ;; the markers haven't moved.  We check their validity
              ;; before reinserting the string so as we don't need to
              ;; mind marker insertion-type.
-             (while (and (markerp (car-safe (car list)))
-                         (integerp (cdr-safe (car list))))
-               (let* ((marker-adj (pop list))
-                      (m (car marker-adj)))
-                 (and (eq (marker-buffer m) (current-buffer))
-                      (= apos m)
-                      (push marker-adj valid-marker-adjustments))))
+             (while (eq 'adjust-marker (car-safe (car list)))
+               (let* ((entry (cdr-safe (car list)))
+                      (id (car entry))
+                      (offset (cdr entry))
+                      (marker (marker-with-id id)))
+                 (pop list)
+                 (when (and marker
+                            (eq (marker-buffer marker) (current-buffer))
+                            (= apos marker))
+                   (push (cons marker offset) valid-marker-adjustments))))
              ;; Insert string and adjust point
              (if (< pos 0)
                  (progn
diff --git a/src/alloc.c b/src/alloc.c
index ceda62f5ed6..c0793221acb 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -3953,12 +3953,20 @@ build_overlay (bool front_advance, bool rear_advance,
   return overlay;
 }
 
+static ptrdiff_t
+next_marker_id (void)
+{
+  static ptrdiff_t next = 0;
+  return next++;
+}
+
 DEFUN ("make-marker", Fmake_marker, Smake_marker, 0, 0, 0,
        doc: /* Return a newly allocated marker which does not point at any place.  */)
   (void)
 {
   struct Lisp_Marker *p = ALLOCATE_PLAIN_PSEUDOVECTOR (struct Lisp_Marker,
 						       PVEC_MARKER);
+  p->id = next_marker_id ();
   p->buffer = 0;
   p->bytepos = 0;
   p->charpos = 0;
@@ -3984,6 +3992,7 @@ build_marker (struct buffer *buf, ptrdiff_t charpos, ptrdiff_t bytepos)
 
   struct Lisp_Marker *m = ALLOCATE_PLAIN_PSEUDOVECTOR (struct Lisp_Marker,
 						       PVEC_MARKER);
+  m->id = next_marker_id ();
   m->buffer = buf;
   m->charpos = charpos;
   m->bytepos = bytepos;
diff --git a/src/lisp.h b/src/lisp.h
index 79ae7d4758a..5e528f2ecd9 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -3066,6 +3066,8 @@ knuth_hash (hash_hash_t hash, unsigned bits)
 {
   struct vectorlike_header header;
 
+  ptrdiff_t id;
+
   /* This is the buffer that the marker points into, or 0 if it points nowhere.
      Note: a chain of markers can contain markers pointing into different
      buffers (the chain is per buffer_text rather than per buffer, so it's
diff --git a/src/marker.c b/src/marker.c
index 12d53ad12b8..73e0eb1f492 100644
--- a/src/marker.c
+++ b/src/marker.c
@@ -440,6 +440,26 @@ buf_bytepos_to_charpos (struct buffer *b, ptrdiff_t bytepos)
 
 /* Operations on markers. */
 
+DEFUN ("marker-id", Fmarker_id, Smarker_id, 1, 1, 0,
+       doc: /* Return the id of MARKER.  */)
+  (Lisp_Object marker)
+{
+  CHECK_MARKER (marker);
+  return make_fixnum (XMARKER (marker)->id);
+}
+
+DEFUN ("marker-with-id", Fmarker_with_id, Smarker_with_id, 1, 1, 0,
+       doc: /* Return the marker in the current buffer with id ID.
+Value is nil if no such marker exists.  */)
+  (Lisp_Object id)
+{
+  CHECK_FIXNUM (id);
+  struct Lisp_Marker *m = marker_vector_marker_with_id (current_buffer, XFIXNUM (id));
+  if (m == NULL)
+    return Qnil;
+  return make_lisp_ptr (m, Lisp_Vectorlike);
+}
+
 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.  */)
@@ -859,6 +879,8 @@ syms_of_marker (void)
 {
   defsubr (&Smarker_position);
   defsubr (&Smarker_last_position);
+  defsubr (&Smarker_id);
+  defsubr (&Smarker_with_id);
   defsubr (&Smarker_buffer);
   defsubr (&Sset_marker);
   defsubr (&Scopy_marker);
diff --git a/src/pdumper.c b/src/pdumper.c
index 2b98d4600fb..bdadfedc4de 100644
--- a/src/pdumper.c
+++ b/src/pdumper.c
@@ -2229,6 +2229,8 @@ dump_marker (struct dump_context *ctx, const struct Lisp_Marker *marker)
   dump_pseudovector_lisp_fields (ctx, &out->header, &marker->header);
   DUMP_FIELD_COPY (out, marker, need_adjustment);
   DUMP_FIELD_COPY (out, marker, insertion_type);
+  DUMP_FIELD_COPY (out, marker, id);
+  out->id *= -1;
   if (marker->buffer)
     {
       dump_field_lv_rawptr (ctx, out, marker, &marker->buffer,
diff --git a/src/undo.c b/src/undo.c
index 1a91aca01aa..a56834f8cfe 100644
--- a/src/undo.c
+++ b/src/undo.c
@@ -146,10 +146,10 @@ record_marker_adjustments (ptrdiff_t from, ptrdiff_t to)
 
           if (adjustment)
             {
-	      Lisp_Object marker = make_lisp_ptr (m, Lisp_Vectorlike);
+	      Lisp_Object id = make_fixnum (m->id);
               bset_undo_list
                 (current_buffer,
-                 Fcons (Fcons (marker, make_fixnum (adjustment)),
+                 Fcons (Fcons (Qadjust_marker, Fcons (id, make_fixnum (adjustment))),
                         BVAR (current_buffer, undo_list)));
             }
         }
@@ -433,6 +433,7 @@ syms_of_undo (void)
 
   /* Marker for function call undo list elements.  */
   DEFSYM (Qapply, "apply");
+  DEFSYM (Qadjust_marker, "adjust_marker");
 
   pending_boundary = Qnil;
   staticpro (&pending_boundary);
-- 
2.50.1

>From eeb806de8553c1fe17c25d59fb49c091b3c4e320 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= <[email-masked]>
Date: Tue, 12 Aug 2025 16:37:33 +0200
Subject: [PATCH 2/4] ; Fix DEFSYM

* src/undo.c (syms_of_undo): adjust_marker -> adjust-marker.
---
 src/undo.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/undo.c b/src/undo.c
index a56834f8cfe..95038b16b6c 100644
--- a/src/undo.c
+++ b/src/undo.c
@@ -433,7 +433,7 @@ syms_of_undo (void)
 
   /* Marker for function call undo list elements.  */
   DEFSYM (Qapply, "apply");
-  DEFSYM (Qadjust_marker, "adjust_marker");
+  DEFSYM (Qadjust_marker, "adjust-marker");
 
   pending_boundary = Qnil;
   staticpro (&pending_boundary);
-- 
2.50.1

>From 686bfcb46781d696884576bcd2c560507730b2a1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= <[email-masked]>
Date: Tue, 12 Aug 2025 17:45:11 +0200
Subject: [PATCH 3/4] Don't use negative marker ids

* src/alloc.c (syms_of_alloc): New DEFVAR_INT for next marker id.
(next_marker_id): Use it.
* src/pdumper.c (dump_marker): Store id as-is.
---
 src/alloc.c   | 9 +++++++--
 src/pdumper.c | 2 +-
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/src/alloc.c b/src/alloc.c
index c0793221acb..df47cd2fa9f 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -3956,8 +3956,9 @@ build_overlay (bool front_advance, bool rear_advance,
 static ptrdiff_t
 next_marker_id (void)
 {
-  static ptrdiff_t next = 0;
-  return next++;
+  if (next__marker_id == PTRDIFF_MAX)
+    next__marker_id = 0;
+  return next__marker_id++;
 }
 
 DEFUN ("make-marker", Fmake_marker, Smake_marker, 0, 0, 0,
@@ -7894,6 +7895,10 @@ syms_of_alloc (void)
 #endif
   DEFSYM (Qalloc, "alloc");
   DEFSYM (QCemergency, ":emergency");
+
+  DEFVAR_INT ("next--marker-id", next__marker_id,
+	      doc: /* Next marker id (internal use only..  */);
+  next__marker_id = 0;
 }
 
 #ifdef HAVE_MPS
diff --git a/src/pdumper.c b/src/pdumper.c
index bdadfedc4de..74cbe88bb94 100644
--- a/src/pdumper.c
+++ b/src/pdumper.c
@@ -2230,7 +2230,7 @@ dump_marker (struct dump_context *ctx, const struct Lisp_Marker *marker)
   DUMP_FIELD_COPY (out, marker, need_adjustment);
   DUMP_FIELD_COPY (out, marker, insertion_type);
   DUMP_FIELD_COPY (out, marker, id);
-  out->id *= -1;
+
   if (marker->buffer)
     {
       dump_field_lv_rawptr (ctx, out, marker, &marker->buffer,
-- 
2.50.1

>From 5014504eb21371852b18607346f7a958be983ca7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= <[email-masked]>
Date: Tue, 12 Aug 2025 20:16:33 +0200
Subject: [PATCH 4/4] Port marker-with-id

---
 src/marker.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/src/marker.c b/src/marker.c
index 73e0eb1f492..fd88743b0b3 100644
--- a/src/marker.c
+++ b/src/marker.c
@@ -454,10 +454,15 @@ DEFUN ("marker-with-id", Fmarker_with_id, Smarker_with_id, 1, 1, 0,
   (Lisp_Object id)
 {
   CHECK_FIXNUM (id);
-  struct Lisp_Marker *m = marker_vector_marker_with_id (current_buffer, XFIXNUM (id));
-  if (m == NULL)
-    return Qnil;
-  return make_lisp_ptr (m, Lisp_Vectorlike);
+
+  DO_MARKERS (current_buffer, m)
+    {
+      if (m->id == XFIXNUM (id))
+	return make_lisp_ptr (m, Lisp_Vectorlike);
+    }
+  END_DO_MARKERS;
+
+  return Qnil;
 }
 
 DEFUN ("marker-buffer", Fmarker_buffer, Smarker_buffer, 1, 1, 0,
-- 
2.50.1