[network/ktorrent/release/26.08] 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 1840cb79a053cd6f7c1308e2d1ca568fe4929c50 by Jack Hill. Committed on 21/07/2026 at 21:15. Pushed by jackh into branch 'release/26.08'. 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 (cherry picked from commit 16b1ff640d147552d5300871c71499d0f15f1698) Co-authored-by: Jack Hill <[email protected]> M +12 -11 plugins/scanfolder/scanthread.cpp M +1 -1 plugins/scanfolder/scanthread.h https://invent.kde.org/network/ktorrent/-/commit/1840cb79a053cd6f7c1308e2d1ca568fe4929c50 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; }; }