Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Assertions triggered with unclosed parentheses, brackets, or braces with _GLIBCXX_ASSERTIONS #1559

Closed
akb825 opened this issue Mar 29, 2023 · 11 comments · Fixed by llvm/llvm-project#78092

Comments

@akb825
Copy link

akb825 commented Mar 29, 2023

When clang and clangd are built with _GLIBCXX_ASSERTIONS enabled (which is in the default CXXFLAGS some Linux distributions like Arch, Fedora, and RedHat), clangd will trigger assertions and crash for unclosed parentheses, brackets, or braces. For example, the following will assert and crash:

int main()
{
int main()
{
    int foo[
}
#include <assert.h>
int main()
{
    assert(
}

Logs

qtc.languageclient.messages: StdIOClient std err:

qtc.languageclient.messages: /usr/include/c++/12.2.0/bits/stl_vector.h:1142: std::vector<_Tp, _Alloc>::const_reference std::vector<_Tp, _Alloc>::operator[](size_type) const [with _Tp = clang::syntax::Token; _Alloc = std::allocator<clang::syntax::Token>; const_reference = const clang::syntax::Token&; size_type = long unsigned int]: Assertion '__n < this->size()' failed.

qtc.languageclient.messages: StdIOClient std err:

qtc.languageclient.messages:  #0 0x00007f736bf7baaa (/usr/lib/libLLVM-15.so+0xd7baaa)
 #1 0x00007f736bf7913f llvm::sys::RunSignalHandlers() (/usr/lib/libLLVM-15.so+0xd7913f)
 #2 0x00007f736bf7928d (/usr/lib/libLLVM-15.so+0xd7928d)
 #3 0x00007f736ac51f50 (/usr/lib/libc.so.6+0x38f50)
 #4 0x00007f736aca08ec (/usr/lib/libc.so.6+0x878ec)
 #5 0x00007f736ac51ea8 raise (/usr/lib/libc.so.6+0x38ea8)
 #6 0x00007f736ac3b53d abort (/usr/lib/libc.so.6+0x2253d)
 #7 0x00007f736aed30e2 (/usr/lib/libstdc++.so.6+0xd30e2)
 #8 0x00007f7374c02440 clang::syntax::TokenBuffer::spelledForExpandedToken(clang::syntax::Token const*) const (/usr/lib/libclang-cpp.so.15+0x2002440)
 #9 0x00007f7374c02cc6 clang::syntax::TokenBuffer::spelledForExpanded(llvm::ArrayRef<clang::syntax::Token>) const (/usr/lib/libclang-cpp.so.15+0x2002cc6)
#10 0x000055bef9e70742 (/usr/bin/clangd+0x60a742)
#11 0x000055bef9e866c5 (/usr/bin/clangd+0x6206c5)
#12 0x000055bef9e7221c (/usr/bin/clangd+0x60c21c)
#13 0x000055bef9e7f05b (/usr/bin/clangd+0x61905b)
#14 0x000055bef9e1e0cc (/usr/bin/clangd+0x5b80cc)
#15 0x000055bef9e1e5b1 (/usr/bin/clangd+0x5b85b1)
#16 0x000055bef9f63a8d (/usr/bin/clangd+0x6fda8d)
#17 0x000055befa9c247d (/usr/bin/clangd+0x115c47d)
#18 0x000055bef9f6141c (/usr/bin/clangd+0x6fb41c)
#19 0x000055befa0b7d37 (/usr/bin/clangd+0x851d37)
#20 0x00007f736ac9ebb5 (/usr/lib/libc.so.6+0x85bb5)
#21 0x00007f736ad20d90 (/usr/lib/libc.so.6+0x107d90)
Signalled during AST worker action: GetAST
  Filename: /home/abarany/Development/DeepSea/modules/Render/RenderMock/test/main.cpp
  Directory: /home/abarany/Development/DeepSea/build/debug-shared/.qtc_clangd
  Command Line: /usr/bin/clang -Wno-documentation-unknown-command -Wno-unknown-warning-option -Wno-unknown-pragmas -nostdinc -nostdinc++ -fvisibility-inlines-hidden -fno-rtti -fexceptions -g -fPIE -Wall -Werror -Wconversion -Wno-sign-conversion -fno-strict-aliasing -fvisibility=hidden -Wno-array-bounds -Wno-stringop-overflow -std=gnu++14 -fsyntax-only -m64 --target=x86_64-pc-linux-gnu -DDS_GPU_PROFILING_ENABLED=0 -DDS_MAJOR_VERSION=0 -DDS_MINOR_VERSION=0 -DDS_PATCH_VERSION -DDS_PROFILING_ENABLED -DGTEST_LINKED_AS_SHARED_LIBRARY -D_USE_MATH_DEFINES -DQ_CREATOR_RUN -I/usr/share/qtcreator/cplusplus/wrappedQtHeaders -I/usr/share/qtcreator/cplusplus/wrappedQtHeaders/QtCore -I/home/abarany/Development/DeepSea/modules/Render/RenderMock/test -I/home/abarany/Development/DeepSea/modules/Render/RenderMock/include -I/home/abarany/Development/DeepSea/build/debug-shared/modules/Render/RenderMock/include -I/home/abarany/Development/DeepSea/modules/Render/Render/include -I/home/abarany/Development/DeepSea/build/debug-shared/modules/Render/Render/include -I/home/abarany/Development/DeepSea/modules/Core/Core/include -I/home/abarany/Development/DeepSea/build/debug-shared/modules/Core/Core/include -I/home/abarany/Development/DeepSea/modules/Math/include -I/home/abarany/Development/DeepSea/build/debug-shared/modules/Math/include -I/home/abarany/Development/DeepSea/modules/Geometry/include -I/home/abarany/Development/DeepSea/build/debug-shared/modules/Geometry/include -isystem /usr/include/c++/12.2.1 -isystem /usr/include/c++/12.2.1/x86_64-pc-linux-gnu -isystem /usr/include/c++/12.2.1/backward -isystem /usr/local/include -isystem /usr/lib/clang/15.0.7/include -isystem /usr/include -fmessage-length=0 -fdiagnostics-show-note-include-stack -fretain-comments-from-system-headers -fmacro-backtrace-limit=0 -ferror-limit=1000 -x c++ -resource-dir=/usr/lib/clang/15.0.7 -- /home/abarany/Development/DeepSea/modules/Render/RenderMock/test/main.cpp
  Version: 13

This is a backtrace from a crash after locally re-building clangd with debug symbols:

#0  __pthread_kill_implementation (threadid=<optimized out>, 
    signo=signo@entry=6, no_tid=no_tid@entry=0) at pthread_kill.c:44
#1  0x00007f83f62a0953 in __pthread_kill_internal (signo=6, 
    threadid=<optimized out>) at pthread_kill.c:78
#2  0x00007f83f6251ea8 in __GI_raise (sig=sig@entry=6)
    at ../sysdeps/posix/raise.c:26
#3  0x00007f83f623b5c7 in __GI_abort () at abort.c:100
#4  0x00007f83f64d30e2 in std::__glibcxx_assert_fail (file=<optimized out>, 
    line=<optimized out>, function=<optimized out>, condition=<optimized out>)
    at /usr/src/debug/gcc/gcc/libstdc++-v3/src/c++11/debug.cc:60
#5  0x00007f8400bf6100 in clang::syntax::TokenBuffer::spelledForExpandedToken(clang::syntax::Token const*) const () from /usr/lib/libclang-cpp.so.15
#6  0x00007f8400bf6b31 in clang::syntax::TokenBuffer::spelledForExpanded(llvm::ArrayRef<clang::syntax::Token>) const () from /usr/lib/libclang-cpp.so.15
#7  0x0000559df89c3c31 in clang::clangd::(anonymous namespace)::DumpVisitor::TraverseDecl(clang::Decl*) ()
#8  0x0000559df89cf40d in clang::RecursiveASTVisitor<clang::clangd::(anonymous namespace)::DumpVisitor>::TraverseTranslationUnitDecl(clang::TranslationUnitDecl*) ()
#9  0x0000559df89c3ebc in clang::clangd::(anonymous namespace)::DumpVisitor::TraverseDecl(clang::Decl*) ()
#10 0x0000559df89d3ced in clang::clangd::dumpAST(clang::DynTypedNode const&, clang::syntax::TokenBuffer const&, clang::ASTContext const&) ()
#11 0x0000559df8955dd9 in clang::clangd::ClangdServer::getAST(llvm::StringRef, llvm::Optional<clang::clangd::Range>, llvm::unique_function<void (llvm::Expected<llvm::Optional<clang::clangd::ASTNode> >)>)::{lambda(llvm::Expected<clang::clangd::InputsAndAST>)#1}::operator()(llvm::Expected<clang::clangd::InputsAndAST>)
    ()
#12 0x0000559df8956111 in void llvm::detail::UniqueFunctionBase<void, llvm::Expected<clang::clangd::InputsAndAST> >::CallImpl<clang::clangd::ClangdServer::getAST(llvm::StringRef, llvm::Optional<clang::clangd::Range>, llvm::unique_function<void (llvm::Expected<llvm::Optional<clang::clangd::ASTNode> >)>)::{lambda(llvm::Expected<clang::clangd::InputsAndAST>)#1}>(void*, llvm::Expected<clang::clangd::InputsAndAST>&) ()
#13 0x0000559df8b23487 in clang::clangd::(anonymous namespace)::ASTWorker::runWithAST(llvm::StringRef, llvm::unique_function<void (llvm::Expected<clang::clangd::InputsAndAST>)>, clang::clangd::TUScheduler::ASTActionInvalidation)::{lambda()#1}::operator()() ()
#14 0x0000559df8b19b6c in clang::clangd::(anonymous namespace)::ASTWorker::runTask(llvm::StringRef, llvm::function_ref<void ()>) [clone .constprop.0] ()
#15 0x0000559df8b1a378 in clang::clangd::(anonymous namespace)::ASTWorker::run() ()
#16 0x0000559df8ce2fd7 in void* llvm::thread::ThreadProxy<std::tuple<clang::clangd::AsyncTaskRunner::runAsync(llvm::Twine const&, llvm::unique_function<void ()>)::{lambda()#2}> >(void*) ()
#17 0x00007f83f629ebb5 in start_thread (arg=<optimized out>)
    at pthread_create.c:444
#18 0x00007f83f6320d90 in clone3 ()
    at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81

System information

Output of clangd --version:
clangd version 15.0.7
Features: linux
Platform: x86_64-pc-linux-gnu

Editor/LSP plugin:
Qt Creator 9.0.2

Operating system:
Arch Linux

@HighCommander4
Copy link

Logs

I was unable to obtain logs. I tried going through the log viewer, which includes invocation of clangd and where the process crashed, but the program output seemed to be consumed.

@ckandeler perhaps you can help the bug reporter obtain logs?

@ckandeler
Copy link

Start Qt Creator with the following environment variable set:
QT_LOGGING_RULES='qtc.languageclient.messages.debug=true;qtc.clangcodemodel.clangd.server.debug=true'

@akb825
Copy link
Author

akb825 commented Mar 29, 2023

Thanks, I have updated the description to include the clangd output, which has the assertion message and stack trace. It doesn't seem to have symbols for clangd itself, though it does have them for the libclang-cpp functions that actually trigger the assert. (not sure if this means it's a bug in libclang-cpp or if clangd is passing invalid parameters that lead to the assert)

@akb825
Copy link
Author

akb825 commented Mar 30, 2023

I made a local build of clangd with debug symbols based on the Arch package config and added a full stack trace to the description.

@HighCommander4
Copy link

HighCommander4 commented Apr 3, 2023

The stack trace shows the crash occurs during the ClangdServer::getAST operation.

I can reproduce it with a debug build of clangd by selecting the entire file contents of one your testcases and running the "clangd: Show AST" command in VSCode. The out-of-bounds operator[] access is the one on this line, or in the case of the assert() example, this line.

To clarify, when you experience this crash are you explicitly triggering a command to show the AST? Or is Qt Creator doing this automatically when a file is opened / during normal editing?

@ckandeler
Copy link

Qt Creator requests the AST to help with certain functionality, most notably semantic highlighting (with clangd < 17). If this crash happens a lot, it's probably worth trying a snapshot from the main branch as a workaround.

@akb825
Copy link
Author

akb825 commented Apr 3, 2023

@HighCommander4 as @ckandeler indicated this happens during normal editing. The end result is that the clangd will crash in the background when typing whenever one of these situations is hit and semantic highlighting and code completion will cease to work until it's relaunched and the file no longer triggers the assert. No user action is needed apart from typing, and I typically see dozens of crashes a day as a result.

@ckandeler as a temporary workaround I performed a local rebuild of the Arch clang package with _GLIBCXX_ASSERTIONS disabled. This at least avoids the crashes caused by the asserts, though the out of bounds access could be at risk for undefined behavior in general.

@akb825
Copy link
Author

akb825 commented May 1, 2023

@HighCommander4 since the location and cause of the asserts seem to be known, is there a solution you have in mind? While the hard crash is limited to distros that choose to enable the asserts, this points to potential out of bounds access and undefined behavior even when they aren't.

@HighCommander4
Copy link

I agree that this bug is concerning due to the UB potential, and that there is enough information in the bug report to debug the issue.

I have not had the time to debug it myself so far.

cc'ing a few folks who were involved in writing the TokenBuffer code who may be able to figure this out more quickly than I would: @ilya-biryukov @hlopko @kadircet @sam-mccall

@krumelmonster
Copy link

It really is quite a big inconvenience, I get those crashes a few times a day on arch linux (QtCreator and clang 16.0.6-1). It seems that File.SpelledTokens[ExpandedIndex - File.BeginExpanded] needs some bounds checking? Should this be reported at llvm-proect/issues ?

HighCommander4 added a commit to HighCommander4/llvm-project that referenced this issue Jan 18, 2024
…in TokenBuffer::spelledForExpanded()

Such ranges can legitimately arise in the case of invalid code,
such as a declaration missing an ending brace.

Fixes clangd/clangd#1559
HighCommander4 added a commit to llvm/llvm-project that referenced this issue Jan 18, 2024
…in TokenBuffer::spelledForExpanded() (#78092)

Such ranges can legitimately arise in the case of invalid code, such as
a declaration missing an ending brace.

Fixes clangd/clangd#1559
@HighCommander4
Copy link

Fixed for clangd 18.

ampandey-1995 pushed a commit to ampandey-1995/llvm-project that referenced this issue Jan 19, 2024
…in TokenBuffer::spelledForExpanded() (llvm#78092)

Such ranges can legitimately arise in the case of invalid code, such as
a declaration missing an ending brace.

Fixes clangd/clangd#1559
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment