simplify qtbase patch: validate-at-use instead of surface tracking

This commit is contained in:
Damocles 2026-04-20 19:32:39 +02:00
parent 6a8b38c73a
commit 92afaa7f32

View file

@ -1,162 +1,88 @@
diff --git a/src/plugins/platforms/wayland/qwaylanddisplay.cpp b/src/plugins/platforms/wayland/qwaylanddisplay.cpp diff --git a/src/plugins/platforms/wayland/qwaylanddisplay.cpp b/src/plugins/platforms/wayland/qwaylanddisplay.cpp
index 02169e77..43ab00fa 100644 index 02169e77..42d2aa0f 100644
--- a/src/plugins/platforms/wayland/qwaylanddisplay.cpp --- a/src/plugins/platforms/wayland/qwaylanddisplay.cpp
+++ b/src/plugins/platforms/wayland/qwaylanddisplay.cpp +++ b/src/plugins/platforms/wayland/qwaylanddisplay.cpp
@@ -423,8 +423,10 @@ void QWaylandDisplay::reconnect() @@ -603,6 +603,11 @@ QWaylandScreen *QWaylandDisplay::screenForOutput(struct wl_output *output) const
m_eventThread->wait();
m_frameEventQueueThread->wait();
- qDeleteAll(mWaitingScreens);
- mWaitingScreens.clear();
+ for (auto *screen : std::exchange(mWaitingScreens, {})) {
+ forgetScreenForSurfaces(screen);
+ delete screen;
+ }
while (!mScreens.isEmpty()) {
auto screen = mScreens.takeLast();
@@ -603,6 +605,27 @@ QWaylandScreen *QWaylandDisplay::screenForOutput(struct wl_output *output) const
return nullptr; return nullptr;
} }
+void QWaylandDisplay::registerSurface(QWaylandSurface *surface)
+{
+ mSurfaces.append(surface);
+}
+
+void QWaylandDisplay::unregisterSurface(QWaylandSurface *surface)
+{
+ mSurfaces.removeOne(surface);
+}
+
+bool QWaylandDisplay::isScreenAlive(QWaylandScreen *screen) const +bool QWaylandDisplay::isScreenAlive(QWaylandScreen *screen) const
+{ +{
+ return mScreens.contains(screen) || mWaitingScreens.contains(screen); + return mScreens.contains(screen) || mWaitingScreens.contains(screen);
+} +}
+
+void QWaylandDisplay::forgetScreenForSurfaces(QWaylandScreen *screen)
+{
+ for (auto *surface : std::as_const(mSurfaces))
+ surface->m_screens.removeAll(screen);
+}
+ +
void QWaylandDisplay::handleScreenInitialized(QWaylandScreen *screen) void QWaylandDisplay::handleScreenInitialized(QWaylandScreen *screen)
{ {
if (!mWaitingScreens.removeOne(screen)) if (!mWaitingScreens.removeOne(screen))
@@ -823,6 +846,7 @@ void QWaylandDisplay::registry_global_remove(uint32_t id)
for (auto *screen : mWaitingScreens) {
if (screen->outputId() == id) {
mWaitingScreens.removeOne(screen);
+ forgetScreenForSurfaces(screen);
delete screen;
break;
}
@@ -831,6 +855,7 @@ void QWaylandDisplay::registry_global_remove(uint32_t id)
for (QWaylandScreen *screen : std::as_const(mScreens)) {
if (screen->outputId() == id) {
mScreens.removeOne(screen);
+ forgetScreenForSurfaces(screen);
// If this is the last screen, we have to add a fake screen, or Qt will break.
ensureScreen();
QWindowSystemInterface::handleScreenRemoved(screen);
diff --git a/src/plugins/platforms/wayland/qwaylanddisplay_p.h b/src/plugins/platforms/wayland/qwaylanddisplay_p.h diff --git a/src/plugins/platforms/wayland/qwaylanddisplay_p.h b/src/plugins/platforms/wayland/qwaylanddisplay_p.h
index 29952886..88b57945 100644 index 29952886..379403ee 100644
--- a/src/plugins/platforms/wayland/qwaylanddisplay_p.h --- a/src/plugins/platforms/wayland/qwaylanddisplay_p.h
+++ b/src/plugins/platforms/wayland/qwaylanddisplay_p.h +++ b/src/plugins/platforms/wayland/qwaylanddisplay_p.h
@@ -116,6 +116,10 @@ public: @@ -116,6 +116,7 @@ public:
QPlatformPlaceholderScreen *placeholderScreen() const { return mPlaceholderScreen; } QPlatformPlaceholderScreen *placeholderScreen() const { return mPlaceholderScreen; }
void ensureScreen(); void ensureScreen();
+ void registerSurface(QWaylandSurface *surface);
+ void unregisterSurface(QWaylandSurface *surface);
+ bool isScreenAlive(QWaylandScreen *screen) const; + bool isScreenAlive(QWaylandScreen *screen) const;
+
QWaylandScreen *screenForOutput(struct wl_output *output) const; QWaylandScreen *screenForOutput(struct wl_output *output) const;
void handleScreenInitialized(QWaylandScreen *screen); void handleScreenInitialized(QWaylandScreen *screen);
@@ -289,6 +293,7 @@ private:
void checkWaylandError();
void reconnect();
void setupConnection();
+ void forgetScreenForSurfaces(QWaylandScreen *screen);
void handleWaylandSync();
void requestWaylandSync();
@@ -311,6 +316,7 @@ private:
QList<QWaylandScreen *> mScreens;
QPlatformPlaceholderScreen *mPlaceholderScreen = nullptr;
QList<QWaylandInputDevice *> mInputDevices;
+ QList<QWaylandSurface *> mSurfaces;
QList<Listener> mRegistryListeners;
QWaylandIntegration *mWaylandIntegration = nullptr;
#if QT_CONFIG(cursor)
diff --git a/src/plugins/platforms/wayland/qwaylandsurface.cpp b/src/plugins/platforms/wayland/qwaylandsurface.cpp diff --git a/src/plugins/platforms/wayland/qwaylandsurface.cpp b/src/plugins/platforms/wayland/qwaylandsurface.cpp
index 274fdda8..a881b9d1 100644 index 274fdda8..f630cec3 100644
--- a/src/plugins/platforms/wayland/qwaylandsurface.cpp --- a/src/plugins/platforms/wayland/qwaylandsurface.cpp
+++ b/src/plugins/platforms/wayland/qwaylandsurface.cpp +++ b/src/plugins/platforms/wayland/qwaylandsurface.cpp
@@ -13,18 +13,31 @@ namespace QtWaylandClient { @@ -13,6 +13,7 @@ namespace QtWaylandClient {
QWaylandSurface::QWaylandSurface(QWaylandDisplay *display) QWaylandSurface::QWaylandSurface(QWaylandDisplay *display)
: wl_surface(display->createSurface(this)) : wl_surface(display->createSurface(this))
+ , m_display(display) + , m_display(display)
{ {
+ display->registerSurface(this);
connect(qApp, &QGuiApplication::screenRemoved, this, &QWaylandSurface::handleScreenRemoved); connect(qApp, &QGuiApplication::screenRemoved, this, &QWaylandSurface::handleScreenRemoved);
connect(qApp, &QGuiApplication::screenAdded, this, &QWaylandSurface::screensChanged); connect(qApp, &QGuiApplication::screenAdded, this, &QWaylandSurface::screensChanged);
} @@ -25,6 +26,13 @@ QWaylandSurface::~QWaylandSurface()
QWaylandSurface::~QWaylandSurface()
{
+ m_display->unregisterSurface(this);
destroy();
}
QWaylandScreen *QWaylandSurface::oldestEnteredScreen() QWaylandScreen *QWaylandSurface::oldestEnteredScreen()
{ {
+ // Prune any screen pointers that the display no longer knows about. + // Prune stale screen pointers before iterating. Entries can go stale
+ // This guards against every possible stale-pointer path: waiting-screen + // when a wl_output is removed while a waiting-state QWaylandScreen
+ // deletion, signal-ordering gaps during ensureScreen(), and any future + // referencing it was in m_screens (direct deletion, no screenRemoved signal).
+ // code that removes a screen without notifying surfaces.
+ if (m_display) {
+ m_screens.removeIf([this](QWaylandScreen *s) { + m_screens.removeIf([this](QWaylandScreen *s) {
+ return !m_display->isScreenAlive(s); + return !m_display->isScreenAlive(s);
+ }); + });
+ }
+ +
for (auto *screen : std::as_const(m_screens)) { for (auto *screen : std::as_const(m_screens)) {
// only report valid screens // only report valid screens
// we can have some ouptuts waiting for xdg output information // we can have some ouptuts waiting for xdg output information
@@ -60,6 +73,14 @@ void QWaylandSurface::surface_enter(wl_output *output) @@ -60,6 +68,14 @@ void QWaylandSurface::surface_enter(wl_output *output)
if (!addedScreen) if (!addedScreen)
return; return;
+ // The wl_output proxy argument was resolved at demarshal time (when the + // libwayland resolves wl_output proxy pointers at demarshal time. If a
+ // event was read from the socket). If a preceding event in the same + // preceding event in the same dispatch batch destroyed the output's proxy
+ // dispatch batch destroyed the proxy, fromWlOutput may return a stale + // (e.g. via wl_registry.global_remove), fromWlOutput may return a stale
+ // QWaylandScreen pointer from freed proxy memory. Validate against the + // QWaylandScreen pointer from freed proxy memory. Validate against the
+ // display's live screen lists before using. + // display's live screen lists before dereferencing.
+ if (m_display && !m_display->isScreenAlive(addedScreen)) + if (!m_display->isScreenAlive(addedScreen))
+ return; + return;
+ +
if (m_screens.contains(addedScreen)) { if (m_screens.contains(addedScreen)) {
qCWarning(lcQpaWayland) qCWarning(lcQpaWayland)
<< "Ignoring unexpected wl_surface.enter received for output with id:" << "Ignoring unexpected wl_surface.enter received for output with id:"
@@ -80,6 +101,10 @@ void QWaylandSurface::surface_leave(wl_output *output) @@ -80,6 +96,10 @@ void QWaylandSurface::surface_leave(wl_output *output)
if (!removedScreen) if (!removedScreen)
return; return;
+ // See comment in surface_enter: the proxy may be stale. + // See comment in surface_enter: the proxy may reference a dead screen.
+ if (m_display && !m_display->isScreenAlive(removedScreen)) + if (!m_display->isScreenAlive(removedScreen))
+ return; + return;
+ +
bool wasRemoved = m_screens.removeOne(removedScreen); bool wasRemoved = m_screens.removeOne(removedScreen);
if (!wasRemoved) { if (!wasRemoved) {
qCWarning(lcQpaWayland) qCWarning(lcQpaWayland)
diff --git a/src/plugins/platforms/wayland/qwaylandsurface_p.h b/src/plugins/platforms/wayland/qwaylandsurface_p.h diff --git a/src/plugins/platforms/wayland/qwaylandsurface_p.h b/src/plugins/platforms/wayland/qwaylandsurface_p.h
index 41860297..ddb63b04 100644 index 41860297..af59f0a3 100644
--- a/src/plugins/platforms/wayland/qwaylandsurface_p.h --- a/src/plugins/platforms/wayland/qwaylandsurface_p.h
+++ b/src/plugins/platforms/wayland/qwaylandsurface_p.h +++ b/src/plugins/platforms/wayland/qwaylandsurface_p.h
@@ -57,10 +57,12 @@ protected: @@ -57,6 +57,7 @@ protected:
QList<QWaylandScreen *> m_screens; //As seen by wl_surface.enter/leave events. Chronological order. QList<QWaylandScreen *> m_screens; //As seen by wl_surface.enter/leave events. Chronological order.
QWaylandWindow *m_window = nullptr; QWaylandWindow *m_window = nullptr;
@ -164,8 +90,3 @@ index 41860297..ddb63b04 100644
std::optional<int32_t> m_preferredBufferScale; std::optional<int32_t> m_preferredBufferScale;
std::optional<wl_output_transform> m_preferredBufferTransform; std::optional<wl_output_transform> m_preferredBufferTransform;
friend class QWaylandWindow; // TODO: shouldn't need to be friends
+ friend class QWaylandDisplay;
};
} // namespace QtWaylandClient