Public bug reported:

**Target:** `ubuntu/+source/gtk4` (package `libgtk-4-1`)
**File against:** `libgtk-4-1` 4.22.4+ds-0ubuntu0.1

---

## Title

gtk4 4.22.4: SIGSEGV in gdk_surface_handle_event() on a tablet-pad event
carrying no surface (GDK_PAD_GROUP_MODE) after USB re-enumeration

---

## Description

### Summary

Any running GTK4 application crashes with SIGSEGV in
`gdk_surface_handle_event()` (`gdk/gdksurface.c:2993`) when a tablet-pad
event is delivered while the client has no keyboard focus. The event is
created with a NULL surface and `GDK_SURFACE_IS_MAPPED (surface)` dereferences
it without a guard.

On this machine the crash correlates with the tablet's USB HID devices
re-enumerating, which happens on resume from suspend; four of five resumes
with Ghostty running killed it. It is not application-specific: Nautilus,
Ptyxis, gnome-system-monitor and Ghostty have all died at the same
instruction.

### How it was observed

- Ghostty 1.4.0 (GTK runtime), HUION tablet connected, suspend then resume:
  SIGSEGV one second after `PM: suspend exit`, on four out of five resumes.
- Ghostty, no suspend involved: a full re-enumeration of the USB hub the
  tablet is attached to killed it two seconds later (2026-11-02 08:36:41).
- Nautilus, twelve suspend/resume attempts on the same machine with the
  tablet connected and Nautilus focused: no crash.

The failure is therefore timing dependent rather than a simple recipe. The
most likely condition is that the client is still processing its Wayland
socket when the pad re-registers, so GTK has not yet handled
`wl_keyboard.enter` while mutter already considers that client focused. A
faster or less loaded client processes the enter first and survives.

Locking the screen and touching the dial does **not** reproduce it. With the
lock screen up, `meta_wayland_seat_get_input_focus()` returns NULL, so mutter
assigns the pad no focus client and broadcasts nothing; the application never
receives the pad event at all.

### Steps to reproduce (best effort)

1. Connect a tablet whose pad exposes dial / touch strip / mode groups.
   Tested with HUION Huion Tablet (USB ID `256c:006d`), which presents
   `HUION Huion Tablet Pad`, `... Touch Strip` and `... Dial`.
2. Start a GTK4 application and leave it focused (Ghostty 1.4.0 has been the
   most consistent victim here).
3. Suspend and resume, so the tablet's USB HID devices re-enumerate. Do not
   touch input for a few seconds after resume.
4. The application exits with SIGSEGV and the kernel logs
   `segfault at 3c ... in libgtk-4.so.1.2200.4[5a33b1,...]`.


### Expected behaviour

The application ignores a pad event it cannot associate with a surface.

### Actual behaviour

```
kernel: ghostty[84179]: segfault at 3c ip 00007845717783b1 sp ... error 4
        in libgtk-4.so.1.2200.4[5a33b1,7845712a9000+571000] likely on CPU 3
```

### Backtrace

Symbolized with the `libgtk-4-1` debug info from debuginfod
(build-id `4c74ae5215a17f78b116635961e03231361bf671`):

```
#0  gdk_surface_handle_event.isra.0 (event=...) at gdk/gdksurface.c:2993
#1  _gdk_event_emit (event=...) at gdk/gdkevents.c:491
#2  gdk_event_source_dispatch (...) at gdk/gdkeventsource.c
#3  g_main_context_dispatch_unlocked
#4  g_main_context_iterate_unlocked
#5  g_main_context_iteration
#6  g_application_run
```

`gdk/gdksurface.c:2987-2994` in 4.22.4:

```c
gboolean
gdk_surface_handle_event (GdkEvent *event)
{
  GdkSurface *surface = gdk_event_get_surface (event);
  gint64 begin_time = GDK_PROFILER_CURRENT_TIME;
  gboolean handled = FALSE;

  if (!GDK_SURFACE_IS_MAPPED (surface))   /* line 2993 */
    return FALSE;
```

`GDK_SURFACE_IS_MAPPED` is `((surface)->pending_is_mapped)`
(`gdk/gdksurfaceprivate.h:172`). Disassembling the crashing instruction
confirms the mechanism:

```
5a33b1:  41 8b 4c 24 3c      mov  0x3c(%r12),%ecx     ; r12 == NULL
```

The fault address reported by the kernel is `0x3c`, i.e. `surface == NULL`
and `pending_is_mapped` at struct offset `0x3c`.

### Root cause

