]> git.eshelyaron.com Git - emacs.git/commitdiff
Revert "mark_overlays: Use the normal ITREE_FOREACH"
authorMatt Armstrong <matt@rfc20.org>
Wed, 19 Oct 2022 20:42:35 +0000 (13:42 -0700)
committerStefan Monnier <monnier@iro.umontreal.ca>
Thu, 20 Oct 2022 01:35:09 +0000 (21:35 -0400)
This reverts commit b8fbd42f0a7caa4cd9e2d50dd4e4b2101ac78acd,
with edits.

* src/alloc.c (mark_overlays): restore function.
(mark_buffer): Call it, not ITREE_FOREACH.
(garbage_collect): eassert (!itree_busy_p ()).
* src/itree.h: Comment tweak: explain why GC is considered risky.  It
isn't that GC itself is risky, it is that GC can call ELisp by way of
a hook, and running ELisp during iteration is risks nested iteration.

src/alloc.c
src/itree.h

index 00f2991f2502df67cdf58ac39df25419d7e878af..d7e0a99ffe7e1c981fdd240148b8829a4e6a4844 100644 (file)
@@ -6279,6 +6279,11 @@ garbage_collect (void)
   image_prune_animation_caches (false);
 #endif
 
+  /* ELisp code run by `gc-post-hook' could result in itree iteration,
+     which must not happen while the itree is already busy.  See
+     bug#58639.  */
+  eassert (!itree_iterator_busy_p ());
+
   if (!NILP (Vpost_gc_hook))
     {
       specpdl_ref gc_count = inhibit_garbage_collection ();
@@ -6510,6 +6515,18 @@ mark_overlay (struct Lisp_Overlay *ov)
   mark_object (ov->plist);
 }
 
+/* Mark the overlay subtree rooted at NODE.  */
+
+static void
+mark_overlays (struct interval_node *node)
+{
+  if (node == NULL)
+    return;
+  mark_object (node->data);
+  mark_overlays (node->left);
+  mark_overlays (node->right);
+}
+
 /* Mark Lisp_Objects and special pointers in BUFFER.  */
 
 static void
@@ -6531,9 +6548,8 @@ mark_buffer (struct buffer *buffer)
   if (!BUFFER_LIVE_P (buffer))
       mark_object (BVAR (buffer, undo_list));
 
-  struct interval_node *node;
-  ITREE_FOREACH (node, buffer->overlays, PTRDIFF_MIN, PTRDIFF_MAX, ASCENDING)
-    mark_object (node->data);
+  if (buffer->overlays)
+    mark_overlays (buffer->overlays->root);
 
   /* If this is an indirect buffer, mark its base buffer.  */
   if (buffer->base_buffer &&
index 8d33ef223b5d18c70b54b9eefec62245c716b92e..b0f7a1d193bc1dcd204532b997977664401c9d87 100644 (file)
@@ -149,7 +149,8 @@ struct interval_node *itree_iterator_next (struct itree_iterator *);
      it is cheap a pure.
    - Only a single iteration can happen at a time, so make sure none of the
      code within the loop can start another tree iteration, i.e. it shouldn't
-     be able to run ELisp code (or GC for that matter).
+     be able to run ELisp code, nor GC since GC can run ELisp by way
+     of `post-gc-hook`.
    - If you need to exit the loop early, you *have* to call `ITREE_ABORT`
      just before exiting (e.g. with `break` or `return`).
    - Non-local exits are not supported within the body of the loop.