Don't crash if the cursor theme fails to create
Summary: If the cursor theme failed to create KWin crashed due to an endless recursion. There are two reasons for this fault: 1) When the physical size does not exist we perform a division by 0 which results in an invalid size going into wl_cursor_theme_load 2) We emit the signal that the cursor theme changed even if it didn't change thus creating an endless recursion This change addresses both problems: it checks that the size is not 0 and changes the handling for theme update to only destroy the previous theme if the new theme could be created and only emits the signal if things change. BUG: 390314 FIXED-IN: 5.12.3 Test Plan: Added a new test case which crashed with old code Reviewers: #kwin, #plasma Subscribers: plasma-devel, kwin Tags: #plasma Differential Revision: https://phabricator.kde.org/D10549
This commit is contained in:
parent
b554e54e87
commit
2ea5153e1c
3 changed files with 142 additions and 9 deletions
|
@ -55,6 +55,7 @@ integrationTest(WAYLAND_ONLY NAME testVirtualDesktop SRCS virtual_desktop_test.c
|
||||||
integrationTest(WAYLAND_ONLY NAME testShellClientRules SRCS shell_client_rules_test.cpp)
|
integrationTest(WAYLAND_ONLY NAME testShellClientRules SRCS shell_client_rules_test.cpp)
|
||||||
integrationTest(WAYLAND_ONLY NAME testIdleInhibition SRCS idle_inhibition_test.cpp)
|
integrationTest(WAYLAND_ONLY NAME testIdleInhibition SRCS idle_inhibition_test.cpp)
|
||||||
integrationTest(WAYLAND_ONLY NAME testColorCorrectNightColor SRCS colorcorrect_nightcolor_test.cpp)
|
integrationTest(WAYLAND_ONLY NAME testColorCorrectNightColor SRCS colorcorrect_nightcolor_test.cpp)
|
||||||
|
integrationTest(WAYLAND_ONLY NAME testDontCrashCursorPhysicalSizeEmpty SRCS dont_crash_cursor_physical_size_empty.cpp)
|
||||||
|
|
||||||
if (XCB_ICCCM_FOUND)
|
if (XCB_ICCCM_FOUND)
|
||||||
integrationTest(NAME testMoveResize SRCS move_resize_window_test.cpp LIBS XCB::ICCCM)
|
integrationTest(NAME testMoveResize SRCS move_resize_window_test.cpp LIBS XCB::ICCCM)
|
||||||
|
|
124
autotests/integration/dont_crash_cursor_physical_size_empty.cpp
Normal file
124
autotests/integration/dont_crash_cursor_physical_size_empty.cpp
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
/********************************************************************
|
||||||
|
KWin - the KDE window manager
|
||||||
|
This file is part of the KDE project.
|
||||||
|
|
||||||
|
Copyright (C) 2018 Martin Flöser <mgraesslin@kde.org>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*********************************************************************/
|
||||||
|
#include "kwin_wayland_test.h"
|
||||||
|
#include "composite.h"
|
||||||
|
#include "effectloader.h"
|
||||||
|
#include "client.h"
|
||||||
|
#include "cursor.h"
|
||||||
|
#include "effects.h"
|
||||||
|
#include "platform.h"
|
||||||
|
#include "shell_client.h"
|
||||||
|
#include "screens.h"
|
||||||
|
#include "wayland_server.h"
|
||||||
|
#include "workspace.h"
|
||||||
|
|
||||||
|
#include <KConfigGroup>
|
||||||
|
|
||||||
|
#include <KWayland/Client/seat.h>
|
||||||
|
#include <KWayland/Client/server_decoration.h>
|
||||||
|
#include <KWayland/Client/xdgshell.h>
|
||||||
|
#include <KWayland/Client/surface.h>
|
||||||
|
#include <KWayland/Server/display.h>
|
||||||
|
#include <KWayland/Server/output_interface.h>
|
||||||
|
|
||||||
|
using namespace KWin;
|
||||||
|
using namespace KWayland::Client;
|
||||||
|
static const QString s_socketName = QStringLiteral("wayland_test_kwin_crash_cursor_physical_size_empty-0");
|
||||||
|
|
||||||
|
class DontCrashCursorPhysicalSizeEmpty : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private Q_SLOTS:
|
||||||
|
void init();
|
||||||
|
void initTestCase();
|
||||||
|
void cleanup();
|
||||||
|
void testMoveCursorOverDeco_data();
|
||||||
|
void testMoveCursorOverDeco();
|
||||||
|
};
|
||||||
|
|
||||||
|
void DontCrashCursorPhysicalSizeEmpty::init()
|
||||||
|
{
|
||||||
|
QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Decoration));
|
||||||
|
|
||||||
|
screens()->setCurrent(0);
|
||||||
|
KWin::Cursor::setPos(QPoint(640, 512));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DontCrashCursorPhysicalSizeEmpty::cleanup()
|
||||||
|
{
|
||||||
|
Test::destroyWaylandConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DontCrashCursorPhysicalSizeEmpty::initTestCase()
|
||||||
|
{
|
||||||
|
qRegisterMetaType<KWin::ShellClient*>();
|
||||||
|
qRegisterMetaType<KWin::AbstractClient*>();
|
||||||
|
QSignalSpy workspaceCreatedSpy(kwinApp(), &Application::workspaceCreated);
|
||||||
|
QVERIFY(workspaceCreatedSpy.isValid());
|
||||||
|
kwinApp()->platform()->setInitialWindowSize(QSize(1280, 1024));
|
||||||
|
QVERIFY(waylandServer()->init(s_socketName.toLocal8Bit()));
|
||||||
|
|
||||||
|
if (!QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("icons/DMZ-White/index.theme")).isEmpty()) {
|
||||||
|
qputenv("XCURSOR_THEME", QByteArrayLiteral("DMZ-White"));
|
||||||
|
} else {
|
||||||
|
// might be vanilla-dmz (e.g. Arch, FreeBSD)
|
||||||
|
qputenv("XCURSOR_THEME", QByteArrayLiteral("Vanilla-DMZ"));
|
||||||
|
}
|
||||||
|
qputenv("XCURSOR_SIZE", QByteArrayLiteral("0"));
|
||||||
|
|
||||||
|
kwinApp()->start();
|
||||||
|
QVERIFY(workspaceCreatedSpy.wait());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DontCrashCursorPhysicalSizeEmpty::testMoveCursorOverDeco_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn<Test::ShellSurfaceType>("type");
|
||||||
|
|
||||||
|
QTest::newRow("wlShell") << Test::ShellSurfaceType::WlShell;
|
||||||
|
QTest::newRow("xdgShellV5") << Test::ShellSurfaceType::XdgShellV5;
|
||||||
|
QTest::newRow("xdgShellV6") << Test::ShellSurfaceType::XdgShellV6;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DontCrashCursorPhysicalSizeEmpty::testMoveCursorOverDeco()
|
||||||
|
{
|
||||||
|
// This test ensures that there is no endless recursion if the cursor theme cannot be created
|
||||||
|
// a reason for creation failure could be physical size not existing
|
||||||
|
// see BUG: 390314
|
||||||
|
QScopedPointer<Surface> surface(Test::createSurface());
|
||||||
|
QFETCH(Test::ShellSurfaceType, type);
|
||||||
|
Test::waylandServerSideDecoration()->create(surface.data(), surface.data());
|
||||||
|
QScopedPointer<QObject> shellSurface(Test::createShellSurface(type, surface.data()));
|
||||||
|
|
||||||
|
auto c = Test::renderAndWaitForShown(surface.data(), QSize(100, 50), Qt::blue);
|
||||||
|
QVERIFY(c);
|
||||||
|
QVERIFY(c->isDecorated());
|
||||||
|
|
||||||
|
// destroy physical size
|
||||||
|
KWayland::Server::Display *display = waylandServer()->display();
|
||||||
|
auto output = display->outputs().first();
|
||||||
|
output->setPhysicalSize(QSize(0, 0));
|
||||||
|
// and fake a cursor theme change, so that the theme gets recreated
|
||||||
|
emit KWin::Cursor::self()->themeChanged();
|
||||||
|
|
||||||
|
KWin::Cursor::setPos(QPoint(c->geometry().center().x(), c->clientPos().y() / 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
WAYLANDTEST_MAIN(DontCrashCursorPhysicalSizeEmpty)
|
||||||
|
#include "dont_crash_cursor_physical_size_empty.moc"
|
|
@ -50,12 +50,6 @@ void WaylandCursorTheme::loadTheme()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Cursor *c = Cursor::self();
|
Cursor *c = Cursor::self();
|
||||||
if (!m_theme) {
|
|
||||||
// so far the theme had not been created, this means we need to start tracking theme changes
|
|
||||||
connect(c, &Cursor::themeChanged, this, &WaylandCursorTheme::loadTheme);
|
|
||||||
} else {
|
|
||||||
destroyTheme();
|
|
||||||
}
|
|
||||||
int size = c->themeSize();
|
int size = c->themeSize();
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
// resolution depended
|
// resolution depended
|
||||||
|
@ -63,11 +57,25 @@ void WaylandCursorTheme::loadTheme()
|
||||||
KWayland::Server::Display *display = waylandServer()->display();
|
KWayland::Server::Display *display = waylandServer()->display();
|
||||||
auto output = display->outputs().first();
|
auto output = display->outputs().first();
|
||||||
// calculate dots per inch, multiplied with magic constants from Cursor::loadThemeSettings()
|
// calculate dots per inch, multiplied with magic constants from Cursor::loadThemeSettings()
|
||||||
size = qreal(output->pixelSize().height()) / (qreal(output->physicalSize().height()) * 0.0393701) * 16.0 / 72.0;
|
if (output->physicalSize().height()) {
|
||||||
|
size = qreal(output->pixelSize().height()) / (qreal(output->physicalSize().height()) * 0.0393701) * 16.0 / 72.0;
|
||||||
|
} else {
|
||||||
|
// use sensible default
|
||||||
|
size = 24;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
m_theme = wl_cursor_theme_load(c->themeName().toUtf8().constData(),
|
auto theme = wl_cursor_theme_load(c->themeName().toUtf8().constData(),
|
||||||
size, m_shm->shm());
|
size, m_shm->shm());
|
||||||
emit themeChanged();
|
if (theme) {
|
||||||
|
if (!m_theme) {
|
||||||
|
// so far the theme had not been created, this means we need to start tracking theme changes
|
||||||
|
connect(c, &Cursor::themeChanged, this, &WaylandCursorTheme::loadTheme);
|
||||||
|
} else {
|
||||||
|
destroyTheme();
|
||||||
|
}
|
||||||
|
m_theme = theme;
|
||||||
|
emit themeChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaylandCursorTheme::destroyTheme()
|
void WaylandCursorTheme::destroyTheme()
|
||||||
|
|
Loading…
Reference in a new issue