cquery最近改动
cquery介绍参看使用cquery:C++ language server。
最近cquery改动比较多(终于要熬过这个圣诞了):
- 可执行文件从
build/app
变到build/release/bin/cquery
了,支持release/debug/asan
等多种waf variants,使用RPATH ./waf configure --bundled=5.0.1
可以用上最新出炉的clang+llvm 5.0.1- Riatre把Windows构建修好了 #154
- FreeBSD可以使用了 #155及third party库改动,感谢ngkaho1234把sparsepp FreeBSD kvm搞定
- 不需要在
initializationOptions
里指定resourceDir
了,感谢jiegec的#137 - 各种模板改进和function template/class
template内函数引用的支持。支持了
CXCursor_OverloadedDeclRef
函数调用#174,但template call template clang-c接口没有暴露相应信息,可能无解。 textDocument/hover
信息把函数名插入到函数类型里。用了一些heuristics处理_Atomic
decltype()
throw()
__attribute(())
typeof()
,碰到-> int(*)()
这种还是没救的,数组括号也不好,但大多数情况都显示得不错的。- 加入了实验性的
--enable-comments
,检索注释。#183 #188 #191 注释和原来的声明信息一起显示,带来了UI的挑战。 - VSCode使用浮动窗口,显示多行
textDocument/hover
不成问题。但Emacs lsp-mode和LanguageClient-neovim就遇到一些困难https://github.com/autozimu/LanguageClient-neovim/issues/224 https://github.com/emacs-lsp/lsp-ui/issues/17 workspace/symbol
模糊匹配 #182- danielmartin自己的repo加了实验性的
textDocument/formatting
,格式化。这必须用clang C++ API,作者有一些顾虑。
用了一个O(n^2) sequence
alignment算法,根据编辑距离、camelCase等启发因素排序候选符号(func,type,path,...)。以foo bar
为模式会返回fooBar foobar foozbar
等,而fooBar
排在前面。Emacs
xref-find-apropos
会自作聪明地把模式用空格分割后当作正规表达式转义,需要覆盖掉。
libclang
handleReference
null pointer dereference
下面介绍重点,libclang一字节补丁。
This is a longstanding issue bothering us, with all the 3 bundled
clang+llvm versions:
--bundled-clang={4.0.0,5.0.0,5.0.1}
.
topisani raised the topic in https://gitter.im/cquery-project/Lobby and I fianlly made up my mind to diagnose it.
https://github.com/jacobdufault/cquery/issues/192
1 | % cd /tmp |
By appending --log-file /tmp/cq.log
to the cquery
command line, we can see the error message in /tmp/cq.log
:
1
2indexer.cc:1892 WARN| Indexing /tmp/json/test/src/unit-iterators2.cpp failed with errno=1
libclang: crash detected during indexing TU
errno=1
indicates CXError_Failure
,libclang
uses a sigaction+setjmp
based crash recovery mechanism to
recover from SIGSEGV and returns CXError_Failure
. Sadly
cquery does not report enough diagnostics for this. For these files,
there is no hover, definition, or references information.
https://github.com/jacobdufault/cquery/issues/219 HighCommander4 narrowed it
down to a very simple reproduce: 1
2
3
4
5template <typename>
struct actor;
template <template <typename> class Actor = actor>
struct terminal;
default template argument = actor
causes the null
pointer dereference.
In https://github.com/llvm-mirror/clang/blob/master/tools/libclang/CXIndexDataConsumer.cpp#L203
1 | handleReference(ND, Loc, Cursor, |
dyn_cast_or_null<NamedDecl>(ASTNode.Parent)
may
return NULL. In some code executed later on https://github.com/llvm-mirror/clang/blob/master/tools/libclang/CXIndexDataConsumer.cpp#L935:
1 | ContainerInfo Container; |
getContainerInfo
tries to cast DC
, which
uses a field in DC
and causes a null pointer
dereference.
I have sent the patch to
clang upstream for review, but clang+llvm 5.0.1 was just released.
The holiday season is approaching and it is unrealistic to get this
submitted and get a new release in the near future. For Linux users who
do not want to build clang+llvm from source, my makeshift is
./waf configure --bundled-clang=5.0.1
with
1 | # --bundled-clang=5.0.1 |
What?
Description
Let's check the problematic function in libclang:
1 | bool CXIndexDataConsumer::handleReference(const NamedDecl *D, SourceLocation Loc, |
According to System V x86-64 ABI, the arguments of this function are passed in the following way:
1 | this: rdi |
cquery sets CB.indexEntityReference
to
OnIndexReference
so this field is guaranteed to be non
NULL.
Scroll down the assembly listing a little bit and search for the
if (!CB.indexEntityReference)
condition:
1 | % objdump -M intel -Cd build/release/lib/clang+llvm-5.0.1-x86_64-linux-gnu-ubuntu-14.04/lib/libclang.so.5 --start-address 0x47ae90 --stop-address 0x47b190 |
This redundant if
statement produces 0x47aeca
test rax,rax
. If we replace it with if (!DC)
(because DC
may be NULL and we should avoid null pointer
dereference), since DC
is passed in the register R8, we may
use test r8,r8
: 1
248 85 c0 test rax,rax
4d 85 c0 test r8,r8
It is now clear that we only need to patch one byte, i.e. the
aforementioned printf+dd
hack. For radare2 users,
r2 -nwqc 'wx 4d @ 0x47aece' build/release/lib/clang+llvm-5.0.1-x86_64-linux-gnu-ubuntu-14.04/lib/libclang.so.5.0
.
Sadly radare2 dropped the ball when it was in need and I had to
resort to printf+dd
... Its assembling of
test r8,r8
was incorrect https://github.com/radare/radare2/issues/9071😢