diff options
| author | isanae <14251494+isanae@users.noreply.github.com> | 2019-11-27 15:16:58 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-11-27 15:16:58 -0500 |
| commit | 23bfe4e9ffe1637ff9e4912f913567ee921c801e (patch) | |
| tree | 1e91a5e00683ea4633f15c114dcf4a293d2a294c /src/modlist.cpp | |
| parent | 454c550b158d0efa1820cc09562f77f718abffd3 (diff) | |
| parent | 7f2d0e672205b85425cff488aa41ba0117abd191 (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.cpp | 27 |
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(); |
