LLVM IRBuilder - 创建 Phi 节点时出现内存错误

LLVM IRBuilder - Memory Error when creating Phi Node

我正在关注 Kaleidoscope tutorial 使用 if-else 表达式制作我自己的语言。我想创建函数根据条件分支到的 2 个块 ifelse。然后两个块都分支回 merge 块,我有一个 phi 节点从正确的块获取值。但是,我在调用函数PHINode::addIncoming时总是出现奇怪的错误,我是不是用错了函数?还是我遗漏了什么?

我创建了一个相当小的例子:

using namespace llvm;

static std::unique_ptr<LLVMContext> TheContext;
static std::unique_ptr<IRBuilder<>> Builder;
static std::unique_ptr<llvm::Module> TheModule;

void InitializeModule() {
    // Open a new context and module.
    TheContext = std::make_unique<LLVMContext>();
    TheModule = std::make_unique<Module>("my prg", *TheContext);

    // Create a new builder for the module.
    Builder = std::make_unique<IRBuilder<>>(*TheContext);

    // Create a main function
    std::vector<Type*> Ints(1,
        Type::getInt64Ty(*TheContext));

    FunctionType* FT =
        FunctionType::get(Type::getInt64Ty(*TheContext), Ints, false);

    Function* F =
        Function::Create(FT, Function::ExternalLinkage, "main", TheModule.get());

    BasicBlock* FuncEntry = BasicBlock::Create(*TheContext, "entry", F);
    Builder->SetInsertPoint(FuncEntry);
}

int main() {
    InitializeModule();

    Function* TheFunction = Builder->GetInsertBlock()->getParent();

    Value* Zero = ConstantInt::get(*TheContext, APInt(64, 0, true));
    Value* One = ConstantInt::get(*TheContext, APInt(64, 1, true));

    BasicBlock* ThenBB = BasicBlock::Create(*TheContext, "then");
    BasicBlock* ElseBB = BasicBlock::Create(*TheContext, "else");
    BasicBlock* MergeBB = BasicBlock::Create(*TheContext, "ifcont");

    //branch
    Value* Cond = Builder->CreateICmpNE(One, Zero, "ifcond");
    Builder->CreateCondBr(Cond, ThenBB, ElseBB);

    //then block
    TheFunction->getBasicBlockList().push_back(ThenBB);
    Builder->SetInsertPoint(ThenBB);
    Builder->CreateBr(MergeBB);
    ThenBB = Builder->GetInsertBlock();

    //else block
    TheFunction->getBasicBlockList().push_back(ElseBB);
    Builder->SetInsertPoint(ElseBB);
    Builder->CreateBr(MergeBB);
    ElseBB = Builder->GetInsertBlock();

    //merge
    TheFunction->getBasicBlockList().push_back(MergeBB);
    Builder->SetInsertPoint(MergeBB);
    PHINode* PN =
        Builder->CreatePHI(Type::getInt64Ty(*TheContext), 2, "iftmp");

    PN->addIncoming(Zero, ThenBB);
    PN->addIncoming(One, ElseBB);

    //Finish function
    Builder->CreateRet(PN);
    verifyFunction(*TheFunction);

    return 0;
}

我正在使用 llvm 的发布版本并使用 Visual Studio 2022 进行编译,这会产生以下运行时错误:

Exception thrown at 0x00007FF7E9774274 in test.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.

运行 AddressSanitizer 我得到:

==21908==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x121d66820318 at pc 0x7ff7bd234188 bp 0x00165dd2f840 sp 0x00165dd2f848
READ of size 8 at 0x121d66820318 thread T0
==21908==WARNING: Failed to use and restart external symbolizer!
    #0 0x7ff7bd234187 in llvm::Use::set C:\llvm\llvm-project-main\llvm\include\llvm\IR\Value.h:869
    #1 0x7ff7bd235599 in llvm::PHINode::addIncoming C:\llvm\llvm-project-main\llvm\include\llvm\IR\Instructions.h:2803
    #2 0x7ff7bd2377c8 in main C:\Users\USERNAME\source\repos\test\test.cpp:81
    #3 0x7ff7bd31292b in __scrt_common_main_seh d:\a01\_work\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
    #4 0x7ff91a0d7033 in BaseThreadInitThunk+0x13 (C:\WINDOWS\System32\KERNEL32.DLL+0x180017033)
    #5 0x7ff91ac62650 in RtlUserThreadStart+0x20 (C:\WINDOWS\SYSTEM32\ntdll.dll+0x180052650)

0x121d66820318 is located 8 bytes to the right of 80-byte region [0x121d668202c0,0x121d66820310)
allocated by thread T0 here:
    #0 0x7ff7bd31205a in operator new D:\a01\_work\s\src\vctools\crt\asan\llvm\compiler-rt\lib\asan\asan_win_new_scalar_thunk.cpp:41
    #1 0x7ff7bd2374b2 in main C:\Users\USERNAME\source\repos\test\test.cpp:57
    #2 0x7ff7bd31292b in __scrt_common_main_seh d:\a01\_work\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
    #3 0x7ff91a0d7033 in BaseThreadInitThunk+0x13 (C:\WINDOWS\System32\KERNEL32.DLL+0x180017033)
    #4 0x7ff91ac62650 in RtlUserThreadStart+0x20 (C:\WINDOWS\SYSTEM32\ntdll.dll+0x180052650)

SUMMARY: AddressSanitizer: heap-buffer-overflow C:\llvm\llvm-project-main\llvm\include\llvm\IR\Value.h:869 in llvm::Use::set
Shadow bytes around the buggy address:
  0x045313504010: fa fa fd fd fd fd fd fd fd fd fd fa fa fa fa fa
  0x045313504020: 00 00 00 00 00 00 00 00 00 fa fa fa fa fa 00 00
  0x045313504030: 00 00 00 00 00 00 00 00 fa fa fa fa 00 00 00 00
  0x045313504040: 00 00 00 00 00 00 fa fa fa fa 00 00 00 00 00 00
  0x045313504050: 00 00 00 00 fa fa fa fa 00 00 00 00 00 00 00 00
=>0x045313504060: 00 00 fa[fa]fa fa 00 00 00 00 00 00 00 00 00 00
  0x045313504070: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 fa fa
  0x045313504080: fa fa fd fd fd fd fd fd fd fd fd fa fa fa fa fa
  0x045313504090: fd fd fd fd fd fd fd fd fd fa fa fa fa fa fd fd
  0x0453135040a0: fd fd fd fd fd fd fd fd fa fa fa fa fd fd fd fd
  0x0453135040b0: fd fd fd fd fd fa fa fa fa fa fd fd fd fd fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==21908==ABORTING

因此,visual studio 中的项目设置不正确。我建议阅读 this 文章,了解如何使用 llvm 正确设置 visual studio。然后,我查看了万花筒教程的官方 vs 项目并复制了设置和属性(不仅仅是包含路径...)。