summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorisanae <14251494+isanae@users.noreply.github.com>2019-11-27 15:15:27 -0500
committerisanae <14251494+isanae@users.noreply.github.com>2019-11-27 15:15:27 -0500
commit7f2d0e672205b85425cff488aa41ba0117abd191 (patch)
tree2a3a29b80d7bdf868fe45cc17a1a8b82dd9fbec9 /src
parente18afba89300979a1cabaf26a956903d737e3253 (diff)
fix crash when changing categories on mods when the "no categories" filter is selected
Diffstat (limited to 'src')
-rw-r--r--src/modlist.cpp27
-rw-r--r--src/modlist.h1
2 files changed, 28 insertions, 0 deletions
diff --git a/src/modlist.cpp b/src/modlist.cpp
index c5bc37e9..b7a9b0a1 100644
--- a/src/modlist.cpp
+++ b/src/modlist.cpp
@@ -61,6 +61,7 @@ ModList::ModList(PluginContainer *pluginContainer, QObject *parent)
, m_Profile(nullptr)
, m_NexusInterface(nullptr)
, m_Modified(false)
+ , m_InNotifyChange(false)
, m_FontMetrics(QFont())
, m_DropOnItems(false)
, m_PluginContainer(pluginContainer)
@@ -1195,6 +1196,32 @@ bool ModList::removeRows(int row, int count, const QModelIndex &parent)
void ModList::notifyChange(int rowStart, int rowEnd)
{
+ // this function can emit dataChanged(), which can eventually recurse back
+ // here; for example:
+ //
+ // - a filter is active in the mod list, such as "no categories"
+ // - mods are selected and a category is set on them
+ // - these mods get updated here and disappear from the list because they're
+ // not in "no categories" anymore
+ // - dataChanged() is emitted
+ // - it's picked up in MainWindow::modlistSelectionsChanged() because the
+ // selected mods are gone
+ // - it calls setOverwriteMarkers(), which calls notifyChange() again and
+ // ends up here
+ // - dataChanged() is emitted again
+ //
+ // at this point, MO crashes because dataChanged() is not reentrant: it's in
+ // the middle of modifying internal data and crashes when trying to change an
+ // internal vector
+ //
+ // long story short, this prevents reentrancy
+ if (m_InNotifyChange) {
+ return;
+ }
+
+ m_InNotifyChange = true;
+ Guard g([&]{ m_InNotifyChange = false; });
+
if (rowStart < 0) {
m_Overwrite.clear();
m_Overwritten.clear();
diff --git a/src/modlist.h b/src/modlist.h
index 5ce32f6e..631401c0 100644
--- a/src/modlist.h
+++ b/src/modlist.h
@@ -341,6 +341,7 @@ private:
std::set<int> m_RequestIDs;
mutable bool m_Modified;
+ bool m_InNotifyChange;
QFontMetrics m_FontMetrics;