Bug 395765

Summary: Crash when closing okular
Product: [Applications] okular Reporter: Riccardo Escher <riccardoescher>
Component: generalAssignee: Okular developers <okular-devel>
Status: RESOLVED FIXED    
Severity: crash CC: bugs.kde.org, haxtibal, mail, marcelo.jimenez, oss+kde+bugzilla, ZigZag.g.h
Priority: NOR Keywords: drkonqi
Version: 1.4.2   
Target Milestone: ---   
Platform: openSUSE   
OS: Linux   
See Also: https://bugs.kde.org/show_bug.cgi?id=394534
Latest Commit: Version Fixed In: 18.12.0
Sentry Crash Report:

Description Riccardo Escher 2018-06-22 19:25:12 UTC
Application: okular (1.4.2)

Qt Version: 5.11.0
Frameworks Version: 5.46.0
Operating System: Linux 4.17.1-1-default x86_64
Distribution: "openSUSE Tumbleweed"

-- Information about the crash:
- What I was doing when the application crashed:
After shutdown and reboot a pdf downloaded by firefox was disappeared. Okular opened an error window. When closing this error window Okular crashes

-- Backtrace:
Application: Okular (okular), signal: Segmentation fault
Using host libthread_db library "/lib64/libthread_db.so.1".
[Current thread is 1 (Thread 0x7fcae9e48180 (LWP 3117))]

Thread 4 (Thread 0x7fcabfa54700 (LWP 3376)):
#0  0x00007fcae2b204ec in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
#1  0x00007fcac06dbc1b in ?? () from /usr/lib64/dri/i965_dri.so
#2  0x00007fcac06db947 in ?? () from /usr/lib64/dri/i965_dri.so
#3  0x00007fcae2b1a554 in start_thread () from /lib64/libpthread.so.0
#4  0x00007fcae5b94fdf in clone () from /lib64/libc.so.6

Thread 3 (Thread 0x7fcace2f6700 (LWP 3190)):
#0  0x00007fcae5b8a5d9 in poll () from /lib64/libc.so.6
#1  0x00007fcae04ff2c6 in ?? () from /usr/lib64/libglib-2.0.so.0
#2  0x00007fcae04ff3ec in g_main_context_iteration () from /usr/lib64/libglib-2.0.so.0
#3  0x00007fcae649790b in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () from /usr/lib64/libQt5Core.so.5
#4  0x00007fcae64479fb in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) () from /usr/lib64/libQt5Core.so.5
#5  0x00007fcae62a6356 in QThread::exec() () from /usr/lib64/libQt5Core.so.5
#6  0x00007fcae68e8f45 in ?? () from /usr/lib64/libQt5DBus.so.5
#7  0x00007fcae62af93c in ?? () from /usr/lib64/libQt5Core.so.5
#8  0x00007fcae2b1a554 in start_thread () from /lib64/libpthread.so.0
#9  0x00007fcae5b94fdf in clone () from /lib64/libc.so.6

Thread 2 (Thread 0x7fcad7d76700 (LWP 3123)):
#0  0x00007fcae5b8a5d9 in poll () from /lib64/libc.so.6
#1  0x00007fcae2f42377 in ?? () from /usr/lib64/libxcb.so.1
#2  0x00007fcae2f43f8a in xcb_wait_for_event () from /usr/lib64/libxcb.so.1
#3  0x00007fcadad50939 in ?? () from /usr/lib64/libQt5XcbQpa.so.5
#4  0x00007fcae62af93c in ?? () from /usr/lib64/libQt5Core.so.5
#5  0x00007fcae2b1a554 in start_thread () from /lib64/libpthread.so.0
#6  0x00007fcae5b94fdf in clone () from /lib64/libc.so.6

Thread 1 (Thread 0x7fcae9e48180 (LWP 3117)):
[KCrash Handler]
#6  QFlags<KEntryMap::SearchFlag>::operator|= (other=<optimized out>, this=<optimized out>) at /usr/src/debug/kconfig-5.46.0-1.2.x86_64/src/core/kconfig.cpp:976
#7  KConfigPrivate::lookupData (this=this@entry=0x560200050009, group=..., key=key@entry=0x564b554f6a4c "ActiveTab", flags=flags@entry=...) at /usr/src/debug/kconfig-5.46.0-1.2.x86_64/src/core/kconfig.cpp:977
#8  0x00007fcae82871f3 in KConfigGroup::readEntry (this=this@entry=0x7fff7e0e6d00, key=key@entry=0x564b554f6a4c "ActiveTab", aDefault=...) at /usr/include/qt5/QtCore/qflags.h:120
#9  0x0000564b554ee7c3 in KConfigGroup::readEntry<int> (defaultValue=@0x7fff7e0e6c4c: 0, key=0x564b554f6a4c "ActiveTab", this=0x7fff7e0e6d00) at /usr/include/qt5/QtCore/qvariant.h:518
#10 Shell::readProperties (this=0x564b574f43e0, group=...) at /usr/src/debug/okular-18.04.2-1.1.x86_64/shell/shell.cpp:392
#11 0x00007fcae8fb0b78 in KMainWindow::readPropertiesInternal (this=this@entry=0x564b574f43e0, config=0x564b5757dec0, number=number@entry=1) at /usr/include/qt5/QtCore/qarraydata.h:234
#12 0x00007fcae8fb0bc2 in KMainWindow::restore (this=0x564b574f43e0, number=1, show=<optimized out>) at /usr/src/debug/kxmlgui-5.46.0-1.3.x86_64/src/kmainwindow.cpp:471
#13 0x0000564b554e9cd3 in kRestoreMainWindows<Shell> () at /usr/include/qt5/QtCore/qarraydata.h:255
#14 0x0000564b554e7353 in main (argc=<optimized out>, argv=<optimized out>) at /usr/src/debug/okular-18.04.2-1.1.x86_64/shell/main.cpp:66

Reported using DrKonqi
Comment 1 Christoph Feck 2018-07-18 19:32:53 UTC
*** Bug 394707 has been marked as a duplicate of this bug. ***
Comment 2 Christoph Feck 2018-07-18 19:33:03 UTC
*** Bug 394429 has been marked as a duplicate of this bug. ***
Comment 3 Christoph Feck 2018-07-18 19:33:11 UTC
*** Bug 395684 has been marked as a duplicate of this bug. ***
Comment 4 Christoph Feck 2018-10-11 14:35:01 UTC
*** Bug 399207 has been marked as a duplicate of this bug. ***
Comment 5 Christoph Feck 2018-10-11 14:35:28 UTC
*** Bug 396783 has been marked as a duplicate of this bug. ***
Comment 6 Christoph Feck 2018-10-11 14:36:30 UTC
*** Bug 397737 has been marked as a duplicate of this bug. ***
Comment 7 Tobias Deiminger 2018-10-25 08:11:06 UTC
Just reproduced this on openSUSE Tumbleweed, will have a closer look next days. It never happened with okular master in my Ubuntu environment before. Obvious differences are newer versions of Qt5 and kconfig in the Tumbleweed configuration.
Comment 8 Tobias Deiminger 2018-10-26 13:22:24 UTC
Quite interesting. The crash is caused by a dangling KConfig* pointer inside the KConfigGroup that's passed to Shell::readProperties. The KConfig was deleted preliminary during Shell::openUrl(). There a QDialog event loop processed a XSMP "SaveYourself" message, and the related handler code eventually deleted a globally used KConfig instance.

It goes like this
1. KMainWindow::restore creates a KConfig *config = KConfigGui::sessionConfig(). This KConfig is managed singleton-like, see static KConfig *KConfigGui::s_sessionConfig.

2. KMainWindow::readPropertiesInternal constructs a KConfigGroup grp(config, ...) with that KConfig, and passes it on to Shell::readProperties (polymorphic call from framework to application).

3. The trouble begins in openUrl(). There we can't find a document, and spawn a QDialog for the "file not found" message. QDialog has an event loop that's stacked onto the application event loop.

It happens that ksmserver sent us an XSMP "SaveYourself" message (that's expected after client registration), which now gets processed by the QDialog event loop. We handle "SaveYourself" with KMWSessionManager::saveState => KConfigGui::setSessionConfig and hit the code
   if (hasSessionConfig()) { delete s_sessionConfig; s_sessionConfig = nullptr; }
Sadly, the old s_sessionConfig address is still stored in the KConfigGroup, where the pointer is dangling now.

4. Inside group.readEntry<int>( SESSION_TAB_KEY, 0 ) the dangling KConfig* is accessed, resulting in segfault.

I'm not yet sure how to fix it. Shall we discuss it with some KF5 guys? It seems a bit fragile if a framework passes some wrapped up pointer to application code, and said pointer can become invalid for non-obvious reasons.
Comment 9 Tobias Deiminger 2018-10-29 20:45:10 UTC
Git commit d1ea28fc7338c24910faff77c6308a3e4f32369a by Tobias Deiminger.
Committed on 29/10/2018 at 20:44.
Pushed by tobiasdeiminger into branch 'master'.

Avoid crash during session restore

Summary:
Do all access to the passed KConfigGroup really synchronous to KMainWindow::readProperties, then we're safe.

Currently kxmlgui can't guarantee that the passed KConfigGroup is still valid after our call to Shell::openUrl(). This is because inside Shell::openUrl, QDialog::exec may get called. The stacked event loop processes all kinds of asynchronous events, and litterally *anything* can happen. E.g. incoming ICE and DBus messages may be processed. In bug 395765 it happened that XSMP SafeYourself was processed, which calls KConfigGui::setSessionConfig, which leaves the KConfig pointer inside KConfigGroup dangling.

Test Plan:
- get recent Qt5 and KF5
- manually save desktop session while a document is open in okular
- modify ~/.config/session/okular_<sessionid> so that Urls points to non existing file
- manually restore session with okular -session <session_id>, dialog will open and warn about non existent file
- okular shall not crash after closing that dialog

Reviewers: aacid

Reviewed By: aacid

Subscribers: aacid, okular-devel

Tags: #okular

Differential Revision: https://phabricator.kde.org/D16457

M  +1    -1    shell/shell.cpp

https://commits.kde.org/okular/d1ea28fc7338c24910faff77c6308a3e4f32369a
Comment 10 Riccardo Escher 2018-10-30 20:59:12 UTC
Wow! Thank you very much!
Comment 11 Erik Quaeghebeur 2018-12-07 12:21:50 UTC
I'm constantly being hit by this in 1.5.3 (18.08.3). In what version is this fixed?