首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >llvm::BasicBlock::isLandingPad未按预期行事

llvm::BasicBlock::isLandingPad未按预期行事
EN

Stack Overflow用户
提问于 2020-03-03 16:32:30
回答 2查看 123关注 0票数 0

我对LLVM中的isLandingPadBasicBlock上有点困惑。我有以下代码,其中我创建了一个空的BasicBlock,然后在它上调用isLandingPad

代码语言:javascript
复制
#include "llvm/IR/IRBuilder.h"
#include <assert.h>

using namespace llvm;

int main(void)
{
    // Start with a LLVM context.
    LLVMContext TheContext;

    // Make a module.
    Module *TheModule = new Module("mymod", TheContext);

    // Make a function
    std::vector<Type*> NoArgs = {};
    Type *u32 = Type::getInt32Ty(TheContext);
    FunctionType *FT = FunctionType::get(u32, NoArgs, false);
    Function *F = Function::Create(FT, Function::ExternalLinkage, "main", TheModule);

    // Make an empty block
    IRBuilder<> Builder(TheContext);
    BasicBlock *BB = BasicBlock::Create(TheContext, "entry", F);
    Builder.SetInsertPoint(BB);

    auto fnp = BB->getFirstNonPHI();
    assert(fnp == nullptr);

    // I think this should crash.
    auto islp = BB->isLandingPad();
    printf("isLP = %d\n", islp);

    // If we inline the implementation of the above call, we have the following
    // (which *does* crash).
    auto islp2 = isa<LandingPadInst>(BB->getFirstNonPHI());
    printf("isLP2 = %d\n", islp2);

    return 0;
}

其中产出:

代码语言:javascript
复制
isLP = 0
codegen: /usr/lib/llvm-7/include/llvm/Support/Casting.h:106: static bool llvm::isa_impl_cl<llvm::LandingPadInst, const llvm::Instruction *>::doit(const From *) [To = llvm::LandingPadInst, From = const llvm::Instruction *]: Assertion `Val && "isa<> used on a null pointer"' failed.

根据isLandingPad (source.html#l00470)的LLVM源代码,当BasicBlock为空时(因为我们在nullptr上调用isa ),这应该是分段错误。但是,当我运行这个程序时,对isLandingPad的调用成功并返回false。有趣的是,当我内联isLandingPad的函数定义(如下面所示)时,它会像预期的那样崩溃。

我在这里显然做错了什么,但是我不知道BB->isLandingPad()调用在什么方面与内联版本不同,以及为什么isLandingPad不会崩溃,而它应该根据消息来源。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-03-04 10:22:27

LLVM本身(至少在我的系统上)是用禁用断言的方式编译的,所以断言不会触发。当您在代码中内联它时,您正在使用启用断言进行编译,因此它确实会触发。

注意,由于isa<...>是一个模板,它将被编译到编译单元中,并作为其一部分进行实例化。在本例中,至少有两个:一个在LLVM中,一个包含您的程序。严格地说,他们都应该是相同的(“一个定义规则”),否则你有UB无论如何。在这种情况下,实际的结果是,从任何一个编译单元调用isa<...>()可能最终都会调用另一个编译单元实例化的版本。但是,在isa<...>()的情况下,调用很可能是内联的,也就是说,您将得到一个特定于实例化它的每个编译单元的isa<...>()版本。

票数 1
EN

Stack Overflow用户

发布于 2020-03-03 16:46:36

如果代码“应该分段错误”,这似乎意味着代码正在运行时调用未定义的行为(UB)。编译器可能是基于程序中没有出现UB的错误假设进行优化的,这种错误假设导致您观察到的错误结果isLP == false

您不应该调用未定义的行为并重构代码,使其永远不使用可以调用UB的参数调用函数。(例如,在调用getFirstNonPHIisLandingPad之前检查isa<LandingPadInst>的结果。

具体来说,您不应该假设UB (例如取消引用nullptr或它附近的地址)具有定义良好的效果,例如“它将分段错误”,因为编译器可能会重组您的代码(假设UB永远不会发生),从而消除您期望的效果(例如,它将生成不试图从nullptr加载的代码)。

内联和优化级别对生成的代码有很大影响,这就是在不同情况下看到不同结果(无效的返回值与分段错误)的原因。

关于未定义行为的更多信息:

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60511694

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档