From 35fbc26893b8fd6821fa8b09f0771d5b97d224ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Br=C3=BCbach?= Date: Tue, 28 Jul 2026 01:58:02 +0200 Subject: [PATCH] [GameScene] Arrow Graphics destruction safety Took 13 minutes --- cockatrice/src/game_graphics/game_scene.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/cockatrice/src/game_graphics/game_scene.cpp b/cockatrice/src/game_graphics/game_scene.cpp index d0a4f6798..58e6888c6 100644 --- a/cockatrice/src/game_graphics/game_scene.cpp +++ b/cockatrice/src/game_graphics/game_scene.cpp @@ -47,6 +47,17 @@ GameScene::~GameScene() { delete animationTimer; + // Delete all ArrowItems before QGraphicsScene's base destructor runs. + // QGraphicsScene::~QGraphicsScene() destroys items in arbitrary order. + // If a PlayerTarget is destroyed before an ArrowItem pointing to it, + // ArrowItem::onTargetDestroyed fires and emits on the partially-destroyed + // GameScene, causing a segfault. + for (auto *item : items()) { + if (auto *arrow = qgraphicsitem_cast(item)) { + delete arrow; + } + } + // DO NOT call clearViews() here // clearViews calls close() on the zoneViews, which sends signals; sending signals in destructors leads to segfaults // deleteLater() deletes the zoneView without allowing it to send signals @@ -530,7 +541,9 @@ void GameScene::clearArrowsForPlayer(int playerId) void GameScene::clearArrowsForPlayerLocally(int playerId) { for (int arrowId : arrowRegistry.idsForPlayer(playerId)) { - arrowRegistry.take(playerId, arrowId)->delArrow(); + if (auto *arrow = arrowRegistry.take(playerId, arrowId)) { + arrow->delArrow(); + } } }