我确信这很简单但是,我一直试图弄清楚它超过一个小时,我无法弄明白。
以下代码给出了分段错误:
Value *newArray = mBuilder.CreateGEP(alloca, value); // alloca is a `StructType`
但这不是
Value *newArray = mBuilder.CreateGEP(alloca, ConstantInt::get(mContext, APInt(32, 0)));
value
%bar1 = load double, double* %bar
%3 = fptoui double %bar1 to i32
当我使用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
为什么我会出现分段错误,如何解决?
以下代码重现了该问题:
#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;
}
答案 0 :(得分: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);
}
此类不拥有底层数据,预计会在数据驻留在某些其他缓冲区的情况下使用,其缓冲区的生命周期超出ArrayRef的范围。
换句话说,将ArrayRef
返回到局部变量是非法的,就像返回指向局部变量的指针一样。在内部,ArrayRef
仅存储out
data
指针,并且只要out
超出范围(即PrefixZero
的末尾) ,data
被释放,ArrayRef
现在包含一个指向释放内存的指针。
在结构上使用getelementptr
时,表示成员访问权的索引(即您的第二个索引)必须是常量。如果你考虑一下,就不可能对指令进行类比检查(请记住,通常结构的成员都不具有相同的类型)。另外,计算给定非常量索引的指针偏移量基本上必须生成整个查找表,并且指针算术指令生成那么多代码将是违反直觉的。您可以将结构上的GEP视为与C中的the_struct.member_name
等效,并且您无法用变量替换member_name
。
请注意,如果在构建LLVM时启用了断言,则第二个问题应该导致断言失败&#34;类型为!&#34;的GetElementPtrInst索引无效,这虽然不能完全告诉您需要的所有内容知道(比如索引无效的方式),确实指出了正确的方向,而不仅仅是&#34;分段错误&#34;将。因此,如果您没有收到该消息,请确保已启用断言,以便下次遇到问题时可以从断言消息中受益。