GNOME Bugzilla – Bug 793062
[Wayland] Crash under gdk_wayland_window_attach_image()
Last modified: 2018-03-27 08:37:28 UTC
Follow up from Bug 773274 comment 27. The provided patch from https://bugzilla.gnome.org/attachment.cgi?id=367641&action=diff works as expected - the issue is fixed.
I see another crash with this patch applied: (gdb) p impl->display_server.wl_surface $2 = (struct wl_surface *) 0x0 It also comes from the expose event handler, bt:
+ Trace 238373
This crash happens at gdk_window_impl_wayland_end_paint() and at wl_surface_damage() where impl->display_server.wl_surface is null.
I wonder how we can end up in end_paint() with a wl_surface being NULL. _gdk_frame_clock_emit_paint() ends up calling gtk_widget_render() which calls gdk_window_end_draw_frame (window, context) which calls gdk_window_impl_wayland_end_paint(), but there the window's wl_surface is NULL. As Martin pointed out, this is from: 1833 case GDK_EXPOSE: 1834 if (event->any.window) 1835 gtk_widget_render (event_widget, event->any.window, event->expose.region); 1836 break; So the window here from event->any.window has its wl_surface NULL. That event here comes from _gdk_window_process_updates_recurse_helper(): 3835 /* While gtk+ no longer handles exposes on anything but native 3836 window we still have to send them to all windows that have the 3837 event mask set for backwards compat. We also need to send 3838 it to all native windows, even if they don't specify the 3839 expose mask, because they may have non-native children that do. */ 3840 if (gdk_window_has_impl (window) || 3841 window->event_mask & GDK_EXPOSURE_MASK) 3842 { 3843 GdkEvent event; 3844 3845 event.expose.type = GDK_EXPOSE; 3846 event.expose.window = window; /* we already hold a ref */ 3847 event.expose.send_event = FALSE; 3848 event.expose.count = 0; 3849 event.expose.region = clipped_expose_region; 3850 cairo_region_get_extents (clipped_expose_region, &event.expose.area); 3851 3852 _gdk_event_emit (&event); 3853 } 3854 And this is from gdk_window_process_updates_internal(window) called from: 4163 static void 4164 gdk_window_process_updates_with_mode (GdkWindow *window, 4165 int recurse_mode) 4166 { ... 4174 4175 find_impl_windows_to_update (list, window, recurse_mode); 4176 4177 if (window->impl_window != window) 4178 g_ptr_array_add (list, g_object_ref (window->impl_window)); 4179 4180 for (i = (int)list->len - 1; i >= 0; i --) 4181 { 4182 GdkWindow *impl_window = g_ptr_array_index (list, i); 4183 4184 if (impl_window->update_area && 4185 !impl_window->update_freeze_count && 4186 !gdk_window_is_toplevel_frozen (impl_window) && 4187 4188 /* Don't recurse into process_updates_internal, we'll 4189 * do the update later when idle instead. */ 4190 !impl_window->in_update) 4191 { 4192 gdk_window_process_updates_internal (impl_window); 4193 gdk_window_remove_update_window (impl_window); 4194 } 4195 }
You can use this package to do the testing: https://koji.fedoraproject.org/koji/buildinfo?buildID=1022923 it runs natively under Wayland.
(In reply to Martin Stransky from comment #4) > You can use this package to do the testing: > > https://koji.fedoraproject.org/koji/buildinfo?buildID=1022923 > > it runs natively under Wayland. Yeah, but it's hardly usable to be honest. I'm not even sure how to reproduce with it.
(In reply to Olivier Fourdan from comment #5) > (In reply to Martin Stransky from comment #4) > > You can use this package to do the testing: > > > > https://koji.fedoraproject.org/koji/buildinfo?buildID=1022923 > > > > it runs natively under Wayland. > > Yeah, but it's hardly usable to be honest. I'm not even sure how to > reproduce with it. :) well only issue I'm aware of is missing clipboard selection (mouse middle button paste). If you see crashes it may be caused by this bug - you need to enable ABRT to catch the crashes probably or run the browser under gdb. Or is there anything else?
Nope, no crash (yet), but it's hardly usable for me because all menus are truncated, missing most of the entries. Seems like restarting FF has fixed it now... weird.
OK, I managed to reproduce a couple of times (every time that occured while switching back to the FF window, when it changes from “unfocused” to “focused” state) and take a closer look at hte GdkWindow being “end-painted”: gdb) p *window $1 = {parent_instance = {g_type_instance = {g_class = 0x7ffff6a6b6b0}, ref_count = 10, qdata = 0x7fffb60d3580}, impl = 0x7fffb6f09400 [GdkWindowImplWayland], parent = 0x7ffff6abf050 [GdkWaylandWindow], transient_for = 0x7fffcf0f1250 [GdkWaylandWindow], visual = 0x7ffff6abd180 [GdkWaylandVisual], user_data = 0x7fffb6f09260, x = 238, y = 101, event_mask = 6553366, window_type = 3 '\003', depth = 32 ' ', resize_count = 0 '\000', toplevel_window_type = -1 '\377', filters = 0x0, children = 0x7fffb799c630 = {0x7fffb799c5d0}, children_list_node = {data=0x7fffb799c440, next=0x7fffac145310, prev=0x7fffb799c950}, native_children = 0x0, background = 0x7fffabe11060, current_paint = {surface = 0x7fffacdf2b00, region = 0x7fffb610fd00, flushed_region = 0x7fffb63702e0, need_blend_region = 0x7fffb6370300, surface_needs_composite = 0, use_gl = 0}, gl_paint_context = 0x0, update_area = 0x0, update_freeze_count = 0, active_update_area = 0x7fffb610f0e0, old_updated_area = {0x0, 0x0}, old_state = GDK_WINDOW_STATE_FOCUSED, state = (GDK_WINDOW_STATE_WITHDRAWN | GDK_WINDOW_STATE_FOCUSED), alpha = 255 '\377', fullscreen_mode = 0 '\000', input_only = 0, pass_through = 0, modal_hint = 0, composited = 0, has_alpha_background = 0, destroyed = 0, accept_focus = 1, focus_on_map = 1, shaped = 0, support_multidevice = 0, synthesize_crossing_event_queued = 1, effective_visibility = 3, visibility = 2, native_visibility = 0, viewable = 0, applied_shape = 0, in_update = 1, geometry_dirty = 1, event_compression = 1, frame_clock_events_paused = 0, impl_window = 0x7fffb799c440 [GdkWaylandWindow], update_and_descendants_freeze_count = 0, abs_x = 0, abs_y = 0, width = 314, height = 200, shadow_top = 0, shadow_left = 0, shadow_right = 0, shadow_bottom = 0, num_offscreen_children = 0, clip_region = 0x7fffb6370720, cursor = 0x0, device_cursor = 0x7fffabe249a0, shape = 0x0, input_shape = 0x0, devices_inside = 0x0, device_events = 0x0, source_event_masks = 0x0, device_added_handler_id = 0, device_changed_handler_id = 0, frame_clock = 0x7fffabad3cb0 [GdkFrameClockIdle], invalidate_handler = 0x0, drawing_context = 0x7fffb84358e0 [GdkDrawingContext], opaque_region = 0x0} (gdb) p (GdkWindowImplWayland) *window->impl $2 = {parent_instance = {parent = {g_type_instance = {g_class = 0x7ffff6a19c00}, ref_count = 3, qdata = 0x0}}, wrapper = 0x7fffb799c440 [GdkWaylandWindow], display_server = {outputs = 0x0, wl_surface = 0x0, xdg_surface = 0x0, xdg_toplevel = 0x0, xdg_popup = 0x0, gtk_surface = 0x0, wl_subsurface = 0x0, egl_window = 0x0, dummy_egl_window = 0x0, xdg_exported = 0x0, server_decoration = 0x0}, egl_surface = 0x0, dummy_egl_surface = 0x0, initial_configure_received = 0, mapped = 0, use_custom_surface = 0, pending_buffer_attached = 0, pending_commit = 0, awaiting_frame = 0, hint = GDK_WINDOW_TYPE_HINT_UTILITY, transient_for = 0x7fffcf0f1250 [GdkWaylandWindow], popup_parent = 0x0, position_method = POSITION_METHOD_MOVE_RESIZE, staging_cairo_surface = 0x7fffacdf2b00, committed_cairo_surface = 0x0, backfill_cairo_surface = 0x0, pending_buffer_offset_x = 0, pending_buffer_offset_y = 0, title = 0x7fffabf4c4b0 "Firefox", application = {was_set = 0, application_id = 0x0, app_menu_path = 0x0, menubar_path = 0x0, window_object_path = 0x0, application_object_path = 0x0, unique_bus_name = 0x0}, geometry_hints = {min_width = 1, min_height = 2, max_width = 32767, max_height = 32767, base_width = 1, base_height = 2, width_inc = 13, height_inc = 0, min_aspect = 6.9533024459871814e-310, max_aspect = 0, win_gravity = GDK_GRAVITY_NORTH_WEST}, geometry_mask = (GDK_HINT_POS | GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE | GDK_HINT_WIN_GRAVITY), grab_input_seat = 0x0, pending_frame_counter = 0, scale = 1, margin_left = 0, margin_right = 0, margin_top = 0, margin_bottom = 0, margin_dirty = 0, initial_fullscreen_monitor = -1, opaque_region = 0x0, opaque_region_dirty = 1, input_region = 0x0, input_region_dirty = 1, staged_updates_region = 0x0, saved_width = -1, saved_height = -1, parent_surface_committed_handler = 0, pending_move_to_rect = {rect = {x = 0, y = 0, width = 0, height = 0}, rect_anchor = 0, window_anchor = 0, anchor_hints = 0, rect_anchor_dx = 0, rect_anchor_dy = 0}, pending = { width = 0, height = 0, state = (unknown: 0)}, exported = {handle = 0x0, export_count = 0, closures = 0x0, idle_source_id = 0}, imported_transient_for = 0x0, shortcuts_inhibitors = 0x7fffabe24a00 = {[0x621] = 0x621}}
that's a weird combo: state = (GDK_WINDOW_STATE_WITHDRAWN | GDK_WINDOW_STATE_FOCUSED)
“old_state = GDK_WINDOW_STATE_FOCUSED, state = (GDK_WINDOW_STATE_WITHDRAWN | GDK_WINDOW_STATE_FOCUSED)” seems weird, how can a window be withdrawn and focused? Another weird thing is: display_server = {outputs = 0x0, wl_surface = 0x0, xdg_surface = 0x0, xdg_toplevel = 0x0, xdg_popup = 0x0, gtk_surface = 0x0, wl_subsurface = 0x0, egl_window = 0x0, dummy_egl_window = 0x0, xdg_exported = 0x0, server_decoration = 0x0}, egl_surface = 0x0, dummy_egl_surface = 0x0, initial_configure_received = 0, mapped = 0, use_custom_surface = 0, pending_buffer_attached = 0, pending_commit = 0, awaiting_frame = 0 All values are 0, as if the surface was withdrawn. Also hint = GDK_WINDOW_TYPE_HINT_UTILITY, This comes from Firefox code: 3517 nsresult 3518 nsWindow::Create(nsIWidget* aParent, 3519 nsNativeWidget aNativeParent, 3520 const LayoutDeviceIntRect& aRect, 3521 nsWidgetInitData* aInitData) 3522 { ... 3690 switch (aInitData->mPopupHint) { 3691 case ePopupTypeMenu: 3692 // Use GDK_WINDOW_TYPE_HINT_UTILITY on Wayland which 3693 // guides Gtk to create the popup as subsurface 3694 // instead of xdg_shell popup (see Bug 1423598). 3695 gtkTypeHint = mIsX11Display ? GDK_WINDOW_TYPE_HINT_POPUP_MENU : 3696 GDK_WINDOW_TYPE_HINT_UTILITY; So the window causing this issue would be a “ePopupTypeMenu”.
Created attachment 367922 [details] [review] [PATCH] gdkwindow: Do not generate expose event if not mapped If a window is not mapped, we shouldn't be generating fake expose events, that can causes crashes further down the tree with Wayland when not using GL.
Can you try with this patch?
FWIW, I've been running with this patch since yesterday and had no crash in gdk Wayland code since then. Not surprising, if the window is withdrawn, the Wayland resources are NULL (what the see in the GdkWindowImplWayland in comment 8), so by not generating expose events when the window is withdrawn (attachment 367922 [details] [review]), we avoid the crash. Yet, I wonder if Firefox is not leaking Wayland resources somehow, I left it running overnight and today my entire system started to crawl, with ram and swap up to 90% (the system has 12Gb or RAM) and gnome-shell taking most of that. Killing Firefox freed a large part of the memory used by gnome-shell, so I suspect Firefox might be leaking resources. However I don't think the leak is caused by the patch (attachment 367922 [details] [review]), but it might be the same root cause.
I'll check that patch, Thanks. The leaking is interesting, I'll check that.
I am not 100% sure about the leak, I've left FF running a few times overnight and that did not happen. The patch fixes the issue, I reckon.
With the latest patch applied I still see a crash:
+ Trace 238394
it comes from expose event. (gdb) p* window $3 = { parent_instance = { g_type_instance = { g_class = 0x7fcd1cd616b0 }, ref_count = 11, qdata = 0x7fcce02d9780 }, impl = 0x7fcce91d9000 [GdkWindowImplWayland], parent = 0x7fcd1cdbe050 [GdkWaylandWindow], transient_for = 0x7fcce977c5d0 [GdkWaylandWindow], visual = 0x7fcd1cdb6440 [GdkWaylandVisual], user_data = 0x7fcce896fe60, x = 23, y = 88, event_mask = 6553366, window_type = 3 '\003', depth = 32 ' ', resize_count = 0 '\000', toplevel_window_type = -1 '\377', filters = 0x0, children = 0x7fcce96f7b40 = {0x7fcce96f7ae0}, children_list_node = {data=0x7fcce96f7950, next=0x7fcce96f7500, prev=0x0}, native_children = 0x0, background = 0x7fccc8743d40, current_paint = { surface = 0x7fccc7d51980, region = 0x7fccf54172a0, flushed_region = 0x7fccf54172e0, need_blend_region = 0x7fccf54173e0, surface_needs_composite = 0, use_gl = 0 }, gl_paint_context = 0x0, update_area = 0x0, update_freeze_count = 0, active_update_area = 0x7fccea6fcb40, old_updated_area = {0x0, 0x0}, old_state = GDK_WINDOW_STATE_FOCUSED, state = (GDK_WINDOW_STATE_WITHDRAWN | GDK_WINDOW_STATE_FOCUSED), alpha = 255 '\377', fullscreen_mode = 0 '\000', input_only = 0, pass_through = 0, modal_hint = 0, composited = 0, has_alpha_background = 0, destroyed = 0, accept_focus = 1, focus_on_map = 1, shaped = 0, support_multidevice = 0, synthesize_crossing_event_queued = 1, effective_visibility = 3, visibility = 2, native_visibility = 0, viewable = 0, applied_shape = 0, in_update = 1, geometry_dirty = 1, event_compression = 1, frame_clock_events_paused = 0, impl_window = 0x7fcce96f7950 [GdkWaylandWindow], update_and_descendants_freeze_count = 0, abs_x = 0, abs_y = 0, width = 1185, height = 113, shadow_top = 0, shadow_left = 0, shadow_right = 0, shadow_bottom = 0, num_offscreen_children = 0, clip_region = 0x7fccf54177c0, cursor = 0x0, device_cursor = 0x7fccdae657c0 = { [0x5e1] = 0x5e1 }, shape = 0x0, input_shape = 0x0, devices_inside = 0x0, device_events = 0x0, source_event_masks = 0x0, device_added_handler_id = 0, device_changed_handler_id = 0, frame_clock = 0x7fccc7d2d860 [GdkFrameClockIdle], invalidate_handler = 0x0, drawing_context = 0x7fcce00eab80 [GdkDrawingContext], opaque_region = 0x0 }
I can 100% reproducible with the firefox-59 build I provide. Navigate to url bar and type "about:addons" there. When awesomebar disappears FF crashes.
(In reply to Martin Stransky from comment #16) > With the latest patch applied I still see a crash: Weird. Can you double-check the version you use is the one with the patch? Reason I ask is because the backtrace in comment #16 shows: #15 _gdk_window_process_updates_recurse_helper at gdkwindow.c line 3853 with: state = (GDK_WINDOW_STATE_WITHDRAWN | GDK_WINDOW_STATE_FOCUSED) However the patch calls the _gdk_event_emit() only if GDK_WINDOW_IS_MAPPED(window). GDK_WINDOW_IS_MAPPED() is defined as: #define GDK_WINDOW_IS_MAPPED(window) (((window)->state & GDK_WINDOW_STATE_WITHDRAWN) == 0) So with the patch applied you cannot get to frame #15 with “state = (GDK_WINDOW_STATE_WITHDRAWN | GDK_WINDOW_STATE_FOCUSED)” (In reply to Martin Stransky from comment #17) > I can 100% reproducible with the firefox-59 build I provide. Navigate to url > bar and type "about:addons" there. When awesomebar disappears FF crashes. Not here, with the patch applied, it works.
(In reply to Olivier Fourdan from comment #18) > (In reply to Martin Stransky from comment #16) > > With the latest patch applied I still see a crash: > > Weird. Can you double-check the version you use is the one with the patch? Yes, I checked it again. I use my own custom build with the patch, I checked package build log and the patch is applied. It also contains the first patch.
(In reply to Martin Stransky from comment #19) > Yes, I checked it again. I use my own custom build with the patch, I checked > package build log and the patch is applied. It also contains the first patch. First patch should not be needed, only attachment 367922 [details] [review] But if you get to comment 16 with attachment 367922 [details] [review], then this sounds like a multi-thread issue, /something/ changes the Gdkindow state between the test GDK_WINDOW_IS_MAPPED() and the _gdk_event_emit() in frame 15, otherwise I don't see how that's possible.
FWIW, the code in gdk/gdkwindow.c with the patch applied should read as: 3802 static void 3803 _gdk_window_process_updates_recurse_helper (GdkWindow *window, 3804 cairo_region_t *expose_region) 3805 { ... 3835 /* While gtk+ no longer handles exposes on anything but native 3836 window we still have to send them to all windows that have the 3837 event mask set for backwards compat. We also need to send 3838 it to all native windows, even if they don't specify the 3839 expose mask, because they may have non-native children that do. */ 3840 if (GDK_WINDOW_IS_MAPPED(window) && 3841 (gdk_window_has_impl (window) || 3842 window->event_mask & GDK_EXPOSURE_MASK)) 3843 { 3844 GdkEvent event; 3845 3846 event.expose.type = GDK_EXPOSE; 3847 event.expose.window = window; /* we already hold a ref */ 3848 event.expose.send_event = FALSE; 3849 event.expose.count = 0; 3850 event.expose.region = clipped_expose_region; 3851 cairo_region_get_extents (clipped_expose_region, &event.expose.area); 3852 3853 _gdk_event_emit (&event); 3854 } 3855 So we should not get to _gdk_event_emit() line 3853 with “state = (GDK_WINDOW_STATE_WITHDRAWN | GDK_WINDOW_STATE_FOCUSED)” because we're within “if (GDK_WINDOW_IS_MAPPED(window) && ...) { }” line 3840
Reproduced as well...
It may be useful to run Firefox under rr (http://rr-project.org/) and check how exactly that happens.
So I think what happens and I believe this is Firefox doing something unexpected. The issue occurs because the window we're updating recursively is being unmapped (on Wayland if you unmap a window, it's surface resource is destroyed). The patch (attachment 367922 [details] [review]) I posted checks for the window being mapped prior to calling the update, and that patch doesn't fix the issue, which means that when we checked, the window was mapped. When we crash, it's not mapped anymore, so “something” is unmapping the window while gdk is updating it recursively. Some tests shows this is not a threding issue, the crash and the unmap occur from within the same thread id. Unfortunately using a simple break in gdb on gdk_window_unmap() is not practical so the solution is to add a variable, increase its value prior to enter the recursion and check for its value when unmapping the window, so that we can tell exactly when the window is being unmapped from within the recursion. That leads to the following backtrace: (gdb) bt #0 mozalloc_abort (msg=msg@entry=0x55555557d6d8 "Redirecting call to abort() to mozalloc_abort\n") at /usr/src/debug/firefox-59.0-0.6.fc27.x86_64/memory/mozalloc/mozalloc_abort.cpp:33 #1 0x00005555555668b0 in abort () at /usr/src/debug/firefox-59.0-0.6.fc27.x86_64/memory/mozalloc/mozalloc_abort.cpp:80 #2 0x00007fffef81aa85 in g_assertion_message (domain=domain@entry=0x7ffff43a140e "Gdk", file=file@entry=0x7ffff43b8ee8 "/home/ofourdan/src/gnome/gtk+-3/gdk/gdkwindow.c", line=line@entry=5667, func=func@entry=0x7ffff43ba3e0 <__func__.66322> "gdk_window_hide", message=message@entry=0x7fffaad8ae50 "assertion failed: (recurse_level == 0)") at /home/ofourdan/src/gnome/glib/glib/gtestutils.c:2532 #3 0x00007fffef81aada in g_assertion_message_expr (domain=domain@entry=0x7ffff43a140e "Gdk", file=file@entry=0x7ffff43b8ee8 "/home/ofourdan/src/gnome/gtk+-3/gdk/gdkwindow.c", line=line@entry=5667, func=func@entry=0x7ffff43ba3e0 <__func__.66322> "gdk_window_hide", expr=expr@entry=0x7ffff43b8e6a "recurse_level == 0") at /home/ofourdan/src/gnome/glib/glib/gtestutils.c:2555 → #4 0x00007ffff43558b0 in gdk_window_hide (window=0x7fffab257760) at /home/ofourdan/src/gnome/gtk+-3/gdk/gdkwindow.c:5667 #5 0x00007fffe973be90 in moz_container_unmap (widget=0x7fffaa3319b0) at /usr/src/debug/firefox-59.0-0.6.fc27.x86_64/widget/gtk/mozcontainer.cpp:337 #6 0x00007fffefcd57d0 in _g_closure_invoke_va (closure=0x7ffff6afb420, return_value=0x0, instance=0x7fffaa3319b0, args=0x7fffffff9fe8, n_params=0, param_types=0x0) at /home/ofourdan/src/gnome/glib/gobject/gclosure.c:867 #7 0x00007fffefcf133e in g_signal_emit_valist (instance=0x7fffaa3319b0, signal_id=<optimized out>, detail=0, var_args=var_args@entry=0x7fffffff9fe8) at /home/ofourdan/src/gnome/glib/gobject/gsignal.c:3300 #8 0x00007fffefcf1802 in g_signal_emit (instance=instance@entry=0x7fffaa3319b0, signal_id=<optimized out>, detail=detail@entry=0) at /home/ofourdan/src/gnome/glib/gobject/gsignal.c:3447 → #9 0x00007ffff495c24c in gtk_widget_unmap (widget=0x7fffaa3319b0) at /home/ofourdan/src/gnome/gtk+-3/gtk/gtkwidget.c:5033 #10 0x00007fffefcd568d in g_closure_invoke (closure=0x7ffff6afb420, return_value=0x0, n_param_values=1, param_values=0x7fffffffa2a0, invocation_hint=0x7fffffffa240) at /home/ofourdan/src/gnome/glib/gobject/gclosure.c:804 #11 0x00007fffefce878e in signal_emit_unlocked_R (node=node@entry=0x7ffff6affb80, detail=detail@entry=0, instance=instance@entry=0x7fffaa908a60, emission_return=emission_return@entry=0x0, instance_and_params=instance_and_params@entry=0x7fffffffa2a0) at /home/ofourdan/src/gnome/glib/gobject/gsignal.c:3565 #12 0x00007fffefcf0f35 in g_signal_emit_valist (instance=<optimized out>, signal_id=<optimized out>, detail=<optimized out>, var_args=var_args@entry=0x7fffffffa448) at /home/ofourdan/src/gnome/glib/gobject/gsignal.c:3391 #13 0x00007fffefcf1802 in g_signal_emit (instance=instance@entry=0x7fffaa908a60, signal_id=<optimized out>, detail=detail@entry=0) at /home/ofourdan/src/gnome/glib/gobject/gsignal.c:3447 #14 0x00007ffff495c24c in gtk_widget_unmap (widget=0x7fffaa908a60) at /home/ofourdan/src/gnome/gtk+-3/gtk/gtkwidget.c:5033 #15 0x00007ffff4970e8c in gtk_window_hide (widget=0x7fffaa908a60) at /home/ofourdan/src/gnome/gtk+-3/gtk/gtkwindow.c:6217 #16 0x00007fffefcd568d in g_closure_invoke (closure=0x7ffff6afb3a0, return_value=0x0, n_param_values=1, param_values=0x7fffffffa720, invocation_hint=0x7fffffffa6c0) at /home/ofourdan/src/gnome/glib/gobject/gclosure.c:804 #17 0x00007fffefce878e in signal_emit_unlocked_R (node=node@entry=0x7ffff6affac0, detail=detail@entry=0, instance=instance@entry=0x7fffaa908a60, emission_return=emission_return@entry=0x0, instance_and_params=instance_and_params@entry=0x7fffffffa720) at /home/ofourdan/src/gnome/glib/gobject/gsignal.c:3565 #18 0x00007fffefcf0f35 in g_signal_emit_valist (instance=<optimized out>, signal_id=<optimized out>, detail=<optimized out>, var_args=var_args@entry=0x7fffffffa8c8) at /home/ofourdan/src/gnome/glib/gobject/gsignal.c:3391 #19 0x00007fffefcf1802 in g_signal_emit (instance=instance@entry=0x7fffaa908a60, signal_id=<optimized out>, detail=detail@entry=0) at /home/ofourdan/src/gnome/glib/gobject/gsignal.c:3447 #20 0x00007ffff4964235 in gtk_widget_hide (widget=0x7fffaa908a60) at /home/ofourdan/src/gnome/gtk+-3/gtk/gtkwidget.c:4901 #21 0x00007fffe97160b3 in nsWindow::NativeShow (this=0x7fffaa908400, aAction=<optimized out>) at /usr/src/debug/firefox-59.0-0.6.fc27.x86_64/widget/gtk/nsWindow.cpp:4232 #22 0x00007fffe96d2af4 in nsView::DoResetWidgetBounds (this=<optimized out>, aMoveOnly=<optimized out>, aInvalidateChangedSize=<optimized out>) at /usr/src/debug/firefox-59.0-0.6.fc27.x86_64/view/nsView.cpp:341 #23 0x00007fffe96d5fba in nsViewManager::ProcessPendingUpdatesForView (this=this@entry=0x7fffc14c5fc0, aView=<optimized out>, aFlushDirtyRegion=aFlushDirtyRegion@entry=true) at /usr/src/debug/firefox-59.0-0.6.fc27.x86_64/view/nsViewManager.cpp:399 #24 0x00007fffe96d61a5 in nsViewManager::ProcessPendingUpdates (this=this@entry=0x7fffc14c5fc0) at /usr/src/debug/firefox-59.0-0.6.fc27.x86_64/view/nsViewManager.cpp:1102 #25 0x00007fffe96d62d8 in nsViewManager::WillPaintWindow (this=this@entry=0x7fffc14c5fc0, aWidget=0x7fffaa908400) at /usr/src/debug/firefox-59.0-0.6.fc27.x86_64/view/nsViewManager.cpp:707 #26 0x00007fffe96d6326 in nsView::WillPaintWindow (this=<optimized out>, aWidget=<optimized out>) at /usr/src/debug/firefox-59.0-0.6.fc27.x86_64/view/nsView.cpp:1059 → #27 0x00007fffe9722c0b in nsWindow::OnExposeEvent (this=<optimized out>, cr=<optimized out>, this=<optimized out>) at /usr/src/debug/firefox-59.0-0.6.fc27.x86_64/widget/gtk/nsWindow.cpp:2089 #28 0x00007fffe97239b2 in draw_window_of_widget (widget=widget@entry=0x7fffaa3319b0, aWindow=0x7fffab257760, cr=cr@entry=0x7fffc9d42800) at /usr/src/debug/firefox-59.0-0.6.fc27.x86_64/widget/gtk/nsWindow.cpp:5455 #29 0x00007fffe9723a0f in expose_event_cb (widget=widget@entry=0x7fffaa3319b0, cr=0x7fffc9d42800) at /usr/src/debug/firefox-59.0-0.6.fc27.x86_64/widget/gtk/nsWindow.cpp:5478 #30 0x00007ffff481db4b in _gtk_marshal_BOOLEAN__BOXED (closure=closure@entry=0x7fffaa3fef80, return_value=return_value@entry=0x7fffffffaf20, n_param_values=n_param_values@entry=2, param_values=param_values@entry=0x7fffffffafd0, invocation_hint=invocation_hint@entry=0x7fffffffaf70, marshal_data=marshal_data@entry=0x0) at gtkmarshalers.c:83 #31 0x00007ffff495949f in gtk_widget_draw_marshaller (closure=0x7fffaa3fef80, return_value=0x7fffffffaf20, n_param_values=2, param_values=0x7fffffffafd0, invocation_hint=0x7fffffffaf70, marshal_data=0x0) at /home/ofourdan/src/gnome/gtk+-3/gtk/gtkwidget.c:945 #32 0x00007fffefcd568d in g_closure_invoke (closure=0x7fffaa3fef80, return_value=0x7fffffffaf20, n_param_values=2, param_values=0x7fffffffafd0, invocation_hint=0x7fffffffaf70) at /home/ofourdan/src/gnome/glib/gobject/gclosure.c:804 #33 0x00007fffefce86be in signal_emit_unlocked_R (node=<optimized out>, detail=detail@entry=0, instance=instance@entry=0x7fffaa3319b0, emission_return=emission_return@entry=0x7fffffffb0d0, instance_and_params=instance_and_params@entry=0x7fffffffafd0) at /home/ofourdan/src/gnome/glib/gobject/gsignal.c:3635 #34 0x00007fffefcf091c in g_signal_emit_valist (instance=<optimized out>, signal_id=<optimized out>, detail=<optimized out>, var_args=var_args@entry=0x7fffffffb188) at /home/ofourdan/src/gnome/glib/gobject/gsignal.c:3401 #35 0x00007fffefcf1802 in g_signal_emit (instance=instance@entry=0x7fffaa3319b0, signal_id=<optimized out>, detail=detail@entry=0) at /home/ofourdan/src/gnome/glib/gobject/gsignal.c:3447 #36 0x00007ffff4965ab2 in gtk_widget_draw_internal (widget=widget@entry=0x7fffaa3319b0, cr=cr@entry=0x7fffc9d42800, clip_to_size=clip_to_size@entry=1) at /home/ofourdan/src/gnome/gtk+-3/gtk/gtkwidget.c:7019 #37 0x00007ffff475c202 in gtk_container_propagate_draw (container=container@entry=0x7fffaa908a60, child=0x7fffaa3319b0, cr=cr@entry=0x7fffc9d42800) at /home/ofourdan/src/gnome/gtk+-3/gtk/gtkcontainer.c:3838 #38 0x00007ffff475c2c2 in gtk_container_draw (widget=0x7fffaa908a60, cr=0x7fffc9d42800) at /home/ofourdan/src/gnome/gtk+-3/gtk/gtkcontainer.c:3658 #39 0x00007ffff4972dff in gtk_window_draw (widget=0x7fffaa908a60, cr=0x7fffc9d42800) at /home/ofourdan/src/gnome/gtk+-3/gtk/gtkwindow.c:10401 #40 0x00007ffff496586f in gtk_widget_draw_internal (widget=0x7fffaa908a60, cr=0x7fffc9d42800, clip_to_size=<optimized out>) at /home/ofourdan/src/gnome/gtk+-3/gtk/gtkwidget.c:7026 #41 0x00007ffff496e763 in gtk_widget_render (widget=widget@entry=0x7fffaa908a60, window=0x7fffab2575d0, region=<optimized out>) at /home/ofourdan/src/gnome/gtk+-3/gtk/gtkwidget.c:17536 #42 0x00007ffff481cac1 in gtk_main_do_event (event=<optimized out>) at /home/ofourdan/src/gnome/gtk+-3/gtk/gtkmain.c:1838 #43 0x00007ffff433d565 in _gdk_event_emit (event=event@entry=0x7fffffffb520) at /home/ofourdan/src/gnome/gtk+-3/gdk/gdkevents.c:73 → #44 0x00007ffff434da8e in _gdk_window_process_updates_recurse_helper (window=0x7fffab2575d0, expose_region=<optimized out>) at /home/ofourdan/src/gnome/gtk+-3/gdk/gdkwindow.c:3858 → #45 0x00007ffff434e670 in _gdk_window_process_updates_recurse (window=<optimized out>, expose_region=<optimized out>) at /home/ofourdan/src/gnome/gtk+-3/gdk/gdkwindow.c:3917 #46 0x00007ffff434e426 in gdk_window_process_updates_internal (window=0x7fffab2575d0) at /home/ofourdan/src/gnome/gtk+-3/gdk/gdkwindow.c:4007 #47 0x00007ffff434e620 in gdk_window_process_updates_with_mode (window=<optimized out>, recurse_mode=<optimized out>) at /home/ofourdan/src/gnome/gtk+-3/gdk/gdkwindow.c:4201 #48 0x00007fffefcd568d in g_closure_invoke (closure=0x7fffaa3fe620, return_value=0x0, n_param_values=1, param_values=0x7fffffffb800, invocation_hint=0x7fffffffb7a0) at /home/ofourdan/src/gnome/glib/gobject/gclosure.c:804 #49 0x00007fffefce86be in signal_emit_unlocked_R (node=node@entry=0x7ffff6aca9a0, detail=detail@entry=0, instance=instance@entry=0x7fffaa380ed0, emission_return=emission_return@entry=0x0, instance_and_params=instance_and_params@entry=0x7fffffffb800) at /home/ofourdan/src/gnome/glib/gobject/gsignal.c:3635 #50 0x00007fffefcf0f35 in g_signal_emit_valist (instance=<optimized out>, signal_id=<optimized out>, detail=<optimized out>, var_args=var_args@entry=0x7fffffffb9a8) at /home/ofourdan/src/gnome/glib/gobject/gsignal.c:3391 #51 0x00007fffefcf1802 in g_signal_emit (instance=instance@entry=0x7fffaa380ed0, signal_id=<optimized out>, detail=detail@entry=0) at /home/ofourdan/src/gnome/glib/gobject/gsignal.c:3447 #52 0x00007ffff4345f1f in _gdk_frame_clock_emit_paint (frame_clock=frame_clock@entry=0x7fffaa380ed0) at /home/ofourdan/src/gnome/gtk+-3/gdk/gdkframeclock.c:640 #53 0x00007ffff4346621 in gdk_frame_clock_paint_idle (data=0x7fffaa380ed0) at /home/ofourdan/src/gnome/gtk+-3/gdk/gdkframeclockidle.c:430 #54 0x00007ffff4332140 in gdk_threads_dispatch (data=data@entry=0x7fffafdcb640) at /home/ofourdan/src/gnome/gtk+-3/gdk/gdk.c:743 #55 0x00007fffef7f535d in g_timeout_dispatch (source=0x7fffb58bb4a0, callback=0x7ffff4332120 <gdk_threads_dispatch>, user_data=0x7fffafdcb640) at /home/ofourdan/src/gnome/glib/glib/gmain.c:4650 #56 0x00007fffef7f4937 in g_main_dispatch (context=0x7ffff6a25be0) at /home/ofourdan/src/gnome/glib/glib/gmain.c:3177 #57 g_main_context_dispatch (context=context@entry=0x7ffff6a25be0) at /home/ofourdan/src/gnome/glib/glib/gmain.c:3830 #58 0x00007fffef7f4ca8 in g_main_context_iterate (context=context@entry=0x7ffff6a25be0, block=block@entry=0, dispatch=dispatch@entry=1, self=<optimized out>) at /home/ofourdan/src/gnome/glib/glib/gmain.c:3903 #59 0x00007fffef7f4d2c in g_main_context_iteration (context=0x7ffff6a25be0, context@entry=0x0, may_block=0) at /home/ofourdan/src/gnome/glib/glib/gmain.c:3964 #60 0x00007fffe9732d3f in nsAppShell::ProcessNextNativeEvent (this=<optimized out>, mayWait=<optimized out>) at /usr/src/debug/firefox-59.0-0.6.fc27.x86_64/widget/gtk/nsAppShell.cpp:295 ---Type <return> to continue, or q <return> to quit--- #61 0x00007fffe96ffb42 in nsBaseAppShell::DoProcessNextNativeEvent (this=this@entry=0x7fffd2b84040, mayWait=mayWait@entry=false) at /usr/src/debug/firefox-59.0-0.6.fc27.x86_64/widget/nsBaseAppShell.cpp:139 #62 0x00007fffe96ffd7c in nsBaseAppShell::OnProcessNextEvent (this=0x7fffd2b84040, thr=0x7fffdc21c480, mayWait=<optimized out>) at /usr/src/debug/firefox-59.0-0.6.fc27.x86_64/widget/nsBaseAppShell.cpp:272 #63 0x00007fffe7746525 in nsThread::ProcessNextEvent (this=<optimized out>, aMayWait=<optimized out>, aResult=0x7fffffffbda7, this=<optimized out>) at /usr/src/debug/firefox-59.0-0.6.fc27.x86_64/xpcom/threads/nsThread.cpp:952 #64 0x00007fffe774f6d8 in NS_ProcessNextEvent (aThread=<optimized out>, aThread@entry=0x7fffdc21c480, aMayWait=aMayWait@entry=false) at /usr/src/debug/firefox-59.0-0.6.fc27.x86_64/xpcom/threads/nsThreadUtils.cpp:517 #65 0x00007fffe7b7859a in mozilla::ipc::MessagePump::Run (this=0x7fffdc2550c0, aDelegate=0x7fffdc254040) at /usr/src/debug/firefox-59.0-0.6.fc27.x86_64/ipc/glue/MessagePump.cpp:97 #66 0x00007fffe7b4de20 in MessageLoop::RunInternal (this=<optimized out>) at /usr/src/debug/firefox-59.0-0.6.fc27.x86_64/ipc/chromium/src/base/message_loop.cc:326 #67 MessageLoop::RunHandler (this=<optimized out>) at /usr/src/debug/firefox-59.0-0.6.fc27.x86_64/ipc/chromium/src/base/message_loop.cc:319 #68 MessageLoop::Run (this=<optimized out>) at /usr/src/debug/firefox-59.0-0.6.fc27.x86_64/ipc/chromium/src/base/message_loop.cc:299 #69 0x00007fffe96fad38 in nsBaseAppShell::Run (this=0x7fffd2b84040) at /usr/src/debug/firefox-59.0-0.6.fc27.x86_64/widget/nsBaseAppShell.cpp:157 #70 0x00007fffea5cdd2e in nsAppStartup::Run (this=0x7fffd351eb50) at /usr/src/debug/firefox-59.0-0.6.fc27.x86_64/toolkit/components/startup/nsAppStartup.cpp:288 #71 0x00007fffea666c3b in XREMain::XRE_mainRun (this=this@entry=0x7fffffffc030) at /usr/src/debug/firefox-59.0-0.6.fc27.x86_64/toolkit/xre/nsAppRunner.cpp:4710 #72 0x00007fffea667ae6 in XREMain::XRE_main (this=this@entry=0x7fffffffc030, argc=argc@entry=1, argv=argv@entry=0x7fffffffd358, aConfig=...) at /usr/src/debug/firefox-59.0-0.6.fc27.x86_64/toolkit/xre/nsAppRunner.cpp:4849 #73 0x00007fffea667e52 in XRE_main (argc=1, argv=0x7fffffffd358, aConfig=...) at /usr/src/debug/firefox-59.0-0.6.fc27.x86_64/toolkit/xre/nsAppRunner.cpp:4941 #74 0x0000555555559d1c in do_main (argc=1, argv=0x7fffffffd358, envp=<optimized out>) at /usr/src/debug/firefox-59.0-0.6.fc27.x86_64/browser/app/nsBrowserApp.cpp:231 #75 0x0000555555559489 in main (argc=1, argv=0x7fffffffd358, envp=0x7fffffffd368) at /usr/src/debug/firefox-59.0-0.6.fc27.x86_64/browser/app/nsBrowserApp.cpp:304 (gdb) info threads What this shows is that Firefox is unmapping the window on expose events (step #27), and an expose event is precisely what's emitted to update the content. So basically, Firefox is unmapping the window while we're updating it, which leads to the crash.
Olivier, thanks for looking at it.
Created attachment 368558 [details] [review] [PATCH] gdkwindow: Don't paint if the window is unmapped I don't know if unmapping a toplevel window on expose events is legit or not (I would leave that to gtk+ devs to decide), but in case it's deemed as legit, the attached patch would avoid the crash.
(In reply to Olivier Fourdan from comment #26) > Created attachment 368558 [details] [review] [review] > [PATCH] gdkwindow: Don't paint if the window is unmapped > > I don't know if unmapping a toplevel window on expose events is legit or not > (I would leave that to gtk+ devs to decide), but in case it's deemed as > legit, the attached patch would avoid the crash. Would be great to have the patch checked-in. A fix at Firefox side would need to rework complete popup window management.
In that case it would be better to fix the issue in the Wayland backend, I reckon, as this is less likely to break other backends. At least we now know exactly what happens and why it crashes.
Created attachment 368612 [details] [review] [PATCH] wayland: Don't paint if the window is unmapped This patch is better, IMHO, it checks for the window being mapped in the gdkwayland backend where it actually matters (because on Wayland, the surface and other resources are released when unmapped), so we don't interfere with the regular gdk update processing (and thus we avoid gdk warnings about paint operations already in progress).
I've filed two MR (gtk3 and gtk4) for this here: gtk3: https://gitlab.gnome.org/GNOME/gtk/merge_requests/31 gtk4: https://gitlab.gnome.org/GNOME/gtk/merge_requests/32
Both branches have now been merged in gitlab (thanks Matthias!), closing.