LLVM传递:迭代模块函数列表时出错

时间:2016-03-30 12:29:09

标签: llvm

我正在尝试使用LLVM传递来使用llvm::Module::getFunctionList()返回的列表迭代模块函数列表。我使用像这样的循环:

    for (auto curFref = M->getFunctionList().begin(), 
              endFref = M->getFunctionList().end(); 
              curFref != endFref; ++curFref) {
        errs() << "found function: " << curFref->getName() << "\n";
    }

此循环的第一次迭代按预期检索函数,但它不检测列表的结尾并继续只是为了在后续迭代中获取其他非函数的对象(由getName()报告),例如该函数参数。经过几次迭代后,它可能会达到一些垃圾(或NULL)并在引用当前“函数”引用时崩溃。 例如,对于此程序:

int foo(int k) {
    int i, s = 0;
    for (i = 0; i < k; ++i)
        s += i;
    return s;
}

这就是IR代码:

...
; Function Attrs: nounwind uwtable
define i32 @foo(i32 %k) #0 {
entry:
...

输出如下:

found function: foo
found function: k
found function: #0 0x00007f481f77c46e llvm::sys::PrintStackTrace(llvm::raw_ostream&) /home/me/work/llvm-3.8.0/lib/Support/Unix/Signals.inc:322:0
...

因此,您可以看到,在正确迭代foo之后,它继续执行参数k等对象。

我在模块传递(在runOnModule()中)以及在函数传递(使用F.getParent()查询包含的模块)中尝试了这一点,并得到了相同的结果。

问题也在LLVM 3.8.0和LLVM 3.5.2上复制。

知道我错过了什么,我无法在返回的函数列表上正确迭代?

=====

编辑:

请注意,在对模块的函数使用替代迭代时会显示相同的行为,例如对迭代器使用M.begin()/end()时,或者甚至在使用基于C ++ 11范围的for循环时:for (Function &curF: M) ...

此外,M.getFunctionList().size()会在尝试迭代列表项时导致分段错误。所以似乎功能列表确实是腐败的。但这是我在runOnModule()入口点开始时得到的列表。因此,我的代码似乎没有破坏它。

==

编辑2:

我不知道这是否重要,但我的LLVM传递是从LLVM源代码树外部构建为可动态加载的库,然后使用opt命令行选项加载到-load=foo.so

4 个答案:

答案 0 :(得分:2)

我是核心LLVM开发人员之一。

这几乎可以肯定是LLVM的错误检查,错误编译的LLVM,或者您的传递是作为单独的DSO构建的问题(虽然我不知道它是怎么回事)。

LLVM的许多部分使用M->functions()(或M->begin()&amp; M->end())来仅迭代函数。如果行为被破坏,这些部分将始终如一地失败。这些机制与直接以M->getFunctionList()直接访问函数列表之间的唯一区别在于列表是否可变。对于您显示的用例,它们应该正好相同的行为。

我建议尝试运行LLVM测试套件以确保它正常工作。如果您使用Ninja CMake生成器(我建议)来构建LLVM:

% ninja check-llvm

如果此操作失败,特别是如果它在类似区域崩溃,那么这似乎是一个非常好的迹象,表明问题出现在您的LLVM副本中。

无论如何,SO不是一个在这里获得进一步帮助的好地方。这个问题的答案是“实际应该工作”,我检查了LLVM中的代码,我没有看到任何明显的解释。所以我的建议是尝试以上内容,尝试新的LLVM副本(可能是树顶或最新版本)。确保您拥有足够现代的主机工具链来构建LLVM。有关详细信息,请参阅本节 http://llvm.org/docs/GettingStarted.html#host-c-toolchain-both-compiler-and-standard-library

如果所有其他方法都失败了,请尝试联系邮件列表上的开发人员: http://lists.llvm.org/mailman/listinfo/llvm-dev

或尝试使用IRC频道:http://llvm.org/docs/#irc

希望这有帮助!

答案 1 :(得分:0)

您是否曾尝试使用M->begin()M->end()代替M->getFunctionList().begin()M->getFunctionList().end()?这对我有用。

答案 2 :(得分:0)

您的输入是否有可能以某种方式损坏?首先尝试在llvm::verifyModule上运行opt -verify并查看您获得的内容 - 或者在其上运行-verify-each,应该是相同的。此外,您可能对opt {/ p>的{{1}}命令行选项感兴趣

答案 3 :(得分:0)

如果您使用以下内容注册通行证:

 char SkeletonPass::ID = 0;

// Automatically enable the pass.
// This pass is taken from Adrian Samson Template project http://adriansampson.net/blog/clangpass.html
static void registerSkeletonPass(const PassManagerBuilder &,
                         legacy::PassManagerBase &PM) {
  PM.add(new SkeletonPass());
}
static RegisterStandardPasses
  RegisterMyPass(PassManagerBuilder::EP_EarlyAsPossible,
                 registerSkeletonPass);

这仅适用于FunctionPass / BasicBlockPass,一种解决方案是像往常一样使用规范传递而不需要任何技巧,如下所示: -

char SkeletonPass::ID = 0;
static RegisterPass<SkeletonPass> X("passname","Pass Name Analysis");
static void registerPass(const PassManagerBuilder &,
                         legacy::PassManagerBase &PM) {
    PM.add(new SkeletonPass());
}
static RegisterStandardPasses
        RegisterMyPass(PassManagerBuilder::EP_EarlyAsPossible,
                       registerPass);

使用以下cmd运行您的传递:

$ clang -c -O1 -emit-llvm  programs/hello.cpp   -o programs/hello.bc
$ opt   -load build/Debug/libCallgraph.so -passname programs/hello.bc