[server] Fix possible crash on creation of DataDevice
Summary: This is a similar condition as D3148. If a DataDeviceInterface is created for the currently focused keyboard Surface the current selection is sent to the new DataDeviceInterface. If the current selection does not have a DataSourceInterface a DataOfferInterface for a null DataSourceInterface would be created and result in a crash. This change verifies that there is a DataSourcInterface on the current selection prior to sending out the selection. Test Plan: A test case is added which simulates the condition by using two clients. Reviewers: #plasma_on_wayland Subscribers: plasma-devel Tags: #plasma_on_wayland Differential Revision: https://phabricator.kde.org/D3149
This commit is contained in:
parent
988a239637
commit
be04b54827
2 changed files with 95 additions and 1 deletions
|
@ -80,6 +80,7 @@ private Q_SLOTS:
|
|||
void testDestroy();
|
||||
void testSelection();
|
||||
void testSelectionNoDataSource();
|
||||
void testDataDeviceForKeyboardSurface();
|
||||
void testTouch();
|
||||
void testDisconnect();
|
||||
void testPointerEnterOnUnboundSurface();
|
||||
|
@ -1598,6 +1599,99 @@ void TestWaylandSeat::testSelectionNoDataSource()
|
|||
m_seatInterface->setSelection(ddi);
|
||||
}
|
||||
|
||||
void TestWaylandSeat::testDataDeviceForKeyboardSurface()
|
||||
{
|
||||
// this test verifies that the server does not crash when creating a datadevice for the focused keyboard surface
|
||||
// and the currentSelection does not have a DataSource.
|
||||
// to properly test the functionality this test requires a second client
|
||||
using namespace KWayland::Client;
|
||||
using namespace KWayland::Server;
|
||||
// create the DataDeviceManager
|
||||
QScopedPointer<DataDeviceManagerInterface> ddmi(m_display->createDataDeviceManager());
|
||||
ddmi->create();
|
||||
QSignalSpy ddiCreatedSpy(ddmi.data(), &DataDeviceManagerInterface::dataDeviceCreated);
|
||||
QVERIFY(ddiCreatedSpy.isValid());
|
||||
|
||||
// create a second Wayland client connection to use it for setSelection
|
||||
auto c = new ConnectionThread;
|
||||
QSignalSpy connectedSpy(c, &ConnectionThread::connected);
|
||||
QVERIFY(connectedSpy.isValid());
|
||||
c->setSocketName(s_socketName);
|
||||
|
||||
auto thread = new QThread(this);
|
||||
c->moveToThread(thread);
|
||||
thread->start();
|
||||
|
||||
c->initConnection();
|
||||
QVERIFY(connectedSpy.wait());
|
||||
|
||||
QScopedPointer<EventQueue> queue(new EventQueue);
|
||||
queue->setup(c);
|
||||
|
||||
QScopedPointer<Registry> registry(new Registry);
|
||||
QSignalSpy interfacesAnnouncedSpy(registry.data(), &Registry::interfacesAnnounced);
|
||||
QVERIFY(interfacesAnnouncedSpy.isValid());
|
||||
registry->setEventQueue(queue.data());
|
||||
registry->create(c);
|
||||
QVERIFY(registry->isValid());
|
||||
registry->setup();
|
||||
|
||||
QVERIFY(interfacesAnnouncedSpy.wait());
|
||||
QScopedPointer<Seat> seat(registry->createSeat(registry->interface(Registry::Interface::Seat).name,
|
||||
registry->interface(Registry::Interface::Seat).version));
|
||||
QVERIFY(seat->isValid());
|
||||
QScopedPointer<DataDeviceManager> ddm1(registry->createDataDeviceManager(registry->interface(Registry::Interface::DataDeviceManager).name,
|
||||
registry->interface(Registry::Interface::DataDeviceManager).version));
|
||||
QVERIFY(ddm1->isValid());
|
||||
|
||||
// now create our first datadevice
|
||||
QScopedPointer<DataDevice> dd1(ddm1->getDataDevice(seat.data()));
|
||||
QVERIFY(ddiCreatedSpy.wait());
|
||||
auto ddi = ddiCreatedSpy.first().first().value<DataDeviceInterface*>();
|
||||
QVERIFY(ddi);
|
||||
m_seatInterface->setSelection(ddi);
|
||||
|
||||
// switch to other client
|
||||
// create a surface and pass it keyboard focus
|
||||
QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated);
|
||||
QVERIFY(surfaceCreatedSpy.isValid());
|
||||
QScopedPointer<Surface> surface(m_compositor->createSurface());
|
||||
QVERIFY(surface->isValid());
|
||||
QVERIFY(surfaceCreatedSpy.wait());
|
||||
auto serverSurface = surfaceCreatedSpy.first().first().value<SurfaceInterface*>();
|
||||
m_seatInterface->setFocusedKeyboardSurface(serverSurface);
|
||||
QCOMPARE(m_seatInterface->focusedKeyboardSurface(), serverSurface);
|
||||
|
||||
// now create a DataDevice
|
||||
Registry registry2;
|
||||
QSignalSpy dataDeviceManagerSpy(®istry2, &Registry::dataDeviceManagerAnnounced);
|
||||
QVERIFY(dataDeviceManagerSpy.isValid());
|
||||
registry2.setEventQueue(m_queue);
|
||||
registry2.create(m_connection->display());
|
||||
QVERIFY(registry2.isValid());
|
||||
registry2.setup();
|
||||
|
||||
QVERIFY(dataDeviceManagerSpy.wait());
|
||||
QScopedPointer<DataDeviceManager> ddm(registry2.createDataDeviceManager(dataDeviceManagerSpy.first().first().value<quint32>(),
|
||||
dataDeviceManagerSpy.first().last().value<quint32>()));
|
||||
QVERIFY(ddm->isValid());
|
||||
|
||||
QScopedPointer<DataDevice> dd(ddm->getDataDevice(m_seat));
|
||||
QVERIFY(dd->isValid());
|
||||
QVERIFY(ddiCreatedSpy.wait());
|
||||
|
||||
// and delete the connection thread again
|
||||
dd1.reset();
|
||||
ddm1.reset();
|
||||
seat.reset();
|
||||
registry.reset();
|
||||
queue.reset();
|
||||
c->deleteLater();
|
||||
thread->quit();
|
||||
thread->wait();
|
||||
delete thread;
|
||||
}
|
||||
|
||||
void TestWaylandSeat::testTouch()
|
||||
{
|
||||
using namespace KWayland::Client;
|
||||
|
|
|
@ -292,7 +292,7 @@ void SeatInterface::Private::registerDataDevice(DataDeviceInterface *dataDevice)
|
|||
// same client?
|
||||
if (keys.focus.surface->client() == dataDevice->client()) {
|
||||
keys.focus.selection = dataDevice;
|
||||
if (currentSelection) {
|
||||
if (currentSelection && currentSelection->selection()) {
|
||||
dataDevice->sendSelection(currentSelection);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue