https://bugs.kde.org/show_bug.cgi?id=528090
Bug ID: 528090
Summary: Crash (SIGSEGV / use-after-free in
WhisperDownload::processHashCheck) when closing
Whisper model download dialog during model integrity
check
Classification: Applications
Product: kdenlive
Version First 26.08.2
Reported In:
Platform: RedHat Enterprise Linux
OS: Linux
Status: REPORTED
Severity: crash
Priority: NOR
Component: Title Clips & Subtitles
Assignee: [email protected]
Reporter: [email protected]
Target Milestone: ---
SUMMARY
Kdenlive crashes with SIGSEGV (use-after-free on dangling `this` pointer)
in a background QThreadPool worker running
`WhisperDownload::processHashCheck()` if the `WhisperDownload`
modal dialog is closed while the SHA-256 hash verification of installed
Whisper `.pt` models is still in progress.
WHAT I WAS DOING WHEN THE CRASH HAPPENED / STEPS TO REPRODUCE
1. Have one or more large OpenAI Whisper models already downloaded in
`~/.var/app/org.kde.kdenlive/data/kdenlive/whispermodels/` (in this case:
`large-v3-turbo.pt` [1.51 GB], `medium.
pt` [1.42 GB], `small.pt` [461 MB], `base.pt` [139 MB], `tiny.pt` [72 MB]).
2. Open Settings -> Configure Kdenlive -> Plugins -> Speech To Text
(Whisper) (`PluginsSettings`), and open the Whisper model management / download
dialog (`WhisperDownload`).
- Opening `WhisperDownload` immediately calls
`WhisperDownload::checkHashes()`, which launches
`QtConcurrent::run(&WhisperDownload::processHashCheck, this, hashesToCheck)` on
a
background thread and locks `m_closeMutex`.
3. Close the `WhisperDownload` dialog (`10:59:04`) before
`QCryptographicHash::addData(&info)` finishes hashing the large `.pt` file(s),
for example via the window close button (X) or
Escape key (`QDialog::reject()`).
- At this point, systemd journal logs: `QMutex: destroying locked mutex`
because stack-allocated `WhisperDownload` (`0x7fff2efa1df0`) is destroyed while
`processHashCheck` still
holds `m_closeMutex` (`0x7fff2efa1e70`).
4. In the still-open `PluginsSettings` dialog
(`src/dialogs/settings/pluginssettings.cpp:92`), click to check/install missing
dependencies
(`AbstractPythonInterface::installMissingDependencies` at
`src/pythoninterfaces/abstractpythoninterface.cpp:621`), which opens a modal
`KMessageBox::warningContinueCancel`
(`QDialog::exec()`), reusing the main thread stack memory around
`0x7fff2efa1df0`.
5. Approximately 5 seconds after `WhisperDownload` was closed (`10:59:09`),
`QCryptographicHash::addData(&info)` finishes hashing on the worker thread
(Thread 1 / LWP 296) and
executes `Q_EMIT itemMatch(i.value(), hashMatch)` on the destroyed
`WhisperDownload` instance (`this = 0x7fff2efa1df0`), causing an immediate
segmentation fault.
OBSERVED RESULT
1. When `WhisperDownload` closes at `10:59:04`:
`kdenlive[31070]: QMutex: destroying locked mutex`
2. When `QCryptographicHash::addData()` completes on the worker thread at
`10:59:09`:
`SIGSEGV` in `QQmlData::isSignalConnected` / `QMetaObject::activate` /
`WhisperDownload::itemMatch` because `sender = 0x7fff2efa1df0` is a dangling
stack pointer whose `d_ptr` was
overwritten by subsequent stack frames on the main thread.
EXPECTED RESULT
Closing `WhisperDownload` by any means (Close button, window close 'X',
Escape key / `reject()`, or destruction) must set `m_requestClose = true` and
wait for `m_closeMutex` before
the `WhisperDownload` object is destroyed, or avoid passing raw `this` to
`QtConcurrent::run`.
ROOT CAUSE ANALYSIS
In `src/pythoninterfaces/dialogs/whisperdownload.h` and
`src/pythoninterfaces/dialogs/whisperdownload.cpp`:
- `WhisperDownload` is stack-allocated and executed via `QDialog::exec()`.
- `WhisperDownload::checkHashes()` spawns
`QtConcurrent::run(&WhisperDownload::processHashCheck, this, hashesToCheck)`.
- `WhisperDownload::processHashCheck()` acquires `QMutexLocker
lock(&m_closeMutex)` and iterates over `hashesToCheck`, calling
`QCryptographicHash::addData(&info)` on each `.pt` model
file and emitting `Q_EMIT itemMatch(i.value(), hashMatch)`.
- Only `WhisperDownload::queryClose()` (connected to
`QDialogButtonBox::Close`) sets `m_requestClose = true` and locks
`m_closeMutex` before calling `accept()`.
- `WhisperDownload` does not define a destructor (`~WhisperDownload()`),
nor does it override `reject()` or `closeEvent(QCloseEvent*)` to set
`m_requestClose = true` and wait on
`m_closeMutex`. Furthermore, `QCryptographicHash::addData(&info)` blocks
synchronously for the entire 1.5 GB file read before checking `m_requestClose`.
SOFTWARE/OS VERSIONS (from `kinfo` and `flatpak info`)
Operating System: Fedora Linux 44
KDE Plasma Version: 6.7.5
KDE Frameworks Version: 6.31.0
Qt Version: 6.11.3 (Flatpak runtime) / 6.11.2 (Host)
Kernel Version: 7.2.13-200.fc44.x86_64 (64-bit)
Graphics Platform: Wayland
Processors: 8 × 11th Gen Intel® Core™ i5-1145G7 @ 2.60GHz
Memory: 32 GiB of RAM (30.7 GiB usable)
Graphics Processor: Intel® Iris® Xe Graphics
Flatpak Package Details:
- Application: org.kde.kdenlive 26.08.2 (flathub stable, arch x86_64)
- App Commit:
b1fc34accc861c296d08863b01c65d9c32816bdf1d08414ee157de565e56199d
- App Debug Commit (org.kde.kdenlive.Debug):
efff7f5c35f4e69146ec808e9f25bf51b30ac0cff80426843726036118f6cd8a
- Runtime: org.kde.Platform/x86_64/6.11
- Runtime Commit:
fb23e178d082b117df7924f9a84710992ec233ebc007385feb85d349c4c81415
- SDK Debug Commit (org.kde.Sdk.Debug//6.11):
ca2e2fd709050b8496f75ab4d315b2b9731d6d13e0331c3a7361c65af8
BACKTRACE (GDB with DWARF debug symbols for Kdenlive and Qt6)
Core was generated by `/app/bin/kdenlive'.
Program terminated with signal SIGSEGV, Segmentation fault.
[Current thread is 1 (LWP 296)]
Thread 1 (LWP 296 - Crashed QThreadPool worker thread):
#0 0x00007fcc5fd890a2 in std::__atomic_base<unsigned long long>::load
(this=0x61, __m=std::memory_order_relaxed) at
/usr/include/c++/15.2.0/bits/atomic_base.h:501
__b = std::memory_order_relaxed
__PRETTY_FUNCTION__ = <optimized out>
#1 QAtomicOps<unsigned long long>::loadRelaxed<unsigned long long>
(_q_value=...) at /usr/include/QtCore/qatomic_cxx11.h:203
No locals.
#2 QBasicAtomicInteger<unsigned long long>::loadRelaxed (this=0x61) at
/usr/include/QtCore/qbasicatomic.h:48
No locals.
#3 QQmlData::signalHasEndpoint (this=0x560e8bb50780, index=10) at
/usr/lib/debug/source/org.kde.Sdk/qtdeclarative.bst/src/qml/qml/qqmldata_p.h:375
list = 0x61
#4 QQmlData::isSignalConnected (d=0x560e8bb50780, index=10) at
/usr/lib/debug/source/org.kde.Sdk/qtdeclarative.bst/src/qml/qml/qqmlengine.cpp:359
ddata = 0x560e8bb50780
#5 0x00007fcc5f02450e in QObjectPrivate::isDeclarativeSignalConnected
(this=<optimized out>, signal_index=10) at
/usr/lib/debug/source/org.kde.Sdk/qtbase.
bst/src/corelib/kernel/qobject_p.h:232
No locals.
#6 doActivate<false> (sender=0x7fff2efa1df0, signal_index=10,
argv=argv@entry=0x7fcc36dfdef0) at
/usr/lib/debug/source/org.kde.Sdk/qtbase.bst/src/corelib/kernel/qobject.cpp:4278
sp = <optimized out>
signal_spy_set = <optimized out>
empty_argv = {0x7fcbdc000f90}
senderDeleted = <optimized out>
#7 0x00007fcc5f01bb69 in QMetaObject::activate
(sender=sender@entry=0x7fff2efa1df0, m=m@entry=0x560e4a6f6000,
local_signal_index=local_signal_index@entry=0,
argv=argv@entry=0x7fcc36dfdef0) at
/usr/lib/debug/source/org.kde.Sdk/qtbase.bst/src/corelib/kernel/qobject.cpp:4453
signal_index = <optimized out>
#8 0x0000560e49803b7a in QMetaObject::activate<void, QString, bool>
(sender=0x7fff2efa1df0, mo=0x560e4a6f6000, local_signal_index=0, ret=0x0) at
/usr/include/QtCore/qobjectdefs.h:320
_a = {0x0, 0x7fcc36dfdfb0, 0x7fcc36dfdeec}
#9 WhisperDownload::itemMatch (this=this@entry=0x7fff2efa1df0, _t1=...,
_t2=<optimized out>) at
/run/build/kdenlive/_flatpak_build/src/kdenliveLib_autogen/N4EE2GT4VS/moc_whisperdownload.cpp:165
No locals.
#10 0x0000560e49e47dcd in WhisperDownload::processHashCheck
(this=0x7fff2efa1df0, hashesToCheck=...) at
/run/build/kdenlive/src/pythoninterfaces/dialogs/whisperdownload.cpp:259
info = {<QFileDevice> = {<QIODevice> = {<QObject> = {_vptr.QObject
= 0x7fcc5f4e2ec8 <vtable for QFile+16>, d_ptr = {d = 0x7fcbdc003c00}}, <No data
fields>}, <No data fields>},
<No data fields>}
hashMatch = <optimized out>
lock = {m_mutex = 0x7fff2efa1e70, m_isLocked = true}
i = {c = {d = {d = {ptr = 0x560e8c539d50}}}, i = {i = {_M_node =
0x560e8c539d60}}, n = {i = {_M_node = <optimized out>}}}
#11 0x0000560e49e4b2ad in std::__invoke_impl<void, void
(WhisperDownload::*&)(QMap<QString, QString>), WhisperDownload*&, QMap<QString,
QString>&> (__f=<synthetic pointer>: <optimized
out>, __t=<synthetic pointer>: <optimized out>) at
/usr/include/c++/15.2.0/bits/invoke.h:76
No locals.
#12 std::__invoke<void (WhisperDownload::*&)(QMap<QString, QString>),
WhisperDownload*&, QMap<QString, QString>&> (__fn=<synthetic pointer>:
<optimized out>) at /usr/include/c++/15.2.
0/bits/invoke.h:98
No locals.
#13 std::invoke<void (WhisperDownload::*&)(QMap<QString, QString>),
WhisperDownload*&, QMap<QString, QString>&> (__fn=<synthetic pointer>:
<optimized out>) at /usr/include/c++/15.2.
0/functional:122
No locals.
#14 QtConcurrent::StoredFunctionCall<void
(WhisperDownload::*)(QMap<QString, QString>), WhisperDownload*, QMap<QString,
QString> >::runFunctor()::{lambda(void
(WhisperDownload::*)(QMap<QString, QString>), WhisperDownload*, QMap<QString,
QString>)#1}::operator()(void (WhisperDownload::*)(QMap<QString, QString>),
WhisperDownload*, QMap<QString,
QString>) const (__closure=<optimized out>, function=<optimized out>,
args#0=<optimized out>, args#1=...) at
/usr/include/QtConcurrent/qtconcurrentstoredfunctioncall.h:117
No locals.
#19 QtConcurrent::StoredFunctionCall<void
(WhisperDownload::*)(QMap<QString, QString>), WhisperDownload*, QMap<QString,
QString> >::runFunctor (this=<optimized out>) at
/usr/include/QtConcurrent/qtconcurrentstoredfunctioncall.h:121
invoke = <optimized out>
#20 0x0000560e49508ab5 in QtConcurrent::RunFunctionTaskBase<void>::run
(this=0x560e8734f9a0) at /usr/include/QtConcurrent/qtconcurrentrunbase.h:84
No locals.
#21 0x00007fcc5f0ea154 in QThreadPoolThread::run (this=0x560e8bb91930) at
/usr/lib/debug/source/org.kde.Sdk/qtbase.bst/src/corelib/thread/qthreadpool.cpp:72
del = true
page = <optimized out>
r = 0x560e8734f9a0
locker = {m_mutex = 0x560e866d3af8, m_isLocked = false}
#22 0x00007fcc5f1a4b07 in QThreadPrivate::start (arg=0x560e8bb91930) at
/usr/lib/debug/source/org.kde.Sdk/qtbase.bst/src/corelib/thread/qthread_unix.cpp:466
thr = 0x560e8bb91930
data = 0x560e8bb91960
#23 0x00007fcc5e89b4ca in start_thread () from
/var/lib/flatpak/runtime/org.kde.Platform/x86_64/6.11/fb23e178d082b117df7924f9a84710992ec233ebc007385feb85d349c4c81415/files/lib/x86_64-
linux-gnu/libc.so.6
#24 0x00007fcc5e91f014 in clone () from
/var/lib/flatpak/runtime/org.kde.Platform/x86_64/6.11/fb23e178d082b117df7924f9a84710992ec233ebc007385feb85d349c4c81415/files/lib/x86_64-linux-
gnu/libc.so.6
Thread 24 (LWP 2 - Main GUI thread at time of crash):
#0 0x00007fcc5e8a3b42 in __syscall_cancel_arch () from
/var/lib/flatpak/runtime/org.kde.Platform/x86_64/6.
11/fb23e178d082b117df7924f9a84710992ec233ebc007385feb85d349c4c81415/files/lib/x86_64-linux-gnu/libc.so.6
#1 0x00007fcc5e897c9c in __internal_syscall_cancel () from
/var/lib/flatpak/runtime/org.kde.Platform/x86_64/6.
11/fb23e178d082b117df7924f9a84710992ec233ebc007385feb85d349c4c81415/files/lib/x86_64-linux-gnu/libc.so.6
#2 0x00007fcc5e897ce4 in __syscall_cancel () from
/var/lib/flatpak/runtime/org.kde.Platform/x86_64/6.
11/fb23e178d082b117df7924f9a84710992ec233ebc007385feb85d349c4c81415/files/lib/x86_64-linux-gnu/libc.so.6
#3 0x00007fcc5e912396 in ppoll () from
/var/lib/flatpak/runtime/org.kde.Platform/x86_64/6.11/fb23e178d082b117df7924f9a84710992ec233ebc007385feb85d349c4c81415/files/lib/x86_64-linux-
gnu/libc.so.6
#4 0x00007fcc5ed0f232 in g_main_context_iterate_unlocked.isra () from
/var/lib/flatpak/runtime/org.kde.Platform/x86_64/6.
11/fb23e178d082b117df7924f9a84710992ec233ebc007385feb85d349c4c81415/files/lib/x86_64-linux-gnu/libglib-2.0.so.0.8400.4
#5 0x00007fcc5ed0f323 in g_main_context_iteration () from
/var/lib/flatpak/runtime/org.kde.Platform/x86_64/6.
11/fb23e178d082b117df7924f9a84710992ec233ebc007385feb85d349c4c81415/files/lib/x86_64-linux-gnu/libglib-2.0.so.0.8400.4
#6 0x00007fcc5f2fb93d in QEventDispatcherGlib::processEvents
(this=0x560e85d99ce0, flags=...) at /usr/lib/debug/source/org.kde.Sdk/qtbase.
bst/src/corelib/kernel/qeventdispatcher_glib.cpp:402
#7 0x00007fcc5efc219b in QEventLoop::exec (this=0x7fff2efa18d0, flags=...)
at /usr/lib/debug/source/org.kde.Sdk/qtbase.bst/src/corelib/global/qflags.h:78
#8 0x00007fcc63c5ff27 in QDialog::exec() () from
/var/lib/flatpak/runtime/org.kde.Platform/x86_64/6.
11/fb23e178d082b117df7924f9a84710992ec233ebc007385feb85d349c4c81415/files/lib/x86_64-linux-gnu/libQt6Widgets.so.6.11.3
#9 0x00007fcc659157e9 in KMessageBox::createKMessageBox(QDialog*,
QDialogButtonBox*, QIcon const&, QString const&, QList<QString> const&, QString
const&, bool*,
QFlags<KMessageBox::Option>, QString const&, QMessageBox::Icon) () from
/var/lib/flatpak/runtime/org.kde.Platform/x86_64/6.
11/fb23e178d082b117df7924f9a84710992ec233ebc007385feb85d349c4c81415/files/lib/x86_64-linux-gnu/libKF6WidgetsAddons.so.6.31.0
#10 0x00007fcc65916443 in KMessageBox::createKMessageBox(QDialog*,
QDialogButtonBox*, QMessageBox::Icon, QString const&, QList<QString> const&,
QString const&, bool*,
QFlags<KMessageBox::Option>, QString const&) () from
/var/lib/flatpak/runtime/org.kde.Platform/x86_64/6.
11/fb23e178d082b117df7924f9a84710992ec233ebc007385feb85d349c4c81415/files/lib/x86_64-linux-gnu/libKF6WidgetsAddons.so.6.31.0
#11 0x00007fcc65917781 in
KMessageBox::warningContinueCancelListInternal(QDialog*, QString const&,
QList<QString> const&, QString const&, KGuiItem const&, KGuiItem const&,
QString
const&, QFlags<KMessageBox::Option>, QString const&) () from
/var/lib/flatpak/runtime/org.kde.Platform/x86_64/6.
11/fb23e178d082b117df7924f9a84710992ec233ebc007385feb85d349c4c81415/files/lib/x86_64-linux-gnu/libKF6WidgetsAddons.so.6.31.0
#12 0x00007fcc6591796e in KMessageBox::warningContinueCancelList(QWidget*,
QString const&, QList<QString> const&, QString const&, KGuiItem const&,
KGuiItem const&, QString const&,
QFlags<KMessageBox::Option>) () from
/var/lib/flatpak/runtime/org.kde.Platform/x86_64/6.11/fb23e178d082b117df7924f9a84710992ec233ebc007385feb85d349c4c81415/files/lib/x86_64-linux-
gnu/libKF6WidgetsAddons.so.6.31.0
#13 0x00007fcc65917a1b in KMessageBox::warningContinueCancel(QWidget*,
QString const&, QString const&, KGuiItem const&, KGuiItem const&, QString
const&, QFlags<KMessageBox::Option>)
() from
/var/lib/flatpak/runtime/org.kde.Platform/x86_64/6.11/fb23e178d082b117df7924f9a84710992ec233ebc007385feb85d349c4c81415/files/lib/x86_64-linux-gnu/libKF6WidgetsAddons.so.6.31.0
#14 0x0000560e49e5eeab in
AbstractPythonInterface::installMissingDependencies (this=0x560e8bb3f410) at
/run/build/kdenlive/src/pythoninterfaces/abstractpythoninterface.cpp:621
#15 0x0000560e49c40b15 in operator() (__closure=0x560e8bb50790) at
/run/build/kdenlive/src/dialogs/settings/pluginssettings.cpp:92
#20
QtPrivate::QCallableObject<PluginsSettings::PluginsSettings(QWidget*)::<lambda()>,
QtPrivate::List<>, void>::impl(int, QtPrivate::QSlotObjectBase *, QObject *,
void **, bool *)
(which=<optimized out>, this_=0x560e8bb50780, r=<optimized out>, a=<optimized
out>, ret=<optimized out>) at /usr/include/QtCore/qobjectdefs_impl.h:548
#21 0x00007fcc5f024896 in QtPrivate::QSlotObjectBase::call
(this=0x560e8bb50780, r=0x560e86128c50, a=0x7fff2efa2010) at
/usr/lib/debug/source/org.kde.Sdk/qtbase.
bst/src/corelib/kernel/qobjectdefs_impl.h:462
#22 doActivate<false> (sender=0x560e8652c7f0, signal_index=<optimized out>,
argv=<optimized out>) at
/usr/lib/debug/source/org.kde.Sdk/qtbase.bst/src/corelib/kernel/qobject.cpp:4393
#23 0x00007fcc63af541a in QAbstractButton::clicked(bool) () from
/var/lib/flatpak/runtime/org.kde.Platform/x86_64/6.
11/fb23e178d082b117df7924f9a84710992ec233ebc007385feb85d349c4c81415/files/lib/x86_64-linux-gnu/libc.so.6
#45 0x0000560e494c3506 in main (argc=<optimized out>, argv=0x7fff2efa32d8)
at /run/build/kdenlive/src/main.cpp:567
REGISTERS & DISASSEMBLY AT CRASH (Thread 1)
rax 0xa 10
rbx 0x7fcc36dfdef0 140515070697200
rcx 0x61 97
rdx 0xa 10
rsi 0x560e8c52db40 94620483771200
rdi 0x560e8bb50780 94620473427840
rbp 0x7fcc36dfded0 0x7fcc36dfded0
rsp 0x7fcc36dfde18 0x7fcc36dfde18
r12 0x560e8c539d60 94620483820896
r13 0x7fff2efa1df0 140733981531632 <-- dangling `this`
(stack-allocated WhisperDownload)
r14 0x7fff2efa1e20 140733981531680
r15 0xa 10
rip 0x7fcc5fd890a2 0x7fcc5fd890a2
<QQmlData::isSignalConnected(QAbstractDeclarativeData*, QObject const*,
int)+18>
=> 0x7fcc5fd890a2
<_ZN8QQmlData17isSignalConnectedEP24QAbstractDeclarativeDataPK7QObjecti+18>:
mov (%rcx),%rcx
--
You are receiving this mail because:
You are watching all bug changes.