`_gdk_event_emit()` (`gdk/gdkevents.c:491`) hands every event to
`gdk_surface_handle_event()`, which assumes the event has a surface.

The Wayland backend builds tablet-pad events with `seat->keyboard_focus` as
their surface (`gdk/wayland/gdkseat-wayland.c`):

| handler | line |
|---|---|
| `tablet_pad_ring_handle_frame` | 3379 |
| `tablet_pad_strip_handle_frame` | 3456 |
| `tablet_pad_group_handle_mode_switch` | 3582 |
| `tablet_pad_dial_handle_frame` | 3619 |
| `tablet_pad_button_handle_button` | 3755 |

`seat->keyboard_focus` is NULL whenever GTK has no keyboard focus surface,
which is the case in the window between resume and the arrival of
`wl_keyboard.enter`. The pad event is then queued with `surface == NULL` and
crashes the first GTK4 client that dispatches it.

The compositor side is what makes this fire on resume. When a pad registers,
mutter assigns it the current input focus and broadcasts the pad's mode:

```c
/* src/wayland/meta-wayland-tablet-pad-group.c */
meta_wayland_tablet_pad_group_sync_focus (MetaWaylandTabletPadGroup *group)
{
  ...
  if (!wl_list_empty (&group->focus_resource_list))
    {
      broadcast_group_mode (group, clutter_get_current_event_time ());
```

and `meta_wayland_tablet_seat_device_added()` picks that focus from
`meta_wayland_seat_get_input_focus (seat)` at the moment the device appears
(`src/wayland/meta-wayland-tablet-seat.c`). During resume the pad re-registers
while the seat still points at the previously focused client, but GTK has not
yet received the new keyboard enter, so `seat->keyboard_focus` is still NULL
when the `mode_switch` arrives.

Upstream GTK issue #8285 contains a gdb dump of the same event, confirming
the event type and the NULL surface:

```
(gdb) p *event
$8 = {
  event_type = GDK_PAD_GROUP_MODE,
  surface = 0x0,
  device = 0x55e60969b4f0,
  ...
}
```

### Scope on this machine

Same instruction, same fault address, different applications:

```
2026-07-27  gnome-system-mo  segfault at 3c ... libgtk-4.so.1.2200.4[5a33b1,...]
2026-09-11  ptyxis           segfault at 3c ... libgtk-4.so.1.2200.4[5a33b1,...]
2026-09-17  ptyxis           segfault at 3c ... libgtk-4.so.1.2200.4[5a33b1,...]
2026-09-21  nautilus         segfault at 3c ... libgtk-4.so.1.2200.4[5a33b1,...]
2026-09-23  nautilus         segfault at 3c ... libgtk-4.so.1.2200.4[5a33b1,...]
2026-11-01  ghostty          segfault at 3c ... libgtk-4.so.1.2200.4[5a33b1,...]
2026-11-02  ghostty (x3)     segfault at 3c ... libgtk-4.so.1.2200.4[5a33b1,...]
2026-11-03  ghostty          segfault at 3c ... libgtk-4.so.1.2200.4[5a33b1,...]
```

Four of the Ghostty crashes land one second after `PM: suspend exit`. The
remaining one (2026-11-02 08:36:41) happened during a full re-enumeration of
the USB hub the tablet is attached to, with no suspend involved, which points
at device re-enumeration rather than at power management:

```
08:36:38  usb 1-12: new high-speed USB device number 9
08:36:39  input: HUION Huion Tablet Pad as /devices/.../input/input37
08:36:39  input: HUION Huion Tablet Touch Strip as /devices/.../input/input38
08:36:39  input: HUION Huion Tablet Dial as /devices/.../input/input39
08:36:41  kernel: ghostty[67283]: segfault at 3c ...
```

### Upstream

- GNOME/gtk#8285 — "Crash during screen configuration change"
  https://gitlab.gnome.org/GNOME/gtk/-/work_items/8285
- GNOME/gtk#8368 — "gdk_surface_handle_event: SIGSEGV dereferencing surface
  in nautilus (GDK_SURFACE_IS_MAPPED, gdksurface.c:2993)"
  https://gitlab.gnome.org/GNOME/gtk/-/work_items/8368

Both are open. The missing NULL check is still present in 4.22.4, in
4.22.5 and on the `gtk-4-22` branch, so this is not fixed by an upstream
point release at the time of filing.

No duplicate found in `ubuntu/+source/gtk4` on Launchpad.

### Proposed fix

Minimal guard, `gdk/gdksurface.c`:

