crash when restarting X11 session
When gnome-shell is restarted in an X11 session, it crashes:
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x00007fc85c488e07 in _XSend (dpy=0x55ff68f57290, data=0x7fc859e8e088 "SYNC", size=4) at /usr/src/debug/libx11/libX11-1.8.5/src/xcb_io.c:548
548 xcb_connection_t *c = dpy->xcb->connection;
[Current thread is 1 (Thread 0x7fc858907d40 (LWP 826922))]
(gdb) p dpy->xcb
$1 = (struct _X11XCBPrivate *) 0x0
(gdb) bt
#0 0x00007fc85c488e07 in _XSend (dpy=0x55ff68f57290, data=0x7fc859e8e088 "SYNC", size=4) at /usr/src/debug/libx11/libX11-1.8.5/src/xcb_io.c:548
#1 0x00007fc85c4817c9 in XQueryExtension
(dpy=dpy@entry=0x55ff68f57290, name=name@entry=0x7fc859e8e088 "SYNC", major_opcode=major_opcode@entry=0x7ffc0d0913b4, first_event=first_event@entry=0x7ffc0d0913b8, first_error=first_error@entry=0x7ffc0d0913bc) at /usr/src/debug/libx11/libX11-1.8.5/src/QuExt.c:52
#2 0x00007fc859e85e17 in GetVersionInfo (dpy=0x55ff68f57290) at /build/libxext/src/libXext-1.3.5/src/XSync.c:122
#3 find_display_create_optional (create=<optimized out>, dpy=0x55ff68f57290) at /build/libxext/src/libXext-1.3.5/src/XSync.c:167
#4 find_display_create_optional (dpy=dpy@entry=0x55ff68f57290, create=create@entry=1) at /build/libxext/src/libXext-1.3.5/src/XSync.c:154
#5 0x00007fc859e8bf28 in find_display (dpy=0x55ff68f57290) at /build/libxext/src/libXext-1.3.5/src/XSync.c:176
#6 XSyncTriggerFence (dpy=0x55ff68f57290, fence=4194313) at /build/libxext/src/libXext-1.3.5/src/XSync.c:809
#7 0x00007fc85cb00c24 in meta_sync_free (self=0x55ff68f843d0) at ../../../../src/mutter/src/compositor/meta-sync-ring.c:392
#8 0x00007fc85cb00fe0 in meta_sync_ring_destroy () at ../../../../src/mutter/src/compositor/meta-sync-ring.c:470
#9 0x00007fc85caffa24 in meta_compositor_x11_dispose (object=0x55ff68f51770) at ../../../../src/mutter/src/compositor/meta-compositor-x11.c:524
#10 0x00007fc85d5a8900 in g_object_run_dispose (object=0x55ff68f51770) at ../glib/gobject/gobject.c:1448
#11 g_object_run_dispose (object=0x55ff68f51770) at ../glib/gobject/gobject.c:1441
#12 0x00007fc85caa1248 in meta_compositor_destroy (compositor=0x55ff68f51770) at ../../../../src/mutter/src/compositor/compositor.c:202
#13 0x00007fc85cac047c in meta_display_close (display=0x55ff68f40790, timestamp=<optimized out>) at ../../../../src/mutter/src/core/display.c:1191
#14 0x00007fc85d228fd3 in shell_global_reexec_self (global=0x55ff68be6e50) at ../gnome-shell/src/shell-global.c:902
[...]
I think the reason is that meta_display_shutdown_x11()
is called before meta_compositor_destroy()
(since 342c9407), which closes the X11 display, but the meta sync ring still has a (now dangling) pointer to it, and it tries to use it when meta_compositor_destroy()
calls meta_sync_ring_destroy()
which then calls meta_sync_free()
which in turn might use the dangling pointer.
So as far as I can tell the problematic part is here:
meta_display_shutdown_x11 (display);
g_clear_object (&display->stack);
g_clear_pointer (&display->stack_tracker,
meta_stack_tracker_free);
g_clear_pointer (&display->compositor, meta_compositor_destroy);
But there does not seem to be a good ordering... because
-
meta_compositor_destroy()
must precedemeta_display_shutdown_x11()
(due to the sync ring using the X11 display); -
meta_display_shutdown_x11()
must precedeg_clear_object (&display->stack)
(because it callsmeta_stack_{freeze,thaw}()
); -
g_clear_object (&display->stack)
must precedemeta_stack_tracker_free()
becausestack.c:on_stack_changed()
calls into the stack tracker; -
meta_stack_tracker_free()
must be precedemeta_compositor_destroy()
because it retrieves the MetaLaters from the compositor object.
The following change seems to work:
diff --git a/src/core/display.c b/src/core/display.c
index 054b388bc..f587c0339 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -1182,13 +1182,13 @@ meta_display_close (MetaDisplay *display,
/* Stop caring about events */
meta_display_free_events (display);
- meta_display_shutdown_x11 (display);
-
- g_clear_object (&display->stack);
g_clear_pointer (&display->stack_tracker,
meta_stack_tracker_free);
g_clear_pointer (&display->compositor, meta_compositor_destroy);
+ meta_display_shutdown_x11 (display);
+
+ g_clear_object (&display->stack);
/* Must be after all calls to meta_window_unmanage() since they
* unregister windows
diff --git a/src/core/stack.c b/src/core/stack.c
index a91dca18d..73542a462 100644
--- a/src/core/stack.c
+++ b/src/core/stack.c
@@ -80,6 +80,9 @@ on_stack_changed (MetaStack *stack)
GArray *hidden_stack_ids;
GList *sorted;
+ if (!display->stack_tracker)
+ return;
+
COGL_TRACE_BEGIN_SCOPED (StackChanged, "Stack changed");
meta_topic (META_DEBUG_STACK, "Syncing window stack to server");
But I am wondering if it might be better if the MetaStackTracker
constructor received a reference to the MetaStack
and connected the "changed" event handler on the stack instead of the stack itself, that way it could easily disconnect it when it is being destroyed.