diff options
| author | Méven Car <[email protected]> | 2026-06-13 13:14:39 +0000 |
|---|---|---|
| committer | Méven Car <[email protected]> | 2026-06-13 14:34:10 +0000 |
| commit | 99c87fe4314d392ae8d3e4cf9c05e3f014322608 (patch) | |
| tree | b2f8ddc6bf6a9a2c78ca405641f0260c2520e37a | |
| parent | cc806587766d09f916de712b0b5e248ba0c5383c (diff) | |
versioncontrol: fix use-after-free of the current plugin
searchPlugin returns one of the observer-owned m_plugins, so m_currentPlugin
always aliases an entry in that list. Deleting m_currentPlugin in setModel
freed that object while leaving a dangling pointer in m_plugins, which the
next searchPlugin or actions call would dereference. setModel(nullptr) runs
on every directory change, so this was reachable when leaving a versioned
directory.
Make the observer the real owner: parent the plugins to it so QObject
deletes them, stop deleting the shared plugin in setModel (just clear the
current selection), and drop the matching delete in the destructor.
| -rw-r--r-- | src/views/versioncontrol/versioncontrolobserver.cpp | 17 |
1 files changed, 7 insertions, 10 deletions
diff --git a/src/views/versioncontrol/versioncontrolobserver.cpp b/src/views/versioncontrol/versioncontrolobserver.cpp index 008a9a4cf..de81156c5 100644 --- a/src/views/versioncontrol/versioncontrolobserver.cpp +++ b/src/views/versioncontrol/versioncontrolobserver.cpp @@ -44,6 +44,7 @@ VersionControlObserver::~VersionControlObserver() { if (m_currentPlugin) { m_currentPlugin->disconnect(this); + m_currentPlugin = nullptr; } if (m_updateItemStatesThread) { m_updateItemStatesThread->requestInterruption(); @@ -51,20 +52,16 @@ VersionControlObserver::~VersionControlObserver() m_updateItemStatesThread->deleteLater(); } - if (m_currentPlugin) { - delete m_currentPlugin; - m_currentPlugin = nullptr; - } - m_plugins.clear(); + // m_plugins are parented to this observer and destroyed with it by QObject. + // m_currentPlugin is one of them, so it must not be deleted on its own. } void VersionControlObserver::setModel(KFileItemModel *model) { if (m_model) { - if (m_currentPlugin) { - delete m_currentPlugin; - m_currentPlugin = nullptr; - } + // m_currentPlugin points to one of the reused, observer-owned m_plugins. + // Forget the current detection without destroying the shared plugin. + m_currentPlugin = nullptr; if (m_updateItemStatesThread) { m_updateItemStatesThread->requestInterruption(); } @@ -302,7 +299,7 @@ void VersionControlObserver::initPlugins() for (const auto &p : plugins) { if (enabledPlugins.contains(p.name())) { - auto plugin = KPluginFactory::instantiatePlugin<KVersionControlPlugin>(p, parent()).plugin; + auto plugin = KPluginFactory::instantiatePlugin<KVersionControlPlugin>(p, this).plugin; if (plugin) { m_plugins.append(plugin); } |
