java-topology/defects/kdenlive/patch/kdenlive-0009-lumacache-qtconcurrent-race.patch

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.