Bug 473324

Summary: KPhotoAlbum crashes when Jump to Context is used in Thumbnail Viewer with zero thumbnails
Product: [Applications] kphotoalbum Reporter: Victor Lobo <victor.ip.lobo>
Component: Thumbnail ViewerAssignee: KPhotoAlbum Bugs <kpabugs>
Status: RESOLVED FIXED    
Severity: crash CC: 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-13 01:41:53 UTC
SUMMARY
KPhotoAlbum crashes when Jump to Context is used in Thumbnail Viewer with zero thumbnails.


STEPS TO REPRODUCE
1. Open KPhotoAlbum
2. Click Show Thumbnails (notice no thumbnail selected by default)
3. Click View --> Limit View to Selection (notice no thumbnails displayed)
4. Click View --> Jump to Context
5. KPhotoAlbum crashes

OBSERVED RESULT
Crash

EXPECTED RESULT
No crash

SOFTWARE/OS VERSIONS
Linux: openSUSE Tumbleweed 20230807; Kernel Version: 6.4.8-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-54-g1b4d199e

ADDITIONAL INFORMATION
1. Crash is reproducible every time the steps are followed.
2. Provided above is easiest way to reproduce the crash. However, applying Jump to Context from other pathways that lead to Thumbnail Viewer with zero thumbnails will also cause crash. For example another pathway could be (assuming no untagged images): Click "Untagged Images" and then "Click View --> Jump to Context"
3. Crash occurs even in the demo database



GDB Backtrace:
Application: KPhotoAlbum (kphotoalbum), signal: Aborted

[KCrash Handler]
#4  0x00007f3442e92abc in __pthread_kill_implementation () from /lib64/libc.so.6
#5  0x00007f3442e41266 in raise () from /lib64/libc.so.6
#6  0x00007f3442e29897 in abort () from /lib64/libc.so.6
#7  0x00007f34434bb4f9 in qt_message_fatal (message=<synthetic pointer>..., context=...) at global/qlogging.cpp:1914
#8  QMessageLogger::fatal (this=this@entry=0x7ffe57a260b8, msg=msg@entry=0x7f34437d2000 "ASSERT: \"%s\" in file %s, line %d") at global/qlogging.cpp:893
#9  0x00007f34434ba730 in qt_assert (assertion=<optimized out>, file=<optimized out>, line=<optimized out>) at global/qglobal.cpp:3391
#10 0x00000000004b9a4a in ThumbnailView::ThumbnailModel::imageAt (this=0x155d550, index=-1) at /home/victor/Downloads/kphotoalbum/ThumbnailView/ThumbnailModel.cpp:267
#11 0x00000000004c7cbc in ThumbnailView::ThumbnailFacade::currentItem (this=0x15d1030) at /home/victor/Downloads/kphotoalbum/ThumbnailView/ThumbnailFacade.cpp:86
#12 0x0000000000540dc4 in MainWindow::Window::slotJumpToContext (this=0x13ccf00) at /home/victor/Downloads/kphotoalbum/MainWindow/Window.cpp:1669
#13 0x000000000054b202 in QtPrivate::FunctorCall<QtPrivate::IndexesList<>, QtPrivate::List<>, void, void (MainWindow::Window::*)()>::call(void (MainWindow::Window::*)(), MainWindow::Window*, void**) (f=(void (MainWindow::Window::*)(MainWindow::Window * const)) 0x540da0 <MainWindow::Window::slotJumpToContext()>, o=0x13ccf00, arg=0x7ffe57a26360) at /usr/include/qt5/QtCore/qobjectdefs_impl.h:152
#14 0x000000000054a97b in QtPrivate::FunctionPointer<void (MainWindow::Window::*)()>::call<QtPrivate::List<>, void>(void (MainWindow::Window::*)(), MainWindow::Window*, void**) (f=(void (MainWindow::Window::*)(MainWindow::Window * const)) 0x540da0 <MainWindow::Window::slotJumpToContext()>, o=0x13ccf00, arg=0x7ffe57a26360) at /usr/include/qt5/QtCore/qobjectdefs_impl.h:185
#15 0x0000000000549233 in QtPrivate::QSlotObject<void (MainWindow::Window::*)(), QtPrivate::List<>, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*) (which=1, this_=0x15d4db0, r=0x13ccf00, a=0x7ffe57a26360, ret=0x0) at /usr/include/qt5/QtCore/qobjectdefs_impl.h:418
#16 0x00007f34437257a2 in QtPrivate::QSlotObjectBase::call (a=0x7ffe57a26360, r=0x13ccf00, this=0x15d4db0) at ../../include/QtCore/../../src/corelib/kernel/qobjectdefs_impl.h:398
#17 doActivate<false> (sender=0x15739c0, signal_index=4, argv=0x7ffe57a26360) at kernel/qobject.cpp:3925
#18 0x00007f344371e40f in QMetaObject::activate (sender=sender@entry=0x15739c0, m=m@entry=0x7f34448bacc0 <QAction::staticMetaObject>, local_signal_index=local_signal_index@entry=1, argv=argv@entry=0x7ffe57a26360) at kernel/qobject.cpp:3985
#19 0x00007f344439e8b2 in QAction::triggered (this=this@entry=0x15739c0, _t1=<optimized out>) at .moc/moc_qaction.cpp:376
#20 0x00007f34443a142f in QAction::activate (this=0x15739c0, event=<optimized out>) at kernel/qaction.cpp:1161
#21 0x00007f3444525ef2 in QMenuPrivate::activateCausedStack (this=this@entry=0x1697300, causedStack=..., action=action@entry=0x15739c0, action_e=action_e@entry=QAction::Trigger, self=self@entry=true) at widgets/qmenu.cpp:1384
#22 0x00007f344452dd23 in QMenuPrivate::activateAction (this=0x1697300, action=0x15739c0, action_e=QAction::Trigger, self=true) at widgets/qmenu.cpp:1461
#23 0x00007f34443e6d68 in QWidget::event (this=0x15d7150, event=0x7ffe57a26950) at kernel/qwidget.cpp:9045
#24 0x00007f34443a519e in QApplicationPrivate::notify_helper (this=this@entry=0x10f8c90, receiver=receiver@entry=0x15d7150, e=e@entry=0x7ffe57a26950) at kernel/qapplication.cpp:3640
#25 0x00007f34443ad5cf in QApplication::notify (this=<optimized out>, receiver=<optimized out>, e=0x7ffe57a26950) at kernel/qapplication.cpp:3084
#26 0x00007f34436ed4f8 in QCoreApplication::notifyInternal2 (receiver=0x15d7150, event=0x7ffe57a26950) at kernel/qcoreapplication.cpp:1064
#27 0x00007f34436ed6ce in QCoreApplication::sendSpontaneousEvent (receiver=<optimized out>, event=<optimized out>) at kernel/qcoreapplication.cpp:1474
#28 0x00007f34443ab92e in QApplicationPrivate::sendMouseEvent (receiver=0x15d7150, event=event@entry=0x7ffe57a26950, alienWidget=<optimized out>, nativeWidget=0x15d7150, buttonDown=buttonDown@entry=0x7f34448f2330 <qt_button_down>, lastMouseReceiver=..., spontaneous=true, onlyDispatchEnterLeave=false) at kernel/qapplication.cpp:2622
#29 0x00007f34444002ca in QWidgetWindow::handleMouseEvent (this=this@entry=0x161bb10, event=event@entry=0x7ffe57a26c00) at kernel/qwidgetwindow.cpp:580
#30 0x00007f3444402d1f in QWidgetWindow::event (this=0x161bb10, event=0x7ffe57a26c00) at kernel/qwidgetwindow.cpp:300
#31 0x00007f34443a519e in QApplicationPrivate::notify_helper (this=<optimized out>, receiver=0x161bb10, e=0x7ffe57a26c00) at kernel/qapplication.cpp:3640
#32 0x00007f34436ed4f8 in QCoreApplication::notifyInternal2 (receiver=0x161bb10, event=0x7ffe57a26c00) at kernel/qcoreapplication.cpp:1064
#33 0x00007f3443b7d12b in QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent*) () from /lib64/libQt5Gui.so.5
#34 0x00007f3443b503ac in QWindowSystemInterface::sendWindowSystemEvents(QFlags<QEventLoop::ProcessEventsFlag>) () from /lib64/libQt5Gui.so.5
#35 0x00007f3438b1b1aa in ?? () from /lib64/libQt5XcbQpa.so.5
#36 0x00007f344092b988 in g_main_context_dispatch () from /lib64/libglib-2.0.so.0
#37 0x00007f344092bd98 in ?? () from /lib64/libglib-2.0.so.0
#38 0x00007f344092be2c in g_main_context_iteration () from /lib64/libglib-2.0.so.0
#39 0x00007f3443746496 in QEventDispatcherGlib::processEvents (this=0x11dddf0, flags=...) at kernel/qeventdispatcher_glib.cpp:423
#40 0x00007f34436ebf8b in QEventLoop::exec (this=this@entry=0x7ffe57a26f30, flags=..., flags@entry=...) at ../../include/QtCore/../../src/corelib/global/qflags.h:69
#41 0x00007f34436f4420 in QCoreApplication::exec () at ../../include/QtCore/../../src/corelib/global/qflags.h:121
#42 0x0000000000471840 in main (argc=2, argv=0x7ffe57a27638) at /home/victor/Downloads/kphotoalbum/main.cpp:161
[Inferior 1 (process 22157) detached]
Comment 1 Tobias Leupold 2023-08-13 10:42:16 UTC
Dang, you're quite good finding crashes ;-) Can be produced with the demo database this way. I'll have a look into this!
Comment 2 Tobias Leupold 2023-08-13 11:11:05 UTC
Git commit 8d3021ecb5aee71471349241d07b641f772a4171 by Tobias Leupold.
Committed on 13/08/2023 at 13:10.
Pushed by tleupold into branch 'master'.

Disable show selection only if there's no selection

M  +1    -0    CHANGELOG.md
M  +7    -1    MainWindow/Window.cpp
M  +4    -0    ThumbnailView/ThumbnailFacade.cpp

https://invent.kde.org/graphics/kphotoalbum/-/commit/8d3021ecb5aee71471349241d07b641f772a4171
Comment 3 Tobias Leupold 2023-08-13 11:16:57 UTC
This does two things. It prevents the crash itself by checking if there IS actually a selection in ThumbnailFacade::currentItem(), so that the model won't be queried with an invalid index.

This still lead to unexpected behavior: Showing only the selection for no selection did show (as expected) nothing. But when clicking "Show context" afterwards, there would still nothing be shown.

Thus I decided to prevent showing only the selection for nothing at all, the user will see a message that nothing is selected (so nobody wonders why nothing happens when clicking this, one could think that frame is already a selection). This way, we won't reach the code that actually caused the crash anymore. But still, it's not a bad idea to fix the root cause ;-)

@Victor Lobo: If you mess with geotagging your photos, maybe you want to have a look at KGeoTag as well? I'm pretty sure a lot of crashes are hidden in there as well ;-)
Comment 4 Victor Lobo 2023-08-14 00:22:26 UTC
Thank you! Fix works well. Thanks for fixing both issues; the root cause fix is necessary because it also addresses the other pathways which do not rely on Limit View to Selection (such as placing cursor in Search... field in Thumbnail View and then hitting Jump to Context).

Thanks for introducing me to KGeoTag. I am not currently doing any manual geotagging since my cameras record gps co-ordinates. But I will try it out for fixing old images.
Comment 5 Tobias Leupold 2023-08-14 06:58:56 UTC
Nice, thank you :-)