60 lines
2.4 KiB
Diff
60 lines
2.4 KiB
Diff
# UNDF: UNDF-2026-000001111
|
|
# UNDF: (leave blank)
|
|
# Defect: kdenlive-0009
|
|
# Component: src/core.cpp + src/mainwindow.h — buildLumaThumbs / m_lumacache
|
|
# MOAD: 0005 (Thundering Herd / CWE-362) — concurrent cache get+null+compute+put without lock
|
|
# Severity: HIGH — data race on QMap<QString, QImage> from QtConcurrent worker vs UI thread
|
|
#
|
|
# buildLumaThumbs() is called via QtConcurrent::run() (a worker thread) in
|
|
# src/mltconnection.cpp:455. It reads and writes MainWindow::m_lumacache, a
|
|
# static QMap<QString, QImage>, without any mutex.
|
|
#
|
|
# Concurrently, UI widget code (urllistparamwidget.cpp, listparamwidget.cpp,
|
|
# listdependencyparamwidget.cpp, slideshowclip.cpp, core.cpp) reads and writes
|
|
# the same map from the main thread.
|
|
#
|
|
# QMap is not thread-safe for concurrent writes from different threads.
|
|
# A concurrent insert() + rehash from the worker thread and any read/write from
|
|
# the UI thread is undefined behavior — likely manifesting as random crashes or
|
|
# corrupted thumbnails during project load.
|
|
#
|
|
# Fix: add a QMutex to protect all m_lumacache accesses.
|
|
#
|
|
--- a/src/mainwindow.h
|
|
+++ b/src/mainwindow.h
|
|
@@ -103,8 +103,10 @@
|
|
static QMap<QString, QImage> m_lumacache;
|
|
+ static QMutex m_lumacacheMutex;
|
|
/** @brief List of all luma files to use when rendering transitions */
|
|
static QStringList m_lumaFiles;
|
|
|
|
--- a/src/mainwindow.cpp
|
|
+++ b/src/mainwindow.cpp
|
|
@@ -133,2 +133,3 @@
|
|
QMap<QString, QImage> MainWindow::m_lumacache;
|
|
+QMutex MainWindow::m_lumacacheMutex;
|
|
|
|
--- a/src/core.cpp
|
|
+++ b/src/core.cpp
|
|
@@ buildLumaThumbs
|
|
void Core::buildLumaThumbs(const QStringList &values)
|
|
{
|
|
for (auto &entry : values) {
|
|
- if (MainWindow::m_lumacache.contains(entry)) {
|
|
+ QMutexLocker locker(&MainWindow::m_lumacacheMutex);
|
|
+ if (MainWindow::m_lumacache.contains(entry)) {
|
|
continue;
|
|
}
|
|
QImage pix(entry);
|
|
if (!pix.isNull()) {
|
|
MainWindow::m_lumacache.insert(entry, pix.scaled(50, 30, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
|
}
|
|
+ // locker released at end of loop iteration
|
|
}
|
|
}
|
|
|
|
# Note: all other m_lumacache read sites (urllistparamwidget.cpp lines 204-205, 363, 393;
|
|
# listparamwidget.cpp lines 88-89; listdependencyparamwidget.cpp lines 157-158;
|
|
# slideshowclip.cpp lines 148-154; core.cpp line 656) must also hold m_lumacacheMutex
|
|
# before accessing the cache. Those sites run on the main thread, so the locker
|
|
# adds only minimal overhead there.
|