我正在使用从源代码构建的 libTooling(git 标签:
llvmorg-16.0.6
)来搜索 AST 级别的差异。
使用我构建的产品时,出现分段错误。
通过gdb检查,发现这是来自libTooling, 并且在调用
A->getSourceRange()
(source) 时发生分段错误
if (auto *A = dyn_cast<AccessSpecDecl>(D)) {
CharSourceRange Range(A->getSourceRange(), false);
return std::string(
Lexer::getSourceText(Range, AST.getSourceManager(), AST.getLangOpts()));
}
此外,gdb 显示
A
的 vtable 指针(_vptr.Decl
)是 0x0
。
(gdb) p *A
$1 = {<clang::Decl> = {_vptr.Decl = 0x0, NextInContextAndBits = {Value = 0},
DeclCtx = {<llvm::pointer_union_detail::PointerUnionMembers<llvm::PointerUnion<clang::DeclContext*, clang::Decl::MultipleDC*>, llvm::PointerIntPair<void*, 1, int, llvm::pointer_union_detail::PointerUnionUIntTraits<clang::DeclContext*, clang::Decl::MultipleDC*>, llvm::PointerIntPairInfo<void*, 1, llvm::pointer_union_detail::PointerUnionUIntTraits<clang::DeclContext*, clang::Decl::MultipleDC*> > >, 0, clang::DeclContext*, clang::Decl::MultipleDC*>> = {<llvm::pointer_union_detail::PointerUnionMembers<llvm::PointerUnion<clang::DeclContext*, clang::Decl::MultipleDC*>, llvm::PointerIntPair<void*, 1, int, llvm::pointer_union_detail::PointerUnionUIntTraits<clang::DeclContext*, clang::Decl::MultipleDC*>, llvm::PointerIntPairInfo<void*, 1, llvm::pointer_union_detail::PointerUnionUIntTraits<clang::DeclContext*, clang::Decl::MultipleDC*> > >, 1, clang::Decl::MultipleDC*>> = {<llvm::pointer_union_detail::PointerUnionMembers<llvm::PointerUnion<clang::DeclContext*, clang::Decl::MultipleDC*>, llvm::PointerIntPair<void*, 1, int, llvm::pointer_union_detail::PointerUnionUIntTraits<clang::DeclContext*, clang::Decl::MultipleDC*>, llvm::PointerIntPairInfo<void*, 1, llvm::pointer_union_detail::PointerUnionUIntTraits<clang::DeclContext*, clang::Decl::MultipleDC*> > >, 2>> = {Val = {Value = 0}}, <No data fields>}, <No data fields>}, <No data fields>}, Loc = {ID = 0}, DeclKind = 0, InvalidDecl = 0, HasAttrs = 0, Implicit = 0, Used = 0, Referenced = 0,
TopLevelDeclInObjCContainer = 0, static StatisticsEnabled = false, Access = 0, FromASTFile = 0, IdentifierNamespace = 0, CacheValidAndLinkage = 0}, ColonLoc = {ID = 0}}
我将编译器从
/usr/bin/c++
切换到clang++
,但问题没有解决。我还使用 libTooling 和来自 apt install
的 clang-15 进行编译,但它也会引发似乎发生在其他位置的分段错误(对于从源代码构建的 clang 在 clang::diff::SyntaxTree::Impl::getDeclValue
引发,对于来自 apt 的 clang-15 在 clang::diff::SyntaxTree::Impl::getStmtValue
引发)
因为两个编译器的二进制文件(
c++
和clang++
)导致相同的分段错误,我怀疑我做错了什么,但我不知道是什么。
请教我为什么会有 NULL vtable 指针,以及如何解决这个问题。
用于复制的存储库位于此处。
vtable 指针如何
NULL
这个基本问题已经是
在这里提问和回答:
但是,该问题的答案中提出的假设是 与这里的症状并不完美匹配,并且 libtooling 角度已经 一些新颖的方面,所以我不会称其为重复,即使 虽然很接近。
从
gdb
输出中,我们可以看到一切为零,而不仅仅是
虚函数表指针。这表明指针指向
在某个不应该的地方,在恰好包含全零的内存中。
也有可能有什么东西覆盖了整个 AST 内存
零。
作为演示,如果我们有一个带有 vtable 的类:
class C {
public:
int m_x, m_y;
virtual ~C() {}
};
并创建一个指向零的指针:
unsigned char arr[80];
std::memset(arr, 0, sizeof(arr));
C *p = reinterpret_cast<C*>(&arr[0]);
然后
gdb
将报告零 vtable:
(gdb) print *p
$1 = {_vptr.C = 0x0, m_x = 0, m_y = 0}
不知何故,你做了一些事情来造成类似的情况。
所讨论的指针表面上指向一个 lib工具
Decl
AST
节点。但一切都是零,包括DeclKind
。
在此条件下发生崩溃的原因是
DeclKind
为零恰好是使用的值
AccessSpecDecl
表明自己的身份
dyn_cast
.
通话时崩溃的原因是
A->getSourceRange()
getSourceRange
是一个 virtual
函数,但 vtable 指针是
NULL
,因此取消引用该指针会导致崩溃。
在这种情况下,崩溃站点本身并不能提供太多帮助 信息,你想开始从你的程序中删除尽可能多的信息 你可以,同时保留它以这种方式失败的事实。 大概您是从一些 libtooling hello-world 教程示例开始的 不表现出这种行为。删除程序的各个部分, 一点一点,直到你除了原始教程代码之外什么都没有。在 某个时刻,您将移除一块,从而使问题消失;放 回来并继续移除其他部分。
如果通过这样做,您解决了问题,那就太好了,您就完成了。 否则你将拥有一个最小的复制器,它可以作为 新问题。 (但不要只链接到 github 存储库。问题 应该是独立的。)