Subject: bug#75870: 30.0.93; feature/igc: Breakpoint 1, terminate_due_to_signal (sig=sig@entry=6, backtrace_limit=backtrace_limit@entry=40) at ./src/emacs.c:432

From: Pip Cet <[email-masked]>
Date: Tue, 28 Jan 2025 18:26:20 +0000

"Gregor Zattler via \"Bug reports for GNU Emacs, the Swiss army knife of text editors\"" <[email-masked]> writes:

> Dear Emacs developers,

Hello Gregor!

Sorry I'm only getting to this now.

> when I switched to the Emacs frame it
> stayed blank and in GDB I saw
>
> Breakpoint 1, terminate_due_to_signal (sig=sig@entry=6, backtrace_limit=backtrace_limit@entry=40) at ./src/emacs.c:432

That means we aborted, which may be hard or easy to track down.  In this
case, it's the latter.

> it wasn't me who signalled to Emacs, at
> least not deliberately.  Therefore i
> wouldn't know how to reproduce.

abort() is handled on GNU/Linux by making a process send a signal to
itself, and then it will terminate upon receiving it.

> I started another instance of this very
> Emacs build in order to get the version
> and configuring info, see next.  At the
> very end of this email find the GDB
> output from 'bt' and 'xbacktrace' (the
> latter empty).

So these are two backtraces?

> If you have questions involving GDB
> please give specific instructions how to
> get the needed info.

> HTH, Gregor

It definitely does!

> Breakpoint 1, terminate_due_to_signal (sig=sig@entry=6, backtrace_limit=backtrace_limit@entry=40) at ./src/emacs.c:432
> 432	{
> #0  terminate_due_to_signal (sig=sig@entry=6, backtrace_limit=backtrace_limit@entry=40) at ./src/emacs.c:432
> #1  0x00005555555b39a2 in emacs_abort () at ./src/sysdep.c:2390
> #2  0x00005555555cc9ff in igc_check_freeable (start=start@entry=0x555556646030) at ./src/igc.c:3068

I wrote igc_check_freeable to catch cases in which an igc_xzalloc was
paired with an xfree rather than an igc_xfree.  If undetected, such
unbalanced calls would leak roots, which can be a major slowdown.

> #3  0x00005555557ef088 in xfree (block=0x555556646030) at ./src/alloc.c:842
> #4  xfree (block=0x555556646030) at ./src/alloc.c:835
> #5  0x000055555571e72c in xi_disable_devices (dpyinfo=dpyinfo@entry=0x555556633190, to_disable=to_disable@entry=0x7fffffffb340, n_disabled=n_disabled@entry=1) at ./src/xterm.c:13970

That line is:

      xfree (dpyinfo->devices);

You know where this is going.  Here's where we allocated it:

#ifdef HAVE_MPS
  // FIXME/igc: use exact references
  dpyinfo->devices = igc_xzalloc_ambig (sizeof *dpyinfo->devices * ndevices);
#else
  dpyinfo->devices = xzalloc (sizeof *dpyinfo->devices * ndevices);
#endif

So the we shouldn't call xfree, but:

#ifdef HAVE_MPS
  igc_xfree (dpyinfo->devices);
#else
  xfree (dpyinfo->devices);
#endif

> #6  0x0000555555730ede in xi_disable_devices (n_disabled=1, to_disable=0x7fffffffb340, dpyinfo=0x555556633190) at ./src/xterm.c:13885

I'm not entirely sure what precisely a device is in terms of XI.  Did
you add or remove a mouse/keyboard/touchscreen, or suspend and resume
your computer?  Or maybe connect or disconnect from a docking station?
Many USB devices are also "input" devices, so it might have been one of
those, like a hardware security token (which emulates a keyboard) or a
sound device (which has buttons which might be handled by XI).

Here's the patch:

>From aad2659d864d7ab2f81ab1983a5d85e966d14708 Mon Sep 17 00:00:00 2001
From: Pip Cet <[email-masked]>
Subject: [PATCH] [MPS] Fix crashes on XI devices being disabled (bug#75870)

* src/xterm.c (x_free_xi_devices):
(xi_disable_devices) [HAVE_MPS]: Use 'igc_xfree', not 'xfree'.
---
 src/xterm.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/src/xterm.c b/src/xterm.c
index ada7fbc2e41..049e283cdbc 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -5414,7 +5414,11 @@ x_free_xi_devices (struct x_display_info *dpyinfo)
 #endif /* HAVE_XINPUT2_2 */
 	}
 
+#ifdef HAVE_MPS
+      igc_xfree (dpyinfo->devices);
+#else
       xfree (dpyinfo->devices);
+#endif
       dpyinfo->devices = NULL;
       dpyinfo->num_devices = 0;
     }
@@ -13967,7 +13971,11 @@ xi_disable_devices (struct x_display_info *dpyinfo,
     }
 
   /* Free the old devices array and replace it with ndevices.  */
+#ifdef HAVE_MPS
+  igc_xfree (dpyinfo->devices);
+#else
   xfree (dpyinfo->devices);
+#endif
 
   dpyinfo->devices = devices;
   dpyinfo->num_devices = ndevices;
-- 
2.47.1

It's reasonably obvious, so I'll push it and close this bug ASAP.

Thank you again for the report.  Please keep those coming if you can do
so at all!

Pip