[CardDB] Clear CardInfo relations before deferred deletion (#7615)

removeCard() and swapInDatabaseData() schedule CardRelation deletion with deleteLater(), but the owning CardInfo could outlive them through an external shared pointer and kept returning the freed pointers from getAllRelatedCards(). Add CardInfo::clearDirectRelations() and call it after scheduling deletion so the UI can no longer dereference dangling relations.

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
BruebachL 2026-10-24 10:28:24 +02:00 • committed by GitHub
parent 6e770eb7b2
commit 4028606bd9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 49 additions and 0 deletions

View file

@ -26,6 +26,7 @@
#include <libcockatrice/card/database/parser/cockatrice_xml_4.h>
#include <libcockatrice/card/lazy_properties_hash.h>
#include <libcockatrice/card/printing/printing_info.h>
#include <libcockatrice/card/relation/card_relation.h>
#include <libcockatrice/interfaces/interface_card_database_path_provider.h>
#include <libcockatrice/interfaces/interface_card_set_priority_controller.h>
#include <libcockatrice/interfaces/noop_card_preference_provider.h>
@ -124,6 +125,32 @@ TEST(CardDatabaseTest, FindPrintingWithIdOnNullCardInfoReturnsEmpty)
EXPECT_TRUE(db.query()->findPrintingWithId(nullptr, "card_Not a Card_fixture").isEmpty());
}
TEST(CardInfoTest, ClearDirectRelationsDropsRawPointers)
{
auto *forward = new CardRelation("Child");
auto *reverse = new CardRelation("Parent");
auto *toMe = new CardRelation("Child");
auto card = CardInfo::newInstance("Parent", "", false, QHash<QString, QString>(), {forward}, {reverse},
SetToPrintingsMap(), CardInfo::UiAttributes());
card->addReverseRelatedCards2Me(toMe);
ASSERT_EQ(1, card->getRelatedCards().size());
ASSERT_EQ(1, card->getReverseRelatedCards().size());
ASSERT_EQ(1, card->getReverseRelatedCards2Me().size());
ASSERT_EQ(2, card->getAllRelatedCards().size());
card->clearDirectRelations();
EXPECT_TRUE(card->getRelatedCards().isEmpty());
EXPECT_TRUE(card->getReverseRelatedCards().isEmpty());
EXPECT_TRUE(card->getReverseRelatedCards2Me().isEmpty());
EXPECT_TRUE(card->getAllRelatedCards().isEmpty());
delete forward;
delete reverse;
delete toMe;
}
TEST(CardDatabaseTest, Xml4LocalizedDataRoundTrip)
{
NoopCardSetPriorityController controller;