GEP分段故障LLVM C++;美国石油学会

GEP分段故障LLVM C++;美国石油学会,llvm,llvm-ir,llvm-c++-api,Llvm,Llvm Ir,Llvm C++ Api,我相信这真的很简单,但是,我已经尝试了一个多小时,但我无法理解 以下代码给出了一个分段错误: Value *newArray = mBuilder.CreateGEP(alloca, value); // alloca is a `StructType` 但事实并非如此 Value *newArray = mBuilder.CreateGEP(alloca, ConstantInt::get(mContext, APInt(32, 0))); 值的值 调试 当我使用lldb调试它时,我得到:

我相信这真的很简单,但是,我已经尝试了一个多小时,但我无法理解

以下代码给出了一个分段错误:

Value *newArray = mBuilder.CreateGEP(alloca, value); // alloca is a `StructType`
但事实并非如此

Value *newArray = mBuilder.CreateGEP(alloca, ConstantInt::get(mContext, APInt(32, 0)));
值的值
调试 当我使用lldb调试它时,我得到:

* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x0)
    frame #0: 0x00000001000b9e6e a.out`llvm::PointerType::get(llvm::Type*, unsigned int) + 20
a.out`llvm::PointerType::get:
->  0x1000b9e6e <+20>: movq   (%rdi), %rax
*thread#1,queue='com.apple.main thread',stop reason=EXC_BAD_ACCESS(code=1,address=0x0)
帧0:0x00000001000b9e6e a.out`llvm::PointerType::get(llvm::Type*,unsigned int)+20
a、 out`llvm::PointerType::get:
->0x1000b9e6e:movq(%rdi),%rax
问题: 为什么我会遇到分割错误,如何修复它

如何重现这个问题? 以下代码再现了该问题:

#include <vector>

#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/Value.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"

using namespace llvm;

static LLVMContext mContext;
static IRBuilder<> mBuilder(mContext);
static std::unique_ptr<Module> mModule = make_unique<Module>("example", mContext);
static Module *M = mModule.get();

static Type *dType = Type::getDoubleTy(mContext);
static Type *i32 = IntegerType::get(mContext, 32);

// helper functions
static AllocaInst *entryCreateBlockAllocaType(Function *func, std::string name, Type* type) {
  IRBuilder<> tmpBuilder(&func->getEntryBlock(), func->getEntryBlock().begin());
  return tmpBuilder.CreateAlloca(type, nullptr, name);
}

static ArrayRef<Value *> PrefixZero (Value *index) {
  std::vector<Value *> out;
  out.push_back(ConstantInt::get(mContext, APInt(32, 0)));
  out.push_back(index);
  return ArrayRef<Value *>(out);
}

static AllocaInst *createVariable () {
  auto *func = mBuilder.GetInsertBlock()->getParent();
  auto *initValue = ConstantInt::get(mContext, APInt(32, 0));

  auto *alloca = entryCreateBlockAllocaType(func, "var", initValue->getType());
  mBuilder.CreateStore(initValue, alloca);
  return alloca; 
}

static std::vector<Type *> elementTypes (3, dType);
static AllocaInst *createStruct () {
  auto *func = mBuilder.GetInsertBlock()->getParent();

  auto *mStructType = StructType::get(mContext, elementTypes);
  return entryCreateBlockAllocaType(func, "str", mStructType);
}

int main () {
  // create a main function
  auto *FT = FunctionType::get(i32, std::vector<Type *>(), false);
  auto *f = Function::Create(FT, Function::ExternalLinkage, "main", M);

  // set insert point for out below code
  auto *bb = BasicBlock::Create(mContext, "entry", f);
  mBuilder.SetInsertPoint(bb);

  // Create a variable
  auto *variable = createVariable();
  // create a struct
  auto *mStruct = createStruct();

  // Create a GEP with the loaded index
  auto *loadedVar = mBuilder.CreateLoad(variable, "loaded_index");

  // This is where the problem is.
  // If `PrefixZero` is changed to `ConstantInt::get(mContext, APInt(32, 0))` this works
  auto *elementPtr = mBuilder.CreateGEP(mStruct, PrefixZero(loadedVar)); 

  mBuilder.CreateRet(ConstantInt::get(mContext, APInt(32, 0))); 
  f->print(errs()); // print out the function

  return 1;
}
#包括
#包括“llvm/ADT/stlexts.h”
#包括“llvm/Support/raw_ostream.h”
#包括“llvm/IR/Value.h”
#包括“llvm/ADT/APFloat.h”
#包括“llvm/ADT/APInt.h”
#包括“llvm/IR/Constants.h”
#包括“llvm/IR/DerivedTypes.h”
#包括“llvm/IR/LLVMContext.h”
#包括“llvm/IR/IRBuilder.h”
#包括“llvm/IR/Instructions.h”
使用名称空间llvm;
静态LLVMContext-mContext;
静态IRBuilder-mBuilder(mContext);
静态std::unique\u ptr mModule=make\u unique(“示例”,mContext);
静态模块*M=mModule.get();
静态类型*dType=Type::getDoubleTy(mContext);
静态类型*i32=IntegerType::get(mContext,32);
//辅助函数
静态AllocaInst*EntryCreateBlockAllocateType(函数*func,标准::字符串名称,类型*Type){
IRBuilder tmpBuilder(&func->getEntryBlock(),func->getEntryBlock().begin());
返回tmpBuilder.CreateAlloca(类型,nullptr,名称);
}
静态ArrayRef前缀为零(值*索引){
std::向量输出;
out.push_back(ConstantInt::get(mContext,APInt(32,0));
向外。向后推(索引);
返回ArrayRef(out);
}
静态AllocaInst*createVariable(){
auto*func=mBuilder.GetInsertBlock()->getParent();
auto*initValue=ConstantInt::get(mContext,APInt(32,0));
auto*alloca=EntryCreateBlockAllocateType(func,“var”,initValue->getType());
创建存储(initValue,alloca);
返回alloca;
}
静态std::向量元素类型(3,dType);
静态AllocaInst*createStruct(){
auto*func=mBuilder.GetInsertBlock()->getParent();
auto*mStructType=StructType::get(mContext,elementTypes);
返回EntryCreateBlockAllocateType(func,“str”,mStructType);
}
int main(){
//创建一个主函数
auto*FT=FunctionType::get(i32,std::vector(),false);
auto*f=Function::Create(FT,Function::ExternalLinkage,“main”,M);
//为下面的代码设置插入点
auto*bb=BasicBlock::Create(mContext,“entry”,f);
mBuilder.设定插入点(bb);
//创建一个变量
auto*variable=createVariable();
//创建一个结构
auto*msstruct=createStruct();
//使用加载的索引创建GEP
auto*loadedVar=mBuilder.CreateLoad(变量,“加载的索引”);
//这就是问题所在。
//如果将“PrefixZero”更改为“ConstantInt::get(mContext,APInt(32,0))”,则此操作有效
auto*elementPtr=mBuilder.CreateGEP(msstruct,前缀为零(loadedVar));
CreateRet(ConstantInt::get(mContext,APInt(32,0));
f->print(errs());//打印出函数
返回1;
}

您的代码有两个问题:

  • 静态ArrayRef前缀为零(值*索引){
    std::向量输出;
    out.push_back(ConstantInt::get(mContext,APInt(32,0));
    向外。向后推(索引);
    返回ArrayRef(out);
    }
    
    从:

    该类不拥有底层数据,它预期用于数据驻留在其他缓冲区中的情况,该缓冲区的生存期超过了ArrayRef的生存期

    换句话说,向局部变量返回
    ArrayRef
    与向局部变量返回指针一样是非法的。在内部,
    ArrayRef
    只存储
    out
    数据
    指针,一旦
    out
    超出范围(即在
    前缀zero
    的末尾,
    数据
    被释放,并且
    ArrayRef
    现在包含一个指向已释放内存的指针

  • 在结构上使用
    getelementptr
    时,表示成员访问权限的索引(即本例中的第二个索引)必须是常量。如果您仔细想想,就不可能以其他方式对指令进行类型检查(请记住,通常结构的成员并不都具有相同的类型)。另外,计算给定非常量索引的指针偏移量基本上必须生成整个查找表,而指针算术指令生成这么多代码是违反直觉的。您可以将结构上的GEP视为等同于C中的
    结构.member\u name
    ,并且您也不能用其中的变量替换
    member\u name


  • 请注意,如果在LLVM的构建中启用了断言,那么第二个问题应该会导致断言失败“类型的GetElementPtrInst索引无效!”,这虽然不能完全告诉您需要知道的一切(例如索引无效的方式),但它确实为您指明了正确的方向,而不仅仅是“分段错误”将因此,如果没有收到该消息,请确保启用了断言,以便下次遇到问题时可以从断言消息中获益。

    alloca是结构还是指向结构的指针?GEP总是使用指针。如果还没有,请尝试在启用断言的情况下构建LLVM。希望这将为您提供一个断言错误,带有正确的错误消息,而不是分段错误。如果这没有帮助,请发布一个我或其他人可以用来重现问题的帖子。@sepp2k谢谢。它是指向结构类型(
    Builder.CreateAlloca
    )的指针。我将尝试在启用断言的情况下构建llvm,并相应地更新我的问题。@sepp2k我使用
    -llvm\u ENABLE\u assertions=ON
    构建llvm,但没有任何更改(AFAIK)
    #include <vector>
    
    #include "llvm/ADT/STLExtras.h"
    #include "llvm/Support/raw_ostream.h"
    #include "llvm/IR/Value.h"
    #include "llvm/ADT/APFloat.h"
    #include "llvm/ADT/APInt.h"
    #include "llvm/IR/Constants.h"
    #include "llvm/IR/DerivedTypes.h"
    #include "llvm/IR/LLVMContext.h"
    #include "llvm/IR/IRBuilder.h"
    #include "llvm/IR/Instructions.h"
    
    using namespace llvm;
    
    static LLVMContext mContext;
    static IRBuilder<> mBuilder(mContext);
    static std::unique_ptr<Module> mModule = make_unique<Module>("example", mContext);
    static Module *M = mModule.get();
    
    static Type *dType = Type::getDoubleTy(mContext);
    static Type *i32 = IntegerType::get(mContext, 32);
    
    // helper functions
    static AllocaInst *entryCreateBlockAllocaType(Function *func, std::string name, Type* type) {
      IRBuilder<> tmpBuilder(&func->getEntryBlock(), func->getEntryBlock().begin());
      return tmpBuilder.CreateAlloca(type, nullptr, name);
    }
    
    static ArrayRef<Value *> PrefixZero (Value *index) {
      std::vector<Value *> out;
      out.push_back(ConstantInt::get(mContext, APInt(32, 0)));
      out.push_back(index);
      return ArrayRef<Value *>(out);
    }
    
    static AllocaInst *createVariable () {
      auto *func = mBuilder.GetInsertBlock()->getParent();
      auto *initValue = ConstantInt::get(mContext, APInt(32, 0));
    
      auto *alloca = entryCreateBlockAllocaType(func, "var", initValue->getType());
      mBuilder.CreateStore(initValue, alloca);
      return alloca; 
    }
    
    static std::vector<Type *> elementTypes (3, dType);
    static AllocaInst *createStruct () {
      auto *func = mBuilder.GetInsertBlock()->getParent();
    
      auto *mStructType = StructType::get(mContext, elementTypes);
      return entryCreateBlockAllocaType(func, "str", mStructType);
    }
    
    int main () {
      // create a main function
      auto *FT = FunctionType::get(i32, std::vector<Type *>(), false);
      auto *f = Function::Create(FT, Function::ExternalLinkage, "main", M);
    
      // set insert point for out below code
      auto *bb = BasicBlock::Create(mContext, "entry", f);
      mBuilder.SetInsertPoint(bb);
    
      // Create a variable
      auto *variable = createVariable();
      // create a struct
      auto *mStruct = createStruct();
    
      // Create a GEP with the loaded index
      auto *loadedVar = mBuilder.CreateLoad(variable, "loaded_index");
    
      // This is where the problem is.
      // If `PrefixZero` is changed to `ConstantInt::get(mContext, APInt(32, 0))` this works
      auto *elementPtr = mBuilder.CreateGEP(mStruct, PrefixZero(loadedVar)); 
    
      mBuilder.CreateRet(ConstantInt::get(mContext, APInt(32, 0))); 
      f->print(errs()); // print out the function
    
      return 1;
    }
    
    static ArrayRef<Value *> PrefixZero (Value *index) {
      std::vector<Value *> out;
      out.push_back(ConstantInt::get(mContext, APInt(32, 0)));
      out.push_back(index);
      return ArrayRef<Value *>(out);
    }