[network/ktorrent] plugins/scanfolder: Fix crash in ScanFolder plugin due to non-threadsafe KDirWatch destructor
Jack Hill <[email protected]>
| Newsgroups | gmane.comp.kde.cvs |
|---|---|
| Message-ID | <[email protected]> |
Git commit 16b1ff640d147552d5300871c71499d0f15f1698 by Jack Hill.
Committed on 19/07/2026 at 15:23.
Pushed by jackh into branch 'master'.
Fix crash in ScanFolder plugin due to non-threadsafe KDirWatch destructor
KDirWatch has an internal QThreadLocalStorage object which is cleaned
up automatically when the last KDirWatch is deleted. Therefore
KDirWatch is not thread-safe, and each ScanFolder must be deleted in
its own thread. stop() can be called from any thread, so use
deleteLater() instead of normal delete.
To reproduce:
1. Enable Scan Folder plugin
2. Open the settings page and add a folder, doesn't need to contain
any files
3. Disable the Scan Folder plugin
Before:
- Crash
Now:
- No crash
Fixes sentry issue KTORRENT-W8
M +12 -11 plugins/scanfolder/scanthread.cpp
M +1 -1 plugins/scanfolder/scanthread.h
https://invent.kde.org/network/ktorrent/-/commit/16b1ff640d147552d5300871c71499d0f15f1698
diff --git a/plugins/scanfolder/scanthread.cpp b/plugins/scanfolder/scanthread.cpp
index 676fb146d..4ce195691 100644
--- a/plugins/scanfolder/scanthread.cpp
+++ b/plugins/scanfolder/scanthread.cpp
@@ -52,7 +52,6 @@ ScanThread::ScanThread()
: stop_requested(false)
, recursive(false)
{
- scan_folders.setAutoDelete(true);
moveToThread(this);
}
@@ -100,20 +99,19 @@ void ScanThread::updateFolders()
mutex.unlock();
// first erase folders we don't need anymore
- bt::PtrMap<QString, ScanFolder>::iterator i = scan_folders.begin();
+ auto i = scan_folders.begin();
while (i != scan_folders.end()) {
- if (!tmp.contains(i->first)) {
- QString f = i->first;
- i++;
- scan_folders.erase(f);
+ if (!tmp.contains(i.key())) {
+ i.value()->deleteLater();
+ i = scan_folders.erase(i);
} else {
- i->second->setRecursive(recursive);
+ i.value()->setRecursive(recursive);
i++;
}
}
for (const QString &folder : std::as_const(tmp)) {
- if (scan_folders.find(folder)) {
+ if (scan_folders.value(folder)) {
continue;
}
@@ -135,9 +133,12 @@ void ScanThread::stop()
{
stop_requested = true;
- // XXX seems like deleting KDirWatch object(s) created in scan_folders
- // in destructor of this QThread after it has been stopped
- // causes memory corruption, so we delete them early
+ // Make sure QObjects are deleted in their own thread.
+ // Also KDirWatch uses thread-local storage which must
+ // be cleaned up by deleting in the proper thread.
+ for (auto *scan_folder : scan_folders) {
+ scan_folder->deleteLater();
+ }
scan_folders.clear();
exit();
wait();
diff --git a/plugins/scanfolder/scanthread.h b/plugins/scanfolder/scanthread.h
index db1b282e5..12da8a660 100644
--- a/plugins/scanfolder/scanthread.h
+++ b/plugins/scanfolder/scanthread.h
@@ -75,7 +75,7 @@ private:
QStringList folders;
std::atomic<bool> stop_requested;
std::atomic<bool> recursive;
- bt::PtrMap<QString, ScanFolder> scan_folders;
+ QMap<QString, ScanFolder *> scan_folders;
};
}