xwayland: Avoid creating a tree query on crash

If Xwayland has crashed, the Workspace will block stacking order updates
and start destroying all X11 clients.

Once stacking order updates are unblocked, the Workspace will mark the X
stacking order as dirty and create a new Xcb::Tree object.

We don't want to create that Xcb::Tree object because accessing it
after the XCB connection has been shut down will lead to a crash.

BUG: 427688
FIXED-IN: 5.20.1


(cherry picked from commit 2093820aba)
icc-effect-5.20.5
Vlad Zahorodnii 2020-10-14 15:04:57 +00:00
parent 83ed25031c
commit 0109bdbba9
5 changed files with 30 additions and 1 deletions

View File

@ -5,8 +5,10 @@
*/
#include "kwin_wayland_test.h"
#include "composite.h"
#include "main.h"
#include "platform.h"
#include "scene.h"
#include "screens.h"
#include "unmanaged.h"
#include "wayland_server.h"
@ -124,6 +126,11 @@ void XwaylandServerCrashTest::testCrash()
QCOMPARE(kwinApp()->x11DefaultScreen(), nullptr);
QCOMPARE(kwinApp()->x11RootWindow(), XCB_WINDOW_NONE);
QCOMPARE(kwinApp()->x11ScreenNumber(), -1);
// Render a frame to ensure that the compositor doesn't crash.
Compositor::self()->addRepaintFull();
QSignalSpy frameRenderedSpy(Compositor::self()->scene(), &Scene::frameRendered);
QVERIFY(frameRenderedSpy.wait());
}
} // namespace KWin

View File

@ -5,8 +5,10 @@
*/
#include "kwin_wayland_test.h"
#include "composite.h"
#include "main.h"
#include "platform.h"
#include "scene.h"
#include "screens.h"
#include "wayland_server.h"
#include "workspace.h"
@ -103,6 +105,11 @@ void XwaylandServerRestartTest::testRestart()
QCOMPARE(client->windowId(), window);
QVERIFY(client->isDecorated());
// Render a frame to ensure that the compositor doesn't crash.
Compositor::self()->addRepaintFull();
QSignalSpy frameRenderedSpy(Compositor::self()->scene(), &Scene::frameRendered);
QVERIFY(frameRenderedSpy.wait());
// Destroy the test window.
xcb_destroy_window(c.data(), window);
xcb_flush(c.data());

11
main.h
View File

@ -158,6 +158,13 @@ public:
return m_defaultScreen;
}
/**
* Returns @c true if we're in the middle of destroying the X11 connection.
*/
bool isClosingX11Connection() const {
return m_isClosingX11Connection;
}
#ifdef KWIN_BUILD_ACTIVITIES
bool usesKActivities() const {
return m_useKActivities;
@ -233,6 +240,9 @@ protected:
void setTerminating() {
m_terminating = true;
}
void setClosingX11Connection(bool set) {
m_isClosingX11Connection = set;
}
protected:
static int crashes;
@ -255,6 +265,7 @@ private:
#endif
Platform *m_platform = nullptr;
bool m_terminating = false;
bool m_isClosingX11Connection = false;
};
inline static Application *kwinApp()

View File

@ -1788,7 +1788,7 @@ bool Workspace::compositing() const
void Workspace::markXStackingOrderAsDirty()
{
m_xStackingDirty = true;
if (kwinApp()->x11Connection()) {
if (kwinApp()->x11Connection() && !kwinApp()->isClosingX11Connection()) {
m_xStackingQueryTree.reset(new Xcb::Tree(kwinApp()->x11RootWindow()));
}
}

View File

@ -149,6 +149,8 @@ void Xwayland::stop()
return;
}
m_app->setClosingX11Connection(true);
// If Xwayland has crashed, we must deactivate the socket notifier and ensure that no X11
// events will be dispatched before blocking; otherwise we will simply hang...
uninstallSocketNotifier();
@ -169,6 +171,8 @@ void Xwayland::stop()
m_xwaylandProcess = nullptr;
waylandServer()->destroyXWaylandConnection(); // This one must be destroyed last!
m_app->setClosingX11Connection(false);
}
void Xwayland::restart()