Fix memory leaks from DeckLoader usage (#5665)

* add comment

* stack allocate DeckLoader for loading tags

* deckModel now takes ownership of DeckLoader

* fix remaining

* add comment
This commit is contained in:
RickyRister 2025-03-02 15:57:30 -08:00 committed by GitHub
parent 87c5d07807
commit e1964f21de
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 33 additions and 8 deletions

View file

@ -128,6 +128,10 @@ void AbstractTabDeckEditor::actSwapCard(CardInfoPtr info, QString zoneName)
deckDockWidget->deckModel->findCard(info->getName(), zoneName, providerId, collectorNumber)); deckDockWidget->deckModel->findCard(info->getName(), zoneName, providerId, collectorNumber));
} }
/**
* Sets the currently active deck for this tab
* @param _deck The deck. Takes ownership of the object
*/
void AbstractTabDeckEditor::setDeck(DeckLoader *_deck) void AbstractTabDeckEditor::setDeck(DeckLoader *_deck)
{ {
deckDockWidget->setDeck(_deck); deckDockWidget->setDeck(_deck);
@ -289,12 +293,13 @@ void AbstractTabDeckEditor::openDeckFromFile(const QString &fileName, DeckOpenLo
SettingsCache::instance().recents().updateRecentlyOpenedDeckPaths(fileName); SettingsCache::instance().recents().updateRecentlyOpenedDeckPaths(fileName);
if (deckOpenLocation == NEW_TAB) { if (deckOpenLocation == NEW_TAB) {
emit openDeckEditor(l); emit openDeckEditor(l);
l->deleteLater();
} else { } else {
deckMenu->setSaveStatus(false); deckMenu->setSaveStatus(false);
setDeck(l); setDeck(l);
} }
} else { } else {
delete l; l->deleteLater();
QMessageBox::critical(this, tr("Error"), tr("Could not open deck at %1").arg(fileName)); QMessageBox::critical(this, tr("Error"), tr("Could not open deck at %1").arg(fileName));
} }
deckMenu->setSaveStatus(true); deckMenu->setSaveStatus(true);

View file

@ -764,6 +764,10 @@ void TabSupervisor::talkLeft(TabMessage *tab)
removeTab(indexOf(tab)); removeTab(indexOf(tab));
} }
/**
* Creates a new deck editor tab
* @param deckToOpen The deck to open in the tab. Creates a copy of the DeckLoader instance.
*/
TabDeckEditor *TabSupervisor::addDeckEditorTab(const DeckLoader *deckToOpen) TabDeckEditor *TabSupervisor::addDeckEditorTab(const DeckLoader *deckToOpen)
{ {
auto *tab = new TabDeckEditor(this); auto *tab = new TabDeckEditor(this);

View file

@ -289,6 +289,10 @@ void DeckEditorDeckDockWidget::setBannerCard(int /* changedIndex */)
emit deckChanged(); emit deckChanged();
} }
/**
* Sets the currently active deck for this tab
* @param _deck The deck. Takes ownership of the object
*/
void DeckEditorDeckDockWidget::setDeck(DeckLoader *_deck) void DeckEditorDeckDockWidget::setDeck(DeckLoader *_deck)
{ {
deckModel->setDeckList(_deck); deckModel->setDeckList(_deck);

View file

@ -143,10 +143,10 @@ void DeckPreviewDeckTagsDisplayWidget::openTagEditDlg()
auto *deckEditor = qobject_cast<TabDeckEditor *>(currentParent); auto *deckEditor = qobject_cast<TabDeckEditor *>(currentParent);
QStringList knownTags; QStringList knownTags;
QStringList allFiles = getAllFiles(SettingsCache::instance().getDeckPath()); QStringList allFiles = getAllFiles(SettingsCache::instance().getDeckPath());
auto *loader = new DeckLoader(); DeckLoader loader;
for (const QString &file : allFiles) { for (const QString &file : allFiles) {
loader->loadFromFile(file, DeckLoader::getFormatFromName(file), false); loader.loadFromFile(file, DeckLoader::getFormatFromName(file), false);
QStringList tags = loader->getTags(); QStringList tags = loader.getTags();
knownTags.append(tags); knownTags.append(tags);
knownTags.removeDuplicates(); knownTags.removeDuplicates();
} }

View file

@ -18,6 +18,7 @@ DeckListModel::DeckListModel(QObject *parent)
: QAbstractItemModel(parent), lastKnownColumn(1), lastKnownOrder(Qt::AscendingOrder) : QAbstractItemModel(parent), lastKnownColumn(1), lastKnownOrder(Qt::AscendingOrder)
{ {
deckList = new DeckLoader; deckList = new DeckLoader;
deckList->setParent(this);
connect(deckList, &DeckLoader::deckLoaded, this, &DeckListModel::rebuildTree); connect(deckList, &DeckLoader::deckLoaded, this, &DeckListModel::rebuildTree);
connect(deckList, &DeckLoader::deckHashChanged, this, &DeckListModel::deckHashChanged); connect(deckList, &DeckLoader::deckHashChanged, this, &DeckListModel::deckHashChanged);
root = new InnerDecklistNode; root = new InnerDecklistNode;
@ -26,7 +27,6 @@ DeckListModel::DeckListModel(QObject *parent)
DeckListModel::~DeckListModel() DeckListModel::~DeckListModel()
{ {
delete root; delete root;
delete deckList;
} }
void DeckListModel::rebuildTree() void DeckListModel::rebuildTree()
@ -470,10 +470,14 @@ void DeckListModel::cleanList()
setDeckList(new DeckLoader); setDeckList(new DeckLoader);
} }
/**
* @param _deck The deck. Takes ownership of the object
*/
void DeckListModel::setDeckList(DeckLoader *_deck) void DeckListModel::setDeckList(DeckLoader *_deck)
{ {
delete deckList; deckList->deleteLater();
deckList = _deck; deckList = _deck;
deckList->setParent(this);
connect(deckList, &DeckLoader::deckLoaded, this, &DeckListModel::rebuildTree); connect(deckList, &DeckLoader::deckLoaded, this, &DeckListModel::rebuildTree);
connect(deckList, &DeckLoader::deckHashChanged, this, &DeckListModel::deckHashChanged); connect(deckList, &DeckLoader::deckHashChanged, this, &DeckListModel::deckHashChanged);
rebuildTree(); rebuildTree();

View file

@ -63,13 +63,14 @@ void DlgLoadDeckFromClipboard::actOK()
QTextStream stream(&buffer); QTextStream stream(&buffer);
auto *deckLoader = new DeckLoader; auto *deckLoader = new DeckLoader;
deckLoader->setParent(this);
if (buffer.contains("<cockatrice_deck version=\"1\">")) { if (buffer.contains("<cockatrice_deck version=\"1\">")) {
if (deckLoader->loadFromString_Native(buffer)) { if (deckLoader->loadFromString_Native(buffer)) {
deckList = deckLoader; deckList = deckLoader;
accept(); accept();
} else { } else {
QMessageBox::critical(this, tr("Error"), tr("Invalid deck list.")); QMessageBox::critical(this, tr("Error"), tr("Invalid deck list."));
delete deckLoader;
} }
} else if (deckLoader->loadFromStream_Plain(stream)) { } else if (deckLoader->loadFromStream_Plain(stream)) {
deckList = deckLoader; deckList = deckLoader;
@ -81,7 +82,6 @@ void DlgLoadDeckFromClipboard::actOK()
accept(); accept();
} else { } else {
QMessageBox::critical(this, tr("Error"), tr("Invalid deck list.")); QMessageBox::critical(this, tr("Error"), tr("Invalid deck list."));
delete deckLoader;
} }
} }

View file

@ -24,6 +24,14 @@ private:
public: public:
explicit DlgLoadDeckFromClipboard(QWidget *parent = nullptr); explicit DlgLoadDeckFromClipboard(QWidget *parent = nullptr);
/**
* Gets the loaded deck. Only call this method after this dialog window has been successfully exec'd.
*
* The returned DeckLoader is parented to this object; make sure to take ownership of the DeckLoader if you intend
* to use it, since otherwise it will get destroyed once this dlg is destroyed
* @return The DeckLoader
*/
DeckLoader *getDeckList() const DeckLoader *getDeckList() const
{ {
return deckList; return deckList;