┌   ┐
54
└   ┘

summaryrefslogtreecommitdiff
path: root/src
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 /src
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.
Diffstat (limited to 'src')
-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);
}