Bug 452814

Summary: Segfault when trying to copy DVD with `cdrecord` not installed
Product: [Applications] k3b Reporter: bence.csokas
Component: Video DVDAssignee: k3b developers <k3b>
Status: RESOLVED FIXED    
Severity: normal CC: michalm, omerusta, trueg
Priority: NOR    
Version: 21.12.3   
Target Milestone: ---   
Platform: Arch Linux   
OS: Linux   
Latest Commit: Version Fixed In:
Sentry Crash Report:

Description bence.csokas 2022-04-21 06:01:33 UTC
# Version info
I was using a freshly installed K3b 21.12.3 on Arch Linux
# What happened?
I clicked on "Tools > Copy medium", clicked on "Start", and the program abruptly closed. Further analysis revealed that a SIGSEGV was raised in `K3b::ExternalBin::hasFeature(QString const&) const ()`.
# What was expected?
That the program starts copying the disk, or (see later) that an error window pops up saying something like "Cdrecord/growisofs is required for this type of medium!"
# Root cause analysis
Running `k3b` in GDB, I printed the backtrace of the crash:
```
(gdb) bt
#0  0x00007ffff7e585a4 in K3b::ExternalBin::hasFeature(QString const&) const () at /usr/lib/libk3blib.so.7
#1  0x00007ffff7ebceff in K3b::DvdCopyJob::slotDiskInfoReady(K3b::Device::DeviceHandler*) () at /usr/lib/libk3blib.so.7
#2  0x00007ffff617b4af in  () at /usr/lib/libQt5Core.so.5
#3  0x00007ffff7e42484 in K3b::Device::DeviceHandler::finished(K3b::Device::DeviceHandler*) () at /usr/lib/libk3blib.so.7
#4  0x00007ffff7e6c8ae in K3b::Device::DeviceHandler::jobFinished(bool) () at /usr/lib/libk3blib.so.7
#5  0x00007ffff616e7d6 in QObject::event(QEvent*) () at /usr/lib/libQt5Core.so.5
#6  0x00007ffff6bc21c6 in QApplicationPrivate::notify_helper(QObject*, QEvent*) () at /usr/lib/libQt5Widgets.so.5
#7  0x00007ffff614a5aa in QCoreApplication::notifyInternal2(QObject*, QEvent*) () at /usr/lib/libQt5Core.so.5
#8  0x00007ffff614b0a9 in QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) () at /usr/lib/libQt5Core.so.5
#9  0x00007ffff6192678 in  () at /usr/lib/libQt5Core.so.5
#10 0x00007ffff0d81163 in g_main_context_dispatch () at /usr/lib/libglib-2.0.so.0
#11 0x00007ffff0dd79e9 in  () at /usr/lib/libglib-2.0.so.0
#12 0x00007ffff0d7e6c5 in g_main_context_iteration () at /usr/lib/libglib-2.0.so.0
#13 0x00007ffff619657a in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () at /usr/lib/libQt5Core.so.5
#14 0x00007ffff614288b in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) () at /usr/lib/libQt5Core.so.5
#15 0x00007ffff6dbc776 in QDialog::exec() () at /usr/lib/libQt5Widgets.so.5
#16 0x00005555556393a9 in  ()
#17 0x00007ffff617b4af in  () at /usr/lib/libQt5Core.so.5
#18 0x00007ffff6ca7167 in QAbstractButton::clicked(bool) () at /usr/lib/libQt5Widgets.so.5
#19 0x00007ffff6ca8fdc in  () at /usr/lib/libQt5Widgets.so.5
#20 0x00007ffff6cac7ca in  () at /usr/lib/libQt5Widgets.so.5
#21 0x00007ffff6cac998 in QAbstractButton::mouseReleaseEvent(QMouseEvent*) () at /usr/lib/libQt5Widgets.so.5
#22 0x00007ffff6bf83d6 in QWidget::event(QEvent*) () at /usr/lib/libQt5Widgets.so.5
#23 0x00007ffff6bc21c6 in QApplicationPrivate::notify_helper(QObject*, QEvent*) () at /usr/lib/libQt5Widgets.so.5
#24 0x00007ffff6bc6ff7 in QApplication::notify(QObject*, QEvent*) () at /usr/lib/libQt5Widgets.so.5
#25 0x00007ffff614a5aa in QCoreApplication::notifyInternal2(QObject*, QEvent*) () at /usr/lib/libQt5Core.so.5
#26 0x00007ffff6bc59bf in QApplicationPrivate::sendMouseEvent(QWidget*, QMouseEvent*, QWidget*, QWidget*, QWidget**, QPointer<QWidget>&, bool, bool) () at /usr/lib/libQt5Widgets.so.5
#27 0x00007ffff6c16937 in  () at /usr/lib/libQt5Widgets.so.5
#28 0x00007ffff6c184ec in  () at /usr/lib/libQt5Widgets.so.5
#29 0x00007ffff6bc21c6 in QApplicationPrivate::notify_helper(QObject*, QEvent*) () at /usr/lib/libQt5Widgets.so.5
#30 0x00007ffff614a5aa in QCoreApplication::notifyInternal2(QObject*, QEvent*) () at /usr/lib/libQt5Core.so.5
#31 0x00007ffff651f230 in QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent*) () at /usr/lib/libQt5Gui.so.5
#32 0x00007ffff650a6e5 in QWindowSystemInterface::sendWindowSystemEvents(QFlags<QEventLoop::ProcessEventsFlag>) () at /usr/lib/libQt5Gui.so.5
#33 0x00007fffec979f60 in  () at /usr/lib/libQt5XcbQpa.so.5
#34 0x00007ffff0d81163 in g_main_context_dispatch () at /usr/lib/libglib-2.0.so.0
#35 0x00007ffff0dd79e9 in  () at /usr/lib/libglib-2.0.so.0
#36 0x00007ffff0d7e6c5 in g_main_context_iteration () at /usr/lib/libglib-2.0.so.0
#37 0x00007ffff619657a in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () at /usr/lib/libQt5Core.so.5
#38 0x00007ffff614288b in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) () at /usr/lib/libQt5Core.so.5
#39 0x00007ffff6dbc776 in QDialog::exec() () at /usr/lib/libQt5Widgets.so.5
#40 0x00005555556048ca in  ()
#41 0x00007ffff617b4af in  () at /usr/lib/libQt5Core.so.5
#42 0x00007ffff6bb5417 in QAction::triggered(bool) () at /usr/lib/libQt5Widgets.so.5
#43 0x00007ffff6bbaee0 in QAction::activate(QAction::ActionEvent) () at /usr/lib/libQt5Widgets.so.5
#44 0x00007ffff6d3d4c3 in  () at /usr/lib/libQt5Widgets.so.5
#45 0x00007ffff6d3d5a1 in  () at /usr/lib/libQt5Widgets.so.5
#46 0x00007ffff6bf83d6 in QWidget::event(QEvent*) () at /usr/lib/libQt5Widgets.so.5
#47 0x00007ffff6bc21c6 in QApplicationPrivate::notify_helper(QObject*, QEvent*) () at /usr/lib/libQt5Widgets.so.5
#48 0x00007ffff6bc6ff7 in QApplication::notify(QObject*, QEvent*) () at /usr/lib/libQt5Widgets.so.5
#49 0x00007ffff614a5aa in QCoreApplication::notifyInternal2(QObject*, QEvent*) () at /usr/lib/libQt5Core.so.5
--Type <RET> for more, q to quit, c to continue without paging--q
```

