Bug 424882

Summary: The kdevelop crashed if create, rename and save new files
Product: [Applications] kdevelop Reporter: flashyan83
Component: file createAssignee: kdevelop-bugs-null
Status: RESOLVED FIXED    
Severity: normal CC: igorkuo, tarcisio.fischer.cco
Priority: NOR    
Version First Reported In: 5.5.2   
Target Milestone: ---   
Platform: Ubuntu   
OS: Linux   
Latest Commit: Version Fixed/Implemented In: 5.13.231200
Sentry Crash Report:

Description flashyan83 2020-08-01 03:42:50 UTC
SUMMARY


STEPS TO REPRODUCE
1. click new button in files tools.
2. input some content in the unnamed file;
3. click close tab;
4. choose yes in the close document dialog;
5. input one file anme and click save button;
6. kdevelop will crash

OBSERVED RESULT
crashed.

EXPECTED RESULT
no errors.

SOFTWARE/OS VERSIONS
Windows: 
macOS: 
Linux/KDE Plasma: ubuntu 20.04.1 LTS 
(available in About System)
KDE Plasma Version: 
KDE Frameworks Version: 
Qt Version: 

ADDITIONAL INFORMATION
I run the image file. ./KDevelop.AppImage. it is downloaded from kdevelop site.
Comment 1 Milian Wolff 2020-08-05 16:27:36 UTC
without any log or better yet backtrace, there's nothing we can do about this

are you seeing anything strange when you run the appimage from the console? could you paste the log here?

could you runtime-attach gdb to the application after starting it and then reproduce the bug and see if you can get a backtrace?
Comment 2 flashyan83 2020-08-08 03:27:17 UTC
I found a way to run gdb. I run the kdevelop in the /tmp/.mount direcotry. then I got the coredump as below:

(gdb) bt
#0  0x00007ffff3db9ee2 in __dynamic_cast () at /lib/x86_64-linux-gnu/libstdc++.so.6
#1  0x00007ffff7e9fdcf in KDevelop::DocumentController::openDocuments() const () at /lib/x86_64-linux-gnu/libKDevPlatformShell.so.55
#2  0x00007fffb6b2f3ce in ClangUtils::unsavedFiles() () at /lib/x86_64-linux-gnu/libKDevClangPrivate.so.33
#3  0x00007fffb6b85d01 in  () at /usr/lib/x86_64-linux-gnu/qt5/plugins/kdevplatform/33/kdevclangsupport.so
#4  0x00007fffb6b8a15a in  () at /usr/lib/x86_64-linux-gnu/qt5/plugins/kdevplatform/33/kdevclangsupport.so
#5  0x00007ffff6da20eb in  () at /lib/x86_64-linux-gnu/libKDevPlatformLanguage.so.55
#6  0x00007ffff6da6110 in  () at /lib/x86_64-linux-gnu/libKDevPlatformLanguage.so.55
#7  0x00007ffff6da01cd in KDevelop::BackgroundParser::parseDocuments() () at /lib/x86_64-linux-gnu/libKDevPlatformLanguage.so.55
#8  0x00007ffff41a6458 in QMetaObject::activate(QObject*, int, int, void**) () at /lib/x86_64-linux-gnu/libQt5Core.so.5
#9  0x00007ffff41b351e in QTimer::timeout(QTimer::QPrivateSignal) () at /lib/x86_64-linux-gnu/libQt5Core.so.5
#10 0x00007ffff41a6cf5 in QObject::event(QEvent*) () at /lib/x86_64-linux-gnu/libQt5Core.so.5
#11 0x00007ffff4fa5a66 in QApplicationPrivate::notify_helper(QObject*, QEvent*) () at /lib/x86_64-linux-gnu/libQt5Widgets.so.5
#12 0x00007ffff4faf0f0 in QApplication::notify(QObject*, QEvent*) () at /lib/x86_64-linux-gnu/libQt5Widgets.so.5
#13 0x00007ffff417a93a in QCoreApplication::notifyInternal2(QObject*, QEvent*) () at /lib/x86_64-linux-gnu/libQt5Core.so.5
#14 0x00007ffff41d18b0 in QTimerInfoList::activateTimers() () at /lib/x86_64-linux-gnu/libQt5Core.so.5
#15 0x00007ffff41d219c in  () at /lib/x86_64-linux-gnu/libQt5Core.so.5
#16 0x00007ffff243afbd in g_main_context_dispatch () at /lib/x86_64-linux-gnu/libglib-2.0.so.0
#17 0x00007ffff243b240 in  () at /lib/x86_64-linux-gnu/libglib-2.0.so.0
#18 0x00007ffff243b2e3 in g_main_context_iteration () at /lib/x86_64-linux-gnu/libglib-2.0.so.0
#19 0x00007ffff41d2565 in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () at /lib/x86_64-linux-gnu/libQt5Core.so.5
#20 0x00007ffff41794db in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) () at /lib/x86_64-linux-gnu/libQt5Core.so.5
#21 0x00007ffff4181246 in QCoreApplication::exec() () at /lib/x86_64-linux-gnu/libQt5Core.so.5
#22 0x000000000040c381 in main ()
Comment 3 Christoph Feck 2020-08-08 06:51:27 UTC
Setting status correctly.
Comment 4 Igor Kushnir 2022-07-05 09:07:17 UTC
I can reproduce this crash almost every time in almost latest git master version of KDevelop. Since sometimes the crash is not reproduced, thread safety might be involved. The backtrace with debug symbols:

Application: KDevelop (kdevelop), signal: Segmentation fault

[KCrash Handler]
#4  __cxxabiv1::(anonymous namespace)::adjust_pointer<void> (offset=Python Exception <class 'gdb.MemoryError'>: Cannot access memory at address 0x20
#5  __cxxabiv1::__dynamic_cast(void const*, __cxxabiv1::__class_type_info const*, __cxxabiv1::__class_type_info const*, ptrdiff_t) (src_ptr=0x55f14aa98dd0, src_type=0x7ff30c9ddbb0 <typeinfo for KDevelop::IDocument>, dst_type=0x7ff308e991b0 <typeinfo for Sublime::Document>, src2dst=-2) at /usr/src/debug/gcc/libstdc++-v3/libsupc++/dyncast.cc:58
#6  0x00007ff30caef0d0 in KDevelop::DocumentController::openDocuments() const (this=<optimized out>) at /usr/src/debug/kdevelop/kdevplatform/shell/documentcontroller.cpp:796
#7  0x00007ff2904cf9d7 in ClangUtils::unsavedFiles() () at /usr/src/debug/kdevelop/plugins/clang/util/clangutils.cpp:49
#8  0x00007ff290533f08 in ClangParseJob::ClangParseJob(KDevelop::IndexedString const&, KDevelop::ILanguageSupport*) (this=0x7ff2452f7250, url=..., languageSupport=<optimized out>) at /usr/src/debug/kdevelop/plugins/clang/clangparsejob.cpp:193
#9  0x00007ff290538457 in non-virtual thunk to ClangSupport::createParseJob(KDevelop::IndexedString const&) () at /usr/src/debug/kdevelop/plugins/clang/clangsupport.h:44
#10 0x00007ff30923c697 in KDevelop::BackgroundParserPrivate::createParseJob(KDevelop::IndexedString const&, DocumentParsePlan const&) (this=this@entry=0x55f13cc68d60, url=..., parsePlan=...) at /usr/src/debug/kdevelop/kdevplatform/language/backgroundparser/backgroundparser.cpp:380
#11 0x00007ff30923e36c in KDevelop::BackgroundParserPrivate::parseDocumentsInternal() (this=this@entry=0x55f13cc68d60) at /usr/src/debug/kdevelop/kdevplatform/language/backgroundparser/backgroundparser.cpp:320
#12 0x00007ff30923a121 in KDevelop::BackgroundParser::parseDocuments() (this=<optimized out>) at /usr/src/debug/kdevelop/kdevplatform/language/backgroundparser/backgroundparser.cpp:705
#13 0x00007ff30b2f7830 in QObject::event(QEvent*) () at /usr/lib/libQt5Core.so.5
#14 0x00007ff30bf20abc in QApplicationPrivate::notify_helper(QObject*, QEvent*) () at /usr/lib/libQt5Widgets.so.5
#15 0x00007ff30b2d3f38 in QCoreApplication::notifyInternal2(QObject*, QEvent*) () at /usr/lib/libQt5Core.so.5
#16 0x00007ff30b2d4a33 in QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) () at /usr/lib/libQt5Core.so.5
#17 0x00007ff30b31a818 in  () at /usr/lib/libQt5Core.so.5
#18 0x00007ff306f42c6b in g_main_context_dispatch () at /usr/lib/libglib-2.0.so.0
#19 0x00007ff306f99001 in  () at /usr/lib/libglib-2.0.so.0
#20 0x00007ff306f40392 in g_main_context_iteration () at /usr/lib/libglib-2.0.so.0
#21 0x00007ff30b31e64c in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () at /usr/lib/libQt5Core.so.5
#22 0x00007ff30b2cc6ec in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) () at /usr/lib/libQt5Core.so.5
#23 0x00007ff30b2d71e9 in QCoreApplication::exec() () at /usr/lib/libQt5Core.so.5
#24 0x000055f13b615b6c in main(int, char**) (argc=<optimized out>, argv=<optimized out>) at /usr/src/debug/kdevelop/app/main.cpp:846
[Inferior 1 (process 19863) detached]
Comment 5 Tarcisio Fischer 2022-07-18 09:06:26 UTC
I can confirm this happens with me also.
[This commit](https://invent.kde.org/tarcisiofischer/kdevelop/-/commit/5a3bc1ac92d5aceec2bfcf4a4d9cdf20152a08f5) seems to solve the issue, although I still need to make an unit test before proceeding to a MR.

This bug may be the same as Bug 456338
Comment 6 Igor Kushnir 2022-12-15 17:29:45 UTC
(In reply to Tarcisio Fischer from comment #5)
> I still need to make an unit test before proceeding to a MR.
If the fix is still stuck at the unit test stage, maybe create a merge request without a test? The fix is short enough that writing a unit test could be a lot more effort than implementing the fix itself :)
Comment 7 Bug Janitor Service 2023-09-09 05:40:38 UTC
A possibly relevant merge request was started @ https://invent.kde.org/kdevelop/kdevelop/-/merge_requests/479
Comment 8 Igor Kushnir 2023-09-15 12:15:20 UTC
Git commit 42a580e2fdd2187ca155d89b480862c9775b6728 by Igor Kushnir.
Committed on 15/09/2023 at 14:14.
Pushed by igorkushnir into branch 'master'.

Don't emit documentUrlChanged twice while saving a text document

When KTextEditor::Document is renamed during saving, it emits a
KTextEditor::Document::documentUrlChanged signal. The slot
TextDocument::documentUrlChanged() is connected to this signal and calls
PartDocument::setUrl(), which in turn calls notifyUrlChanged(), from
which the IDocumentController::documentUrlChanged signal is emitted.
TextDocument::save() saves its KTextEditor::Document and also calls
notifyUrlChanged() if the KTextEditor::Document's URL changes in the
process. Thus the IDocumentController::documentUrlChanged signal is
emitted twice for a single URL change.

DocumentControllerPrivate::changeDocumentUrl() is connected to the
IDocumentController::documentUrlChanged signal. During the duplicate
second signal emission and invocation of this function, the renamed
document is already stored under the correct URL in
DocumentControllerPrivate::documents. changeDocumentUrl() then wrongly
assumes that the renamed document is saved under the name of another
open document and closes it. As the renamed document is not modified,
changeDocumentUrl() then proceeds to insert it into
DocumentControllerPrivate::documents, even though the document is
already closed and is about to be destroyed. The next time
DocumentController::openDocuments() is called, it attempts to
dynamic_cast to Sublime::Document* each element of
DocumentControllerPrivate::documents, including the now-dangling pointer
to the renamed document, which results in a segmentation fault.

The fix is to remove the explicit notifyUrlChanged() call from
TextDocument::save() and rely on KTextEditor::Document's URL change
notifications.

Add an assertion that catches the wrong assumption in
changeDocumentUrl().

Tarcisio Fischer tracked the bug to changeDocumentUrl() (thanks!) and
proposed an alternative fix within this function: prevent the wrong
assumption by checking the condition asserted in this commit. The
alternative fix is less efficient, because it keeps the duplicate signal
emission.
Related: bug 456338
FIXED-IN: 5.13.231200

M  +1    -0    kdevplatform/shell/documentcontroller.cpp
M  +1    -8    kdevplatform/shell/textdocument.cpp

https://invent.kde.org/kdevelop/kdevelop/-/commit/42a580e2fdd2187ca155d89b480862c9775b6728