┌   ┐
54
└   ┘

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMéven Car <[email protected]>2026-06-13 13:14:39 +0000
committerMéven Car <[email protected]>2026-06-13 14:34:10 +0000
commit99c87fe4314d392ae8d3e4cf9c05e3f014322608 (patch)
treeb2f8ddc6bf6a9a2c78ca405641f0260c2520e37a
parentcc806587766d09f916de712b0b5e248ba0c5383c (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.cpp17
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);
}