```diff
   GdkSurface *surface = gdk_event_get_surface (event);
   gint64 begin_time = GDK_PROFILER_CURRENT_TIME;
   gboolean handled = FALSE;

+  if (surface == NULL)
+    return FALSE;
+
   if (!GDK_SURFACE_IS_MAPPED (surface))
     return FALSE;
```

A broader fix would be to make `_gdk_event_emit()` skip surface-bearing event
types when `gdk_event_get_surface()` returns NULL, and/or to stop using
`seat->keyboard_focus` as the surface for pad events, since pad events are
device-level and not tied to a window.

### Workaround

Unplugging the tablet before suspending prevents the crash. Setting
`GDK_BACKEND=x11` for the affected application also avoids it: the X11
backend creates no tablet-pad events at all.

### Environment

```
Ubuntu 26.04.1 LTS (resolute), amd64
libgtk-4-1        4.22.4+ds-0ubuntu0.1   (resolute-updates)
libglib2.0-0t64   2.88.0-1ubuntu0.1
libwayland-client0 1.24.0-2
gnome-shell       50.1-0ubuntu1.4
mutter            50.1
Linux 7.0.0-42-generic
GNOME on Wayland (XDG_SESSION_TYPE=wayland)
Display on AMD Granite Ridge iGPU (amdgpu); GTK uses Mesa EGL 4.6
Tablet: HUION Huion Tablet, USB 256c:006d
```

Ghostty is the classic Snap (`ghostty` v1.4.0, rev 1016), i.e. it links
against the host `libgtk-4-1`, not a bundled GTK; the crash is unrelated to
the Snap packaging.

---

## Attachments

- `journal-suspend-crash.txt` — already prepared, contains all ten crashes,
  the resume window with USB re-enumeration, the non-suspend crash, the
  suspend history and the tablet device list.
- No `.crash` file is attached. Ghostty is a classic Snap and Snap crashes are
  not collected by apport, and the failure could not be reproduced on demand
  with a packaged application (twelve suspend/resume attempts with Nautilus
  produced nothing). The symbolized frame above comes from Ubuntu's
  debuginfod data for build-id
  `4c74ae5215a17f78b116635961e03231361bf671`.

---

## Submission notes

File with:

```
ubuntu-bug libgtk-4-1
```

or via the web form:

```
https://bugs.launchpad.net/ubuntu/+source/gtk4/+filebug
```

Paste the Title and the Description above. After filing, add bug watches
for GNOME/gtk issues #8285 and #8368 (the "Also affects project" /
"Add bug watch" links on the bug page), so the Ubuntu status tracks upstream.

Note: no `.crash` file exists for the Ghostty crashes, because Snap crashes
are not collected by apport. If a triager asks for a core dump, it can be
produced later by running a packaged GTK4 application and catching the same
race; the analysis in this report does not depend on one.

ProblemType: Bug
DistroRelease: Ubuntu 26.04
Package: libgtk-4-1 4.22.4+ds-0ubuntu0.1
ProcVersionSignature: Ubuntu 7.0.0-42.42-generic 7.0.14
Uname: Linux 7.0.0-42-generic x86_64
ApportVersion: 2.34.1-0ubuntu0.1
Architecture: amd64
CasperMD5CheckResult: unknown
CurrentDesktop: ubuntu:GNOME
Date: Tue Nov  3 06:55:14 2026
InstallationDate: Installed on 2025-02-06 (635 days ago)
InstallationMedia: Ubuntu 24.04.1 LTS "Noble Numbat" - Release amd64 
(20240827.1)
ProcEnviron:
 LANG=en_US.UTF-8
 PATH=(custom, no user)
 SHELL=/bin/bash
 TERM=xterm-256color
 XDG_RUNTIME_DIR=<set>
SourcePackage: gtk4
UpgradeStatus: No upgrade log present (probably fresh install)

** Affects: gtk4 (Ubuntu)
     Importance: Undecided
         Status: New


** Tags: amd64 apport-bug resolute wayland-session

** Attachment added: "journal-suspend-crash.txt"
   
https://bugs.launchpad.net/bugs/2172827/+attachment/6014645/+files/journal-suspend-crash.txt

-- 
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2172827

Title:
  gtk4 4.22.4: SIGSEGV in gdk_surface_handle_event() on a tablet-pad
  event carrying no surface (GDK_PAD_GROUP_MODE) after USB re-
  enumeration

To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/gtk4/+bug/2172827/+subscriptions


-- 
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs

Reply via email to