Subject: bug#75477: 31.0.50; scratch/igc: crash on the latest commit

From: Pip Cet <[email-masked]>
Date: Fri, 10 Jan 2025 17:11:22 +0000

Pip Cet <[email-masked]> writes:

> Pip Cet <[email-masked]> writes:
>
>> "Ihor Radchenko" <[email-masked]> writes:
>>
>>> Gerd Möllmann <[email-masked]> writes:
>>>
>>>> Don't know if that helps, but M-x igc-root-stats can be used to display
>>>> information about known roots. Maybe one can see there if the number of
>>>> roots increases over time, which would indicate if there is something
>>>> like a "root leak", for example by using xfree instead of igc_xfree.
>>>
>>> I noticed that creating a new frame took longer and longer over time
>>> recently. Up to a dozen of seconds.
>>
>> Thanks! Trying to reproduce that here with:
>>
>> ./src/emacs -Q --eval '(run-with-timer 1.0 1.0 (lambda () (delete-frame (make-frame))))'
>>
>> indicates 8 xzalloc-ambig roots apparently leaked per frame created
>> (after the fix I just pushed).  Ouch.  Even if we xfree() those, that's
>> a great number of heap words incorrectly declared to be ambiguous roots,
>> which may hide other bugs.
>>
>> No apparent leak with --with-x-toolkit=no, so we know where to look.
>
> Or not.  It's down to one leak/frame now, which is still bad, but I

It's weird bug day: I'm seeing one leak/frame sometimes, sometimes it's
two leaks/frame, and I expected the following patch to give me a unique
call chain to a root that isn't freed:

diff --git a/src/igc.c b/src/igc.c
index f034aae9460..cac9cd5501c 100644
--- a/src/igc.c
+++ b/src/igc.c
@@ -858,6 +858,7 @@ igc_check_fwd (void *client, bool is_vector)
   void *start, *end;
   const char *label;
   bool ambig;
+  void *caller[4];
 };
 
 typedef struct igc_root igc_root;
@@ -3217,7 +3218,11 @@ igc_xzalloc_ambig (size_t size)
   void *end = (char *) p + size;
   if (end == p)
     end = (char *) p + IGC_ALIGN_DFLT;
-  root_create_ambig (global_igc, p, end, "xzalloc-ambig");
+  struct igc_root_list *r = root_create_ambig (global_igc, p, end, "xzalloc-ambig");
+  r->d.caller[0] = __builtin_return_address (0);
+  r->d.caller[1] = __builtin_return_address (1);
+  r->d.caller[2] = __builtin_return_address (2);
+  r->d.caller[3] = __builtin_return_address (3);
   return p;
 }

However, while I do see what I think are the 100 leaks after running

./src/emacs -Q --eval '(dotimes (i 100) (delete-frame (make-frame)))'

they have different call chains.

I'm using

p global_igc->roots[0]
while 1
p *$.next
end

in GDB, and I was expecting the leaked roots to be among the first
values printed.

Is there something obvious I'm doing wrong?  Or are we really creating
menuitems in such a way that we usually leak one, but it's random which
one?

Pip