Googling revealed that this is most likely caused by a `*this` pointer being NULL (i.e. function call on a NULLed object), so I moved on to frame 2. Cross-referencing the code, the most likely suspect of the crash was this line: https://invent.kde.org/multimedia/k3b/-/blob/master/libk3b/jobs/k3bdvdcopyjob.cpp#L166

With this, I figured out that `cdrecord` and `growisofs` need to be installed, after which I was able to go on with the copying. It also turns out that on start-up, K3b spat out a dialog box complaining about these missing tools, plus some others unrelated to this (like `cdrdao`), but it opened on an other screen that I didn't see. But, by pressing ESC, I was able to proceed.

So, my question is, why was I able to proceed with CRITICAL dependencies missing? And if these tools are NOT critical, why does the code down the line not check if they exist (i.e. a NULL check for `k3bcore->externalBinManager()->binObject("cdrecord")` in the offending lines, or a dummy object instead of NULL)? IMHO, a segfault is not a very helpful way to convey to the user that someting is missing, especially a dependency that can be solved by one line of `pacman -S`/`apt install`/whatever.
Comment 1 Ömer Fadıl USTA 2022-04-21 22:29:25 UTC
Hello bence.csokas , i have prepared a patch for your bug report, i will be glad if you have time to give a try if it accepted

https://invent.kde.org/multimedia/k3b/-/merge_requests/30
Comment 2 Albert Astals Cid 2022-06-09 09:30:38 UTC
Git commit 0ede72063c38c103acf72ce513185a3cc760fac4 by Albert Astals Cid, on behalf of Ömer Fadıl Usta.
Committed on 09/06/2022 at 09:30.
Pushed by aacid into branch 'master'.

Add extra checks for externalbins

Fix some possible calls over null objects
Shorten the repeated parts

M  +2    -2    libk3b/jobs/k3bcdcopyjob.cpp
M  +1    -1    libk3b/jobs/k3bclonejob.cpp
M  +9    -9    libk3b/jobs/k3bdvdcopyjob.cpp
M  +9    -8    libk3b/jobs/k3bmetawriter.cpp
M  +9    -9    libk3b/projects/audiocd/k3baudiojob.cpp
M  +6    -8    libk3b/projects/datacd/k3bdatajob.cpp
M  +10   -7    libk3b/projects/datacd/k3bisoimager.cpp
M  +11   -9    libk3b/projects/mixedcd/k3bmixedjob.cpp
M  +10   -8    src/k3bsystemproblemdialog.cpp
M  +4    -3    src/projects/k3baudioburndialog.cpp
M  +4    -3    src/projects/k3bmixedburndialog.cpp

https://invent.kde.org/multimedia/k3b/commit/0ede72063c38c103acf72ce513185a3cc760fac4