summaryrefslogtreecommitdiff
path: root/src/modlist.cpp
diff options
context:
space:
mode:
authorisanae <14251494+isanae@users.noreply.github.com>2019-11-27 15:16:58 -0500
committerGitHub <noreply@github.com>2019-11-27 15:16:58 -0500
commit23bfe4e9ffe1637ff9e4912f913567ee921c801e (patch)
tree1e91a5e00683ea4633f15c114dcf4a293d2a294c /src/modlist.cpp
parent454c550b158d0efa1820cc09562f77f718abffd3 (diff)
parent7f2d0e672205b85425cff488aa41ba0117abd191 (diff)
Merge pull request #909 from isanae/change-category-crash
Fix crash when changing categories on mods while a filter is selected
Diffstat (limited to 'src/modlist.cpp')
-rw-r--r--src/modlist.cpp27
1 files changed, 27 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();