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