Bug 473762

Summary: KPhotoAlbum crashes when Viewer and Annotations is open and then user right-clicks Show Info in Viewer
Product: [Applications] kphotoalbum Reporter: Victor Lobo <victor.ip.lobo>
Component: ViewerAssignee: KPhotoAlbum Bugs <kpabugs>
Status: VERIFIED FIXED    
Severity: crash CC: johannes, tl
Priority: NOR    
Version: GIT master   
Target Milestone: ---   
Platform: openSUSE   
OS: Linux   
Latest Commit: Version Fixed In:
Sentry Crash Report:

Description Victor Lobo 2023-08-25 22:06:51 UTC
SUMMARY
KPhotoAlbum crashes when Viewer and Annotations is open and then user right-clicks Show Info in Viewer


STEPS TO REPRODUCE
1. Open KPhotoAlbum
2. Go to Thumbnail View
3. Open any Image in Viewer
4. From Viewer open Annotations window (Ctrl 1)
5. Go back to Viewer and Right-Click
6. Go to Show Info in the right-click context menu. Observe that Annotations window gets automatically closed now.
8. Click anywhere on Viewer (or anywhere really)
9. Crash

OBSERVED RESULT
Crash

EXPECTED RESULT
No crash

SOFTWARE/OS VERSIONS
Linux: openSUSE Tumbleweed 20230816; Kernel Version: 6.4.9-1-default (64-bit)
KDE Plasma Version: 5.27.7
KDE Frameworks Version: 5.108.0
Qt Version: 5.15.10
KPhotoAlbum Version 5.11.0 (as installed from Opensuse Tumbleweed repository)
Also occurs in latest git version v5.11.0-70-gffaaaad0

ADDITIONAL INFORMATION
1. Crash is reproducible every time the steps are followed.
2. Crash occurs even in the demo database.
3. Crash occurs for Images and Videos.


Backtrace:
Application: KPhotoAlbum (kphotoalbum), signal: Segmentation fault

[KCrash Handler]
#4  std::__atomic_base<int>::load (__m=std::memory_order_relaxed, this=0x9292929292929292) at /usr/include/c++/13/bits/atomic_base.h:505
#5  QAtomicOps<int>::loadRelaxed<int> (_q_value=<error reading variable: Cannot access memory at address 0x9292929292929292>) at /usr/include/qt5/QtCore/qatomic_cxx11.h:239
#6  0x000000000046ea0c in QBasicAtomicInteger<int>::loadRelaxed (this=0x9292929292929292) at /usr/include/qt5/QtCore/qbasicatomic.h:107
#7  0x00000000004723dc in QtPrivate::RefCount::isShared (this=0x9292929292929292) at /usr/include/qt5/QtCore/qrefcount.h:101
#8  0x00000000005f1271 in QList<QDockWidget*>::detach (this=0x128f590) at /usr/include/qt5/QtCore/qlist.h:178
#9  0x00000000005ef0a4 in QList<QDockWidget*>::begin (this=0x128f590) at /usr/include/qt5/QtCore/qlist.h:338
#10 0x00000000005e6dd0 in AnnotationDialog::Dialog::hideTornOfWindows (this=0x128f440) at /home/victor/Downloads/kphotoalbum/AnnotationDialog/Dialog.cpp:983
#11 0x00000000005e697d in AnnotationDialog::Dialog::exec (this=0x128f440) at /home/victor/Downloads/kphotoalbum/AnnotationDialog/Dialog.cpp:952
#12 0x00000000005e4c0d in AnnotationDialog::Dialog::configure (this=0x128f440, list=..., oneAtATime=true) at /home/victor/Downloads/kphotoalbum/AnnotationDialog/Dialog.cpp:761
#13 0x000000000053409f in MainWindow::Window::configImages (this=0x10ea660, list=..., oneAtATime=true) at /home/victor/Downloads/kphotoalbum/MainWindow/Window.cpp:509
#14 0x000000000053403d in MainWindow::Window::configureImages (list=..., oneAtATime=true) at /home/victor/Downloads/kphotoalbum/MainWindow/Window.cpp:503
#15 0x00000000004d7cd5 in operator() (__closure=0x7f69140063b0) at /home/victor/Downloads/kphotoalbum/Viewer/ViewerWidget.cpp:905
#16 0x00000000004dead3 in QtPrivate::FunctorCall<QtPrivate::IndexesList<>, QtPrivate::List<>, void, Viewer::ViewerWidget::editImage()::<lambda()> >::call(struct {...} &, void **) (f=..., arg=0x1ac2ec8) at /usr/include/qt5/QtCore/qobjectdefs_impl.h:146
#17 0x00000000004de9bf in QtPrivate::Functor<Viewer::ViewerWidget::editImage()::<lambda()>, 0>::call<QtPrivate::List<>, void>(struct {...} &, void *, void **) (f=..., arg=0x1ac2ec8) at /usr/include/qt5/QtCore/qobjectdefs_impl.h:256
#18 0x00000000004de8d4 in QtPrivate::QFunctorSlotObject<Viewer::ViewerWidget::editImage()::<lambda()>, 0, QtPrivate::List<>, void>::impl(int, QtPrivate::QSlotObjectBase *, QObject *, void **, bool *) (which=1, this_=0x7f69140063a0, r=0xe138d0, a=0x1ac2ec8, ret=0x0) at /usr/include/qt5/QtCore/qobjectdefs_impl.h:443
#19 0x00007f692c919320 in QObject::event (this=0xe138d0, e=0x1ac2e80) at kernel/qobject.cpp:1347
#20 0x00007f692d5a519e in QApplicationPrivate::notify_helper (this=<optimized out>, receiver=0xe138d0, e=0x1ac2e80) at kernel/qapplication.cpp:3640
#21 0x00007f692c8ed568 in QCoreApplication::notifyInternal2 (receiver=0xe138d0, event=0x1ac2e80) at kernel/qcoreapplication.cpp:1064
#22 0x00007f692c8ed72e in QCoreApplication::sendEvent (receiver=<optimized out>, event=<optimized out>) at kernel/qcoreapplication.cpp:1462
#23 0x00007f692c8f0b61 in QCoreApplicationPrivate::sendPostedEvents (receiver=0x0, event_type=0, data=0xe13850) at kernel/qcoreapplication.cpp:1821
#24 0x00007f692c8f10a8 in QCoreApplication::sendPostedEvents (receiver=<optimized out>, event_type=<optimized out>) at kernel/qcoreapplication.cpp:1680
#25 0x00007f692c946c93 in postEventSourceDispatch (s=0xef5510) at kernel/qeventdispatcher_glib.cpp:277
#26 0x00007f69295169b8 in g_main_context_dispatch () from /lib64/libglib-2.0.so.0
#27 0x00007f6929516dc8 in ?? () from /lib64/libglib-2.0.so.0
#28 0x00007f6929516e5c in g_main_context_iteration () from /lib64/libglib-2.0.so.0
#29 0x00007f692c9464a6 in QEventDispatcherGlib::processEvents (this=0xefaa00, flags=...) at kernel/qeventdispatcher_glib.cpp:423
#30 0x00007f692c8ebffb in QEventLoop::exec (this=this@entry=0x7fff38296670, flags=..., flags@entry=...) at ../../include/QtCore/../../src/corelib/global/qflags.h:69
#31 0x00007f692c8f4490 in QCoreApplication::exec () at ../../include/QtCore/../../src/corelib/global/qflags.h:121
#32 0x0000000000471840 in main (argc=2, argv=0x7fff38296d78) at /home/victor/Downloads/kphotoalbum/main.cpp:161
[Inferior 1 (process 21568) detached]
Comment 1 Johannes Zarl-Zierl 2023-08-27 20:16:23 UTC
With your description and the stack trace I could reproduce the bug.

I assume that you do have the annotation dialog configured with a floating dock window? At least on my system, I initially failed to reproduce until I looked at the stack trace and tried with a floating window...
Comment 2 Victor Lobo 2023-08-27 23:24:47 UTC
Since I am not sure, I assume that "floating dock window" means clicking the "diamond" icon to "pop out" a component in the Annotation window. 

If I assume correctly, then NO, I do not have the annotation dialog configured with a floating dock window. I am using the out-of-the-box as-installed by default Annotation dialog. 

What I observe is:
1. If I delete the "layout.dat" file in KPA base directory and restart KPA, I can still reproduce the bug.
2. I can reproduce the bug with floating and without floating windows.

I do want to note  that very infrequently (1 out of 25 times maybe) the steps 1-9 to reproduce may not cause a crash. This could be possibly why you failed to reproduce the bug initially. However, in such a case going back to step 3 and following the steps again always cause a crash for me.
Comment 3 Tobias Leupold 2023-08-28 06:15:29 UTC
First: I'm bitching here without helping, as I'm on vacation and the internet is quite bad. So I can't really help to debug this at the moment ;-)

But I just noticed (again) one thing, not regarding this specific crash: Why do we even store the dock window configuration in that said layout.dat file, and not in the configuration? Is that a remnant from old times, or is there a specific reason to do so?

Thanks for working on this @all :-)
Comment 4 Johannes Zarl-Zierl 2023-08-28 19:59:38 UTC
@Victor: Thanks for the clarification!

@Tobias: The main reason is that this is binary data. We use the method QMainWindow::saveState[1], which returns a QByteArray containing the state.
[1] https://doc.qt.io/qt-5/qmainwindow.html#saveState
Comment 5 Tobias Leupold 2023-08-28 20:49:51 UTC
Yeah, of course – but we can store the QByteArray in a QConfig/KConfig without a problem. We actually already do so (cf. MainWindow/State). Well, but that's another question that we should maybe discuss elsewhere. I don't want to hijack the bug ;-) Maybe I should simply implement storing that in the config (and also moving possibly existing layout data) in a branch so that you can check it out.

However thanks again and kudos to Victor for finding another crash and writing another useful bug report :-D
Comment 6 Johannes Zarl-Zierl 2023-08-28 22:58:17 UTC
Git commit 70a6f27f7312a0c4a296a788f5b008ee58fcb1d4 by Johannes Zarl-Zierl.
Committed on 29/08/2023 at 00:33.
Pushed by johanneszarl into branch 'master'.

Fix crash when the AnnotationDialog is deleted while open

If the annotation dialog is open and the
DB::CategoryCollection::categoryCollectionChanged signal is triggered,
the dialog is deleted.
The anotation dialog tries to hide any floating dock widgets after
closing, but at that point, it has already been deleted and invalidated
memory is accessed.

M  +2    -0    AnnotationDialog/Dialog.cpp

https://invent.kde.org/graphics/kphotoalbum/-/commit/70a6f27f7312a0c4a296a788f5b008ee58fcb1d4
Comment 7 Victor Lobo 2023-08-29 01:12:56 UTC
Re-opening this bug since the fix does not work for me. I get a crash after doing the same steps. However, this time the backtrace is slightly different.

kphotoalbum v5.11.0-76-g603af9a9


Backtrace:
Application: KPhotoAlbum (kphotoalbum), signal: Segmentation fault

[KCrash Handler]
#4  QListData::begin (this=0x1eab190) at /usr/include/qt5/QtCore/qlist.h:118
#5  0x00000000005ef4b8 in QList<QDockWidget*>::begin (this=0x1eab190) at /usr/include/qt5/QtCore/qlist.h:339
#6  0x00000000005e7062 in AnnotationDialog::Dialog::hideFloatingWindows (this=0x1eab040) at /home/victor/Downloads/kphotoalbum/AnnotationDialog/Dialog.cpp:987
#7  0x00000000005e6b0f in AnnotationDialog::Dialog::exec (this=0x1eab040) at /home/victor/Downloads/kphotoalbum/AnnotationDialog/Dialog.cpp:953
#8  0x00000000005e4d9f in AnnotationDialog::Dialog::configure (this=0x1eab040, list=..., oneAtATime=true) at /home/victor/Downloads/kphotoalbum/AnnotationDialog/Dialog.cpp:762
#9  0x00000000005340d9 in MainWindow::Window::configImages (this=0x1ccc1b0, list=..., oneAtATime=true) at /home/victor/Downloads/kphotoalbum/MainWindow/Window.cpp:509
#10 0x0000000000534077 in MainWindow::Window::configureImages (list=..., oneAtATime=true) at /home/victor/Downloads/kphotoalbum/MainWindow/Window.cpp:503
#11 0x00000000004d7d0f in operator() (__closure=0x7f6dd8006b00) at /home/victor/Downloads/kphotoalbum/Viewer/ViewerWidget.cpp:907
#12 0x00000000004deb0d in QtPrivate::FunctorCall<QtPrivate::IndexesList<>, QtPrivate::List<>, void, Viewer::ViewerWidget::editImage()::<lambda()> >::call(struct {...} &, void **) (f=..., arg=0x236a158) at /usr/include/qt5/QtCore/qobjectdefs_impl.h:146
#13 0x00000000004de9f9 in QtPrivate::Functor<Viewer::ViewerWidget::editImage()::<lambda()>, 0>::call<QtPrivate::List<>, void>(struct {...} &, void *, void **) (f=..., arg=0x236a158) at /usr/include/qt5/QtCore/qobjectdefs_impl.h:256
#14 0x00000000004de90e in QtPrivate::QFunctorSlotObject<Viewer::ViewerWidget::editImage()::<lambda()>, 0, QtPrivate::List<>, void>::impl(int, QtPrivate::QSlotObjectBase *, QObject *, void **, bool *) (which=1, this_=0x7f6dd8006af0, r=0x19f58d0, a=0x236a158, ret=0x0) at /usr/include/qt5/QtCore/qobjectdefs_impl.h:443
#15 0x00007f6df3f19320 in QObject::event (this=0x19f58d0, e=0x236a110) at kernel/qobject.cpp:1347
#16 0x00007f6df4ba519e in QApplicationPrivate::notify_helper (this=<optimized out>, receiver=0x19f58d0, e=0x236a110) at kernel/qapplication.cpp:3640
#17 0x00007f6df3eed568 in QCoreApplication::notifyInternal2 (receiver=0x19f58d0, event=0x236a110) at kernel/qcoreapplication.cpp:1064
#18 0x00007f6df3eed72e in QCoreApplication::sendEvent (receiver=<optimized out>, event=<optimized out>) at kernel/qcoreapplication.cpp:1462
#19 0x00007f6df3ef0b61 in QCoreApplicationPrivate::sendPostedEvents (receiver=0x0, event_type=0, data=0x19f5850) at kernel/qcoreapplication.cpp:1821
#20 0x00007f6df3ef10a8 in QCoreApplication::sendPostedEvents (receiver=<optimized out>, event_type=<optimized out>) at kernel/qcoreapplication.cpp:1680
#21 0x00007f6df3f46c93 in postEventSourceDispatch (s=0x1ad6e80) at kernel/qeventdispatcher_glib.cpp:277
#22 0x00007f6df0b169b8 in g_main_context_dispatch () from /lib64/libglib-2.0.so.0
#23 0x00007f6df0b16dc8 in ?? () from /lib64/libglib-2.0.so.0
#24 0x00007f6df0b16e5c in g_main_context_iteration () from /lib64/libglib-2.0.so.0
#25 0x00007f6df3f464a6 in QEventDispatcherGlib::processEvents (this=0x1adc420, flags=...) at kernel/qeventdispatcher_glib.cpp:423
#26 0x00007f6df3eebffb in QEventLoop::exec (this=this@entry=0x7ffceb2dcee0, flags=..., flags@entry=...) at ../../include/QtCore/../../src/corelib/global/qflags.h:69
#27 0x00007f6df3ef4490 in QCoreApplication::exec () at ../../include/QtCore/../../src/corelib/global/qflags.h:121
#28 0x0000000000471850 in main (argc=2, argv=0x7ffceb2dd5e8) at /home/victor/Downloads/kphotoalbum/main.cpp:161
[Inferior 1 (process 15534) detached]
Comment 8 Johannes Zarl-Zierl 2023-08-29 22:15:20 UTC
Git commit b0574aeeb0abbf4a1bbbe42e9623b21ff1c00006 by Johannes Zarl-Zierl.
Committed on 30/08/2023 at 00:08.
Pushed by johanneszarl into branch 'master'.

Fix crash when annotationdialog is deleted while open (take 2).

This commit takes a different approach than commit 70a6f27f, which
avoids coping with already deleted objects altogether.
Therefore, this should be a far more robust approach to fixing the bug.

M  +14   -5    AnnotationDialog/Dialog.cpp
M  +3    -1    AnnotationDialog/Dialog.h

https://invent.kde.org/graphics/kphotoalbum/-/commit/b0574aeeb0abbf4a1bbbe42e9623b21ff1c00006
Comment 9 Johannes Zarl-Zierl 2023-08-29 22:17:46 UTC
How about now? The new fix is not only more elegant but hopefully more robust as well...
Comment 10 Victor Lobo 2023-08-29 23:35:20 UTC
Yes. This fixes the crash. Thank you!