filechooser crashes when called to save file from X11 app on Wayland
When trying to save a file from the Brave browser, which uses X11, xdg-desktop-portal-gnome crashes.
The file open dialog succeeds, but crashes if I change the sorting order. The save file dialog succeeds when called from a Wayland app.
I've done a bit of triage, but got into the weeds pretty quickly. I've attached the full backtrace for reference, but the interesting bits are here:
#0 wl_proxy_get_version (proxy=proxy@entry=0x0) at ../src/wayland-client.c:2200
#1 0x00007fd0d7a52f2c in wl_display_get_registry (wl_display=0x0) at /usr/include/wayland/wayland-client-protocol.h:1062
#2 gtk_im_context_wayland_global_get (display=0x55a0504c80f0 [GdkX11Display]) at ../gtk/gtkimcontextwayland.c:782
#3 gtk_im_context_wayland_global_get (display=0x55a0504c80f0 [GdkX11Display]) at ../gtk/gtkimcontextwayland.c:772
#4 0x00007fd0d7a53446 in gtk_im_context_wayland_focus_in (context=0x55a0508269f0 [GtkIMContextWayland]) at ../gtk/gtkimcontextwayland.c:803
We're getting the NULL
display due to gdk_wayland_display_get_wl_display()
returning NULL
in frame 2. It's returning NULL because of the following check in gdk_wayland_display_get_wl_display()
.
g_return_val_if_fail (GDK_IS_WAYLAND_DISPLAY (display), NULL);
The display comes from:
gtk_im_context_wayland_focus_in() ->
gtk_widget_get_display(self->widget) ->
_gtk_widget_get_display(widget) ->
gtk_root_get_display(widget->priv->root) ->
GTK_ROOT_GET_IFACE(widget->priv->root)->get_display(widget->priv->root)
The interface resolves to the interface set up via gtk_window_root_interface_init()
and means that ->get_display
is gtk_window_root_get_display()
:
(gdb) print *(GtkRootInterface *)((IFaceEntries *)((TypeNode *)((GTypeInstance *)self->widget->priv->root)->g_class->g_type)->_prot.iface_entries->data)->entry[5]->vtable
$46 = {g_iface = {g_type = 0x55a05034fa50 [GtkRoot], g_instance_type = 0x55a05034fc20 [GtkWindow/GtkWidget/GInitiallyUnowned]}, get_display = 0x7fd0d79bb330 <gtk_window_root_get_display>,
get_constraint_solver = 0x7fd0d79bb3c0 <gtk_window_root_get_constraint_solver>, get_focus = 0x7fd0d79bb420 <gtk_window_root_get_focus>, set_focus = 0x7fd0d79bfd40 <gtk_window_root_set_focus>}
Which means that root is GtkWindow and we'll pull the display out of GtkWindowPrivate.
(gdb) print &GtkWindow_private_offset
Can't take address of "GtkWindow_private_offset" which isn't an lvalue.
(gdb) disass gtk_window_root_get_display
Dump of assembler code for function gtk_window_root_get_display:
0x00007fd0d79bb330 <+0>: push %rbp
0x00007fd0d79bb331 <+1>: mov %rdi,%rbp
0x00007fd0d79bb334 <+4>: call 0x7fd0d79baac0 <gtk_window_get_type>
0x00007fd0d79bb339 <+9>: mov %rbp,%rdi
0x00007fd0d79bb33c <+12>: mov %rax,%rsi
0x00007fd0d79bb33f <+15>: call 0x7fd0d7768830 <g_type_check_instance_cast@plt>
0x00007fd0d79bb344 <+20>: movslq 0x5733f5(%rip),%rdx # 0x7fd0d7f2e740 <GtkWindow_private_offset.lto_priv.0>
0x00007fd0d79bb34b <+27>: pop %rbp
0x00007fd0d79bb34c <+28>: mov 0x30(%rdx,%rax,1),%rax
0x00007fd0d79bb351 <+33>: ret
End of assembler dump.
(gdb) print *(gint *)0x7fd0d7f2e740
$61 = -576
(gdb) print ((GtkWindowPrivate *)((char *)((GtkWindow *)self->widget->priv->root)-576))->display
$67 = 0x55a0504c80f0 [GdkX11Display]
... which is a GdkX11Display and thus fails the check.