Index: include/llvm/FuzzMutate/OpDescriptor.h =================================================================== --- include/llvm/FuzzMutate/OpDescriptor.h +++ include/llvm/FuzzMutate/OpDescriptor.h @@ -150,6 +150,24 @@ return {Pred, Make}; } +static inline SourcePred sizedPtrType() { + auto Pred = [](ArrayRef, const Value *V) { + if (const auto *PtrT = dyn_cast(V->getType())) + return PtrT->getElementType()->isSized(); + return false; + }; + auto Make = [](ArrayRef, ArrayRef Ts) { + std::vector Result; + + for (Type *T : Ts) + if (T->isSized()) + Result.push_back(UndefValue::get(PointerType::getUnqual(T))); + + return Result; + }; + return {Pred, Make}; +} + static inline SourcePred anyAggregateType() { auto Pred = [](ArrayRef, const Value *V) { return V->getType()->isAggregateType(); Index: lib/FuzzMutate/Operations.cpp =================================================================== --- lib/FuzzMutate/Operations.cpp +++ lib/FuzzMutate/Operations.cpp @@ -196,7 +196,7 @@ // TODO: Handle aggregates and vectors // TODO: Support multiple indices. // TODO: Try to avoid meaningless accesses. - return {"GEP", Weight, {anyPtrType(), anyIntType()}, buildGEP}; + return {"GEP", Weight, {sizedPtrType(), anyIntType()}, buildGEP}; } static uint64_t getAggregateNumElements(Type *T) { Index: unittests/FuzzMutate/OperationsTest.cpp =================================================================== --- unittests/FuzzMutate/OperationsTest.cpp +++ unittests/FuzzMutate/OperationsTest.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/AsmParser/Parser.h" #include "llvm/FuzzMutate/Operations.h" #include "llvm/FuzzMutate/OpDescriptor.h" #include "llvm/IR/Constants.h" @@ -15,6 +16,7 @@ #include "llvm/IR/Verifier.h" #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "llvm/Support/SourceMgr.h" #include // Define some pretty printers to help with debugging failures. @@ -52,9 +54,25 @@ using testing::PrintToString; using testing::SizeIs; +namespace { +std::unique_ptr parseAssembly( + const char *Assembly, LLVMContext &Context) { + + SMDiagnostic Error; + std::unique_ptr M = parseAssemblyString(Assembly, Error, Context); + + std::string ErrMsg; + raw_string_ostream OS(ErrMsg); + Error.print("", OS); + + assert(M && !verifyModule(*M, &errs())); + return M; +} + MATCHER_P(TypesMatch, V, "has type " + PrintToString(V->getType())) { return arg->getType() == V->getType(); } + MATCHER_P(HasType, T, "") { return arg->getType() == T; } TEST(OperationsTest, SourcePreds) { @@ -159,7 +177,7 @@ Module M("M", Ctx); Function *F = Function::Create(FunctionType::get(Type::getVoidTy(Ctx), {}, - /*isVarArg=*/false), + /*isVarArg=*/false), GlobalValue::ExternalLinkage, "f", &M); auto SBOp = fuzzerop::splitBlockDescriptor(1); @@ -200,7 +218,7 @@ Module M("M", Ctx); Function *F = Function::Create(FunctionType::get(Type::getVoidTy(Ctx), {}, - /*isVarArg=*/false), + /*isVarArg=*/false), GlobalValue::ExternalLinkage, "f", &M); auto SBOp = fuzzerop::splitBlockDescriptor(1); @@ -238,7 +256,7 @@ Module M("M", Ctx); Function *F = Function::Create(FunctionType::get(Type::getVoidTy(Ctx), {}, - /*isVarArg=*/false), + /*isVarArg=*/false), GlobalValue::ExternalLinkage, "f", &M); auto *BB = BasicBlock::Create(Ctx, "BB", F); auto *RI = ReturnInst::Create(Ctx, BB); @@ -253,6 +271,33 @@ EXPECT_FALSE(verifyModule(M, &errs())); } + +TEST(OperationsTest, GEPPointerOperand) { + // Check that we only pick sized pointers for the GEP instructions + + LLVMContext Ctx; + const char *SourceCode = + "declare void @f()\n" + "define void @test() {\n" + " %v = bitcast void ()* @f to i64 (i8 addrspace(4)*)*\n" + " %a = alloca i64, i32 10\n" + " ret void\n" + "}"; + auto M = parseAssembly(SourceCode, Ctx); + + fuzzerop::OpDescriptor Descr = fuzzerop::gepDescriptor(1); + + // Get first basic block of the test function + Function &F = *M->getFunction("test"); + BasicBlock &BB = *F.begin(); + + // Don't match %v + ASSERT_FALSE(Descr.SourcePreds[0].matches({}, &*BB.begin())); + + // Match %a + ASSERT_TRUE(Descr.SourcePreds[0].matches({}, &*std::next(BB.begin()))); +} + TEST(OperationsTest, ExtractAndInsertValue) { LLVMContext Ctx; @@ -321,3 +366,5 @@ IVOp.SourcePreds[2].generate({SVal, ConstantInt::get(Int32Ty, 0)}, {}), ElementsAre(ConstantInt::get(Int32Ty, 1))); } + +}