[llvm-bugs] [Bug 35333] New: libclang crashes when calling clang_cursor_getParsedComment when file was changed meanwhile

via llvm-bugs llvm-bugs at lists.llvm.org
Thu Nov 16 12:12:05 PST 2017


https://bugs.llvm.org/show_bug.cgi?id=35333

            Bug ID: 35333
           Summary: libclang crashes when calling
                    clang_cursor_getParsedComment when file was changed
                    meanwhile
           Product: clang
           Version: trunk
          Hardware: All
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P
         Component: libclang
          Assignee: unassignedclangbugs at nondot.org
          Reporter: mail at svenbrauch.de
                CC: klimek at google.com, llvm-bugs at lists.llvm.org

In KDevelop, we use libclang to parse C++ code and then use a visitor to walk
over the result and extract information. During that, calling
clang_Cursor_getParsedComment sometimes crashes with traces like below.

The crash happens when the contents of the analyzed file are changed while the
parse job is running. The reason is, I think, that RawComment::getRawTextSlow
gets the comment's text from the SourceManager using the cursors it thinks the
comment is at, but SourceManager has discarded the original buffer since,
making it read from the new, changed file on disk. It then retrieves some text
that is not actually a comment (e.g. doesn't end with */ or so), for which the
comment lexer is not designed, and crashes.

This bug is easy to reproduce here when e.g. switching git branches while
parsing. Below is the trace, as well as the start and end pointers of the
buffer: In one version of the file, a character was added to the affected
comment, which results in the BufferEnd pointer pointing at the closing /
character instead of behind it, causing the lexer to walk beyond the end
location and crash.

I'm not sure how to fix this. It would be simple to make the comment lexer
survive this situation, but that doesn't really fix the problem (instead, we'll
then sometimes have half the source code returned when retrieving a comment).
One would need to ensure that the same buffer is used to read the comments from
as the AST was generated for.

Ideas?

__________________________
Crash trace:

(gdb) bt
#0  0x00007fff94d9c9c0 in clang::comments::Lexer::lex(clang::comments::Token&)
(this=0x7fff88886940, T=...) at ../tools/clang/lib/AST/CommentLexer.cpp:803
#1  0x00007fff94da246c in clang::comments::Parser::consumeToken()
(this=<optimized out>) at ../tools/clang/include/clang/AST/CommentParser.h:63
#2  0x00007fff94da246c in
clang::comments::Parser::parseParagraphOrBlockCommand() (this=0x7fff88886a70)
at ../tools/clang/lib/AST/CommentParser.cpp:636
#3  0x00007fff94da3b1d in clang::comments::Parser::parseBlockContent()
(this=this at entry=0x7fff88886a70) at
../tools/clang/lib/AST/CommentParser.cpp:736
#4  0x00007fff94da3bcc in clang::comments::Parser::parseFullComment()
(this=this at entry=0x7fff88886a70) at
../tools/clang/lib/AST/CommentParser.cpp:766
#5  0x00007fff94ea4ec0 in clang::RawComment::parse(clang::ASTContext const&,
clang::Preprocessor const*, clang::Decl const*) const (this=<optimized out>,
Context=..., PP=PP at entry=0x0, D=0x7fff1ef5bd50) at
../tools/clang/lib/AST/RawCommentList.cpp:221
#6  0x00007fff94d04d95 in clang::ASTContext::getCommentForDecl(clang::Decl
const*, clang::Preprocessor const*) const (this=0x7fff4cd135e0, D=<optimized
out>, D at entry=0x7fff1ef5bd50, PP=PP at entry=0x0) at
../tools/clang/lib/AST/ASTContext.cpp:542
#7  0x00007fff951d089a in clang_Cursor_getParsedComment(CXCursor) (C=...) at
../tools/clang/tools/libclang/CXComment.cpp:37
#8  0x00007fff9546e4f3 in (anonymous
namespace)::Visitor::setDeclData<(CXCursorKind)3>(CXCursor,
KDevelop::Declaration*, bool) (cursor=..., decl=decl at entry=0x7fff7de33d40,
this=<optimized out>, setComment=true) at
../plugins/clang/duchain/builder.cpp:949
#9  0x00007fff9548aa07 in (anonymous
namespace)::Visitor::createDeclarationCommon<(CXCursorKind)7,
KDevelop::Declaration>(CXCursor, KDevelop::Identifier const&)
(this=0x7fff88889640, cursor=..., id=...) at
../plugins/clang/duchain/builder.cpp:428
#10 0x00007fff9548e691 in (anonymous
namespace)::Visitor::createDeclaration<(CXCursorKind)5, KDevelop::Declaration>
(context=0x7fff7e0729f0, id=..., cursor=..., this=0x7fff88889640) at
../plugins/clang/duchain/builder.cpp:439
#11 0x00007fff9548e691 in (anonymous
namespace)::Visitor::buildDeclaration<(CXCursorKind)5, KDevelop::Declaration,
true> (cursor=..., this=0x7fff88889640) at
../plugins/clang/duchain/builder.cpp:1178
#12 0x00007fff9548e691 in (anonymous
namespace)::Visitor::dispatchCursor<(CXCursorKind)5, (Decision)1, (Decision)0>
(parent=..., cursor=..., this=0x7fff88889640) at
../plugins/clang/duchain/builder.cpp:939
#13 0x00007fff9548e691 in (anonymous
namespace)::Visitor::dispatchCursor<(CXCursorKind)5, (Decision)1, (Decision)2>
(parent=..., cursor=..., this=0x7fff88889640) at
../plugins/clang/duchain/builder.cpp:913
#14 0x00007fff9548e691 in (anonymous
namespace)::Visitor::dispatchCursor<(CXCursorKind)5> (parent=..., cursor=...,
this=0x7fff88889640) at ../plugins/clang/duchain/builder.cpp:901
#15 0x00007fff9548e691 in (anonymous namespace)::visitCursor(CXCursor,
CXCursor, CXClientData) (cursor=..., parent=..., data=0x7fff88889640) at
../plugins/clang/duchain/builder.cpp:1512
#16 0x00007fff951bc050 in clang::cxcursor::CursorVisitor::Visit(CXCursor, bool)
(this=this at entry=0x7fff88887f80, Cursor=...,
CheckedRegionOfInterest=CheckedRegionOfInterest at entry=true) at
../tools/clang/tools/libclang/CIndex.cpp:210
#17 0x00007fff951bf88d in
clang::cxcursor::CursorVisitor::handleDeclForVisitation(clang::Decl const*)
(this=this at entry=0x7fff88887f80, D=0x7fff1ef5bd50) at
../tools/clang/tools/libclang/CIndex.cpp:667
#18 0x00007fff951bfa7b in
clang::cxcursor::CursorVisitor::VisitDeclContext(clang::DeclContext*)
(this=0x7fff88887f80, DC=0x7fff1ef5bc88) at
../tools/clang/tools/libclang/CIndex.cpp:628
#19 0x00007fff951bba69 in
clang::cxcursor::CursorVisitor::VisitChildren(CXCursor)
(this=this at entry=0x7fff88887f80, Cursor=...) at
../tools/clang/tools/libclang/CIndex.cpp:499
#20 0x00007fff951c4557 in clang_visitChildren(CXCursor, CXCursorVisitor,
CXClientData) (parent=..., visitor=visitor at entry=0x7fff9548ca50 <(anonymous
namespace)::visitCursor(CXCursor, CXCursor, CXClientData)>,
client_data=client_data at entry=0x7fff88889640) at
../tools/clang/tools/libclang/CIndex.cpp:4276
#21 0x00007fff95478e17 in (anonymous
namespace)::Visitor::buildDeclaration<(CXCursorKind)22, KDevelop::Declaration,
true>(CXCursor) (this=this at entry=0x7fff88889640, cursor=...) at
../plugins/clang/duchain/builder.cpp:1181
#22 0x00007fff9548d5b6 in (anonymous
namespace)::Visitor::dispatchCursor<(CXCursorKind)22> (cursor=...,
this=0x7fff88889640, parent=...) at ../plugins/clang/duchain/builder.cpp:939
#23 0x00007fff9548d5b6 in (anonymous namespace)::visitCursor(CXCursor,
CXCursor, CXClientData) (cursor=..., parent=..., data=0x7fff88889640) at
../plugins/clang/duchain/builder.cpp:1520
#24 0x00007fff951bc050 in clang::cxcursor::CursorVisitor::Visit(CXCursor, bool)
(this=this at entry=0x7fff88889400, Cursor=...,
CheckedRegionOfInterest=CheckedRegionOfInterest at entry=true) at
../tools/clang/tools/libclang/CIndex.cpp:210
#25 0x00007fff951bf88d in
clang::cxcursor::CursorVisitor::handleDeclForVisitation(clang::Decl const*)
(this=this at entry=0x7fff88889400, D=0x7fff1ef5bc60) at
../tools/clang/tools/libclang/CIndex.cpp:667
#26 0x00007fff951bfa7b in
clang::cxcursor::CursorVisitor::VisitDeclContext(clang::DeclContext*)
(this=this at entry=0x7fff88889400, DC=0x7fff1dcf6788) at
../tools/clang/tools/libclang/CIndex.cpp:628
#27 0x00007fff951bbd5b in
clang::cxcursor::CursorVisitor::VisitChildren(CXCursor)
(this=this at entry=0x7fff88889400, Cursor=...) at
../tools/clang/tools/libclang/CIndex.cpp:533
#28 0x00007fff951c4557 in clang_visitChildren(CXCursor, CXCursorVisitor,
CXClientData) (parent=..., visitor=visitor at entry=0x7fff9548ca50 <(anonymous
namespace)::visitCursor(CXCursor, CXCursor, CXClientData)>,
client_data=client_data at entry=0x7fff88889640) at
../tools/clang/tools/libclang/CIndex.cpp:4276
#29 0x00007fff9547593c in (anonymous namespace)::Visitor::Visitor
(update=<optimized out>, includes=..., file=<optimized out>, tu=<optimized
out>, this=0x7fff88889640) at ../plugins/clang/duchain/builder.cpp:1435
#30 0x00007fff9547593c in Builder::visit(CXTranslationUnitImpl*, void*,
QHash<void*, KDevelop::ReferencedTopDUContext> const&, bool) (tu=<optimized
out>, file=<optimized out>, includes=..., update=<optimized out>) at
../plugins/clang/duchain/builder.cpp:1575
#31 0x00007fff9549c5b5 in ClangHelpers::buildDUChain(void*, QMultiHash<void*,
Import> const&, ParseSession const&, KDevelop::TopDUContext::Features,
QHash<void*, KDevelop::ReferencedTopDUContext>&, ClangIndex*,
std::function<bool ()> const&) (file=<optimized out>, imports=..., session=...,
features=features at entry=KDevelop::TopDUContext::AllDeclarationsContextsAndUses,
includedFiles=..., index=0x55555a8e8b00, abortFunction=...) at
../plugins/clang/duchain/clanghelpers.cpp:189
#32 0x00007fff9549bee0 in ClangHelpers::buildDUChain(void*, QMultiHash<void*,
Import> const&, ParseSession const&, KDevelop::TopDUContext::Features,
QHash<void*, KDevelop::ReferencedTopDUContext>&, ClangIndex*,
std::function<bool ()> const&) (file=<optimized out>, imports=..., session=...,
features=KDevelop::TopDUContext::AllDeclarationsContextsAndUses,
includedFiles=..., index=0x55555a8e8b00, abortFunction=...) at
../plugins/clang/duchain/clanghelpers.cpp:121
#33 0x00007fff95700ae5 in
ClangParseJob::run(QSharedPointer<ThreadWeaver::JobInterface>,
ThreadWeaver::Thread*) (this=0x55555c23ffa0) at
../plugins/clang/clangparsejob.cpp:323
#34 0x00007fffed11c087 in
ThreadWeaver::IdDecorator::run(QSharedPointer<ThreadWeaver::JobInterface>,
ThreadWeaver::Thread*) () at /usr/lib/libKF5ThreadWeaver.so.5
#35 0x00007fffed11c678 in
ThreadWeaver::Executor::run(QSharedPointer<ThreadWeaver::JobInterface> const&,
ThreadWeaver::Thread*) () at /usr/lib/libKF5ThreadWeaver.so.5
#36 0x00007fffed11b670 in
ThreadWeaver::Job::execute(QSharedPointer<ThreadWeaver::JobInterface> const&,
ThreadWeaver::Thread*) () at /usr/lib/libKF5ThreadWeaver.so.5
#37 0x00007fffed11ada5 in ThreadWeaver::Thread::run() () at
/usr/lib/libKF5ThreadWeaver.so.5
#38 0x00007ffff1052fcb in  () at /usr/lib/libQt5Core.so.5
#39 0x00007fffe9c0208a in start_thread () at /usr/lib/libpthread.so.0
#40 0x00007ffff03fc24f in clone () at /usr/lib/libc.so.6

Extra info:

(gdb) p BufferStart
$3 = 0x7fff7db0f180 "/**Positions for tool views in Sublime UI. To combine
them, use\n    Positions class (QFlags based).*/\n    enum Position\n    {\n   
    Left = 1   /**< left tool view position */,\n        Right = 2  /**"...
(gdb) p BufferEnd
$4 = 0x7fff7db0f1e4 "/\n    enum Position\n    {\n        Left = 1   /**< left
tool view position */,\n        Right = 2  /**< right tool view position */,\n 
      Top = 4    /**< top tool view position */,\n        Bottom = 8"...
(gdb) p EndWhitespace
$5 = 0x7fff80000000 <error: Cannot access memory at address 0x7fff80000000>

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20171116/2521c27a/attachment.html>


More information about the llvm-bugs mailing list