GNU bug report logs - #71929
30.0.60; crash in mark_image_cache

Previous Next

Package: emacs;

Reported by: Sean Whitton <spwhitton <at> spwhitton.name>

Date: Thu, 4 Jul 2024 02:34:02 UTC

Severity: normal

Found in version 30.0.60

Done: Po Lu <luangruo <at> yahoo.com>

Bug is archived. No further changes may be made.

Full log


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

From: Po Lu <luangruo <at> yahoo.com>
To: Sean Whitton <spwhitton <at> spwhitton.name>
Cc: 71929 <at> debbugs.gnu.org, Eli Zaretskii <eliz <at> gnu.org>
Subject: Re: bug#71929: 30.0.60; crash in mark_image_cache
Date: Sun, 07 Jul 2024 21:47:28 +0800
Sean Whitton <spwhitton <at> spwhitton.name> writes:

> Hello,
>
> On Sun 07 Jul 2024 at 03:41pm +08, Po Lu wrote:
>
>> Eli Zaretskii <eliz <at> gnu.org> writes:
>>
>>> This is the initial frame of the daemon.  It is not a GUI frame, and
>>> so it should not have a valid image cache.  I guess some change is
>>> needed in verify_image_cache_refcount?
>>
>> Not quite: init_frame_faces is apparently called before the frame is
>> entered into Vframe_list, so, likewise, the face cache's reference count
>> should be verified before it is incremented.
>>
>> Sean, please retry with this patch substituted for the previous:
>
> This time it doesn't crash until I open and close a frame, as can be
> seen in the backtrace:

I must ask you to bear with me again, as another detail was not
correctly accounted for in the last patch.  Please retry with this:

diff --git a/src/frame.c b/src/frame.c
index 7f4bf274ad9..9793b9f5cbe 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -4831,14 +4831,20 @@ gui_set_font (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
 	  /* Clean F's image cache of images whose values are derived
 	     from the font width.  */
 	  clear_image_cache (f, Qauto);
+	  verify_image_cache_refcount (FRAME_IMAGE_CACHE (f));
 	}
       else
 	{
+	  struct image_cache *old_cache = FRAME_IMAGE_CACHE (f);
+
 	  /* Release the current image cache, and reuse or allocate a
 	     new image cache with IWIDTH.  */
 	  FRAME_IMAGE_CACHE (f)->refcount--;
+	  FRAME_IMAGE_CACHE (f) = NULL;
+	  verify_image_cache_refcount (old_cache);
 	  FRAME_IMAGE_CACHE (f) = share_image_cache (f);
 	  FRAME_IMAGE_CACHE (f)->refcount++;
+	  verify_image_cache_refcount (FRAME_IMAGE_CACHE (f));
 	}
     }
 
diff --git a/src/frame.h b/src/frame.h
index 1d920d1a6bc..8a636c56643 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -1682,6 +1682,31 @@ IMAGE_OPT_FROM_ID (struct frame *f, int id)
   eassume (0 <= used);
   return 0 <= id && id < used ? FRAME_IMAGE_CACHE (f)->images[id] : NULL;
 }
+
+/* Abort if C is non-NULL and C's `refcount' field disagrees with the
+   number of frames holding references to the same.  */
+
+INLINE void
+verify_image_cache_refcount (struct image_cache *c)
+{
+  int expected;
+  Lisp_Object tail, frame;
+
+  if (c)
+    {
+      expected = 0;
+
+      FOR_EACH_FRAME (tail, frame)
+	{
+	  if (FRAME_IMAGE_CACHE (XFRAME (frame)) == c)
+	    expected++;
+	}
+
+      if (expected != c->refcount)
+	emacs_abort ();
+    }
+}
+
 #endif
 
 /***********************************************************************
diff --git a/src/image.c b/src/image.c
index 2945447b962..9387c78408b 100644
--- a/src/image.c
+++ b/src/image.c
@@ -3625,6 +3625,7 @@ cache_image (struct frame *f, struct image *img)
     {
       c = FRAME_IMAGE_CACHE (f) = share_image_cache (f);
       c->refcount++;
+      verify_image_cache_refcount (c);
     }
 
   /* Find a free slot in c->images.  */
diff --git a/src/xfaces.c b/src/xfaces.c
index 188dd4778bc..372c36634d1 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -678,7 +678,10 @@ init_frame_faces (struct frame *f)
   /* Make or share an image cache.  */
   if (FRAME_WINDOW_P (f))
     {
-      FRAME_IMAGE_CACHE (f) = share_image_cache (f);
+      struct image_cache *c = share_image_cache (f);
+
+      verify_image_cache_refcount (c);
+      FRAME_IMAGE_CACHE (f) = c;
       ++FRAME_IMAGE_CACHE (f)->refcount;
     }
 #endif /* HAVE_WINDOW_SYSTEM */
@@ -710,6 +713,7 @@ free_frame_faces (struct frame *f)
       if (image_cache)
 	{
 	  --image_cache->refcount;
+	  verify_image_cache_refcount (image_cache);
 	  if (image_cache->refcount == 0)
 	    free_image_cache (f);
 	}




This bug report was last modified 301 days ago.

Previous Next


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