From 799c255fd713039ab23e3ff0a1bcd68428a9a127 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Br=C3=BCbach?= Date: Mon, 7 Sep 2026 00:53:28 +0200 Subject: [PATCH] Close all zone views of a leaving player to avoid crashing (#4298) When a player left, GameScene::removePlayer iterated zoneViews while close() synchronously removed the current view from that list. A judge with several open views of the departing player (e.g. library and hand) only had the first one closed; the remaining views were skipped and left pointing at a player that was about to be deleted, crashing the client on the next access. - GameScene::removePlayer: iterate over a copy of zoneViews - GameScene::toggleZoneView: same fix for the identical iteration bug --- cockatrice/src/game_graphics/game_scene.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/cockatrice/src/game_graphics/game_scene.cpp b/cockatrice/src/game_graphics/game_scene.cpp index 457f1b3f7..17af7618b 100644 --- a/cockatrice/src/game_graphics/game_scene.cpp +++ b/cockatrice/src/game_graphics/game_scene.cpp @@ -221,7 +221,12 @@ void GameScene::removePlayer(PlayerLogic *player) clearArrowsForPlayer(player->getPlayerInfo()->getId()); - for (ZoneViewWidget *zone : zoneViews) { + // Closing a view removes it from zoneViews synchronously, so iterate over a + // copy: otherwise a player with several open views (e.g. library and hand) + // only has the first one closed here and the remaining views are left + // pointing at a player that is about to be deleted. + const QList zoneViewCopy = zoneViews; + for (ZoneViewWidget *zone : zoneViewCopy) { if (zone->getPlayer() == player) { zone->close(); } @@ -664,7 +669,10 @@ CardItem *GameScene::findTopmostCardInZone(const QList &items, */ void GameScene::toggleZoneView(PlayerLogic *player, const QString &zoneName, int numberCards, bool isReversed) { - for (auto &view : zoneViews) { + // Closing a view removes it from zoneViews synchronously, so iterate over a + // copy to make sure every already-open matching view is closed. + const QList zoneViewCopy = zoneViews; + for (auto *view : zoneViewCopy) { ZoneViewZone *temp = view->getZone(); if (temp->getLogic()->getName() == zoneName && temp->getLogic()->getPlayer() == player && qobject_cast(temp->getLogic())->getNumberCards() == numberCards) {