llvm :: BasicBlock :: isLandingPad表现不正常

问题描述 投票:0回答:2

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

#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;
}

输出:

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.

根据isLandingPadhttps://llvm.org/doxygen/BasicBlock_8cpp_source.html#l00470)的LLVM源,当BasicBlock为空时(由于我们在isa上调用nullptr,因此这应该是段错误)。但是,当我运行该程序时,对isLandingPad的调用成功并返回false。有趣的是,当我内联isLandingPad的函数定义时(如下所示),它会按预期崩溃。

我显然在这里做错了,但是我看不出BB->isLandingPad()调用与内联版本有什么不同,以及为什么isLandingPad不会崩溃,何时应该根据消息来源提供。

c++ llvm
2个回答
1
投票

如果代码“应分段”,这似乎意味着该代码在运行时正在调用undefined behavior(UB)。编译器有可能基于错误假设(即程序中未发生UB)进行优化,而这种错误假设会导致您观察到错误结果isLP == false

您绝不应该调用未定义的行为并重组代码,以永不调用带有可以调用UB的参数的函数。 (例如,在调用getFirstNonPHIisa<LandingPadInst>之前检查isLandingPad的结果。

特别是,您不应该假设UB(例如,引用nullptr或它附近的地址)具有明确定义的效果,例如“它将发生段错误”,因为编译器可能会以某种方式重新组织您的代码(假设UB永远不会发生)会消除您期望的效果(例如,它将生成不尝试从nullptr加载的代码)。

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

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


0
投票

LLVM在禁用断言的情况下进行编译,因此不会触发断言。当您将其内联到代码中时,您正在编译时启用了断言,因此它会触发。

© www.soinside.com 2019 - 2024. All rights reserved.