diff --git a/include/llvm/FuzzMutate/OpDescriptor.h b/include/llvm/FuzzMutate/OpDescriptor.h index 322c599dc7f..ac31200b2b6 100644 --- a/include/llvm/FuzzMutate/OpDescriptor.h +++ b/include/llvm/FuzzMutate/OpDescriptor.h @@ -140,6 +140,24 @@ static inline SourcePred anyPtrType() { 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(); diff --git a/lib/FuzzMutate/Operations.cpp b/lib/FuzzMutate/Operations.cpp index af2775ebcfb..92993480215 100644 --- a/lib/FuzzMutate/Operations.cpp +++ b/lib/FuzzMutate/Operations.cpp @@ -172,7 +172,7 @@ OpDescriptor llvm::fuzzerop::gepDescriptor(unsigned Weight) { // TODO: Handle aggregates and vectors // TODO: Support multiple indices. // TODO: Try to avoid meaningless accesses. - return {Weight, {anyPtrType(), anyIntType()}, buildGEP}; + return {Weight, {sizedPtrType(), anyIntType()}, buildGEP}; } static uint64_t getAggregateNumElements(Type *T) { diff --git a/unittests/FuzzMutate/OperationsTest.cpp b/unittests/FuzzMutate/OperationsTest.cpp index 352ad00c5bc..d18291e3df5 100644 --- a/unittests/FuzzMutate/OperationsTest.cpp +++ b/unittests/FuzzMutate/OperationsTest.cpp @@ -8,11 +8,13 @@ //===----------------------------------------------------------------------===// #include "llvm/FuzzMutate/Operations.h" +#include "llvm/AsmParser/Parser.h" #include "llvm/FuzzMutate/OpDescriptor.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Module.h" #include "llvm/IR/Verifier.h" +#include "llvm/Support/SourceMgr.h" #include "gmock/gmock.h" #include "gtest/gtest.h" #include @@ -52,9 +54,25 @@ using testing::NotNull; 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) { @@ -253,6 +271,33 @@ TEST(OperationsTest, GEP) { 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 @@ TEST(OperationsTest, ExtractAndInsertValue) { IVOp.SourcePreds[2].generate({SVal, ConstantInt::get(Int32Ty, 0)}, {}), ElementsAre(ConstantInt::get(Int32Ty, 1))); } + +}