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 /src/views/versioncontrol/versioncontrolobserver.cpp | |
| 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.
Diffstat (limited to 'src/views/versioncontrol/versioncontrolobserver.cpp')
| -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); } |
