1 //===- RandomIRBuilderTest.cpp - Tests for injector strategy --------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/FuzzMutate/RandomIRBuilder.h" 10 #include "llvm/ADT/StringRef.h" 11 #include "llvm/AsmParser/Parser.h" 12 #include "llvm/AsmParser/SlotMapping.h" 13 #include "llvm/FuzzMutate/IRMutator.h" 14 #include "llvm/FuzzMutate/OpDescriptor.h" 15 #include "llvm/FuzzMutate/Operations.h" 16 #include "llvm/IR/Constants.h" 17 #include "llvm/IR/Instructions.h" 18 #include "llvm/IR/LLVMContext.h" 19 #include "llvm/IR/Module.h" 20 #include "llvm/IR/Verifier.h" 21 #include "llvm/Support/SourceMgr.h" 22 23 #include "gtest/gtest.h" 24 25 using namespace llvm; 26 27 static constexpr int Seed = 5; 28 29 namespace { 30 31 std::unique_ptr<Module> parseAssembly(const char *Assembly, 32 LLVMContext &Context) { 33 34 SMDiagnostic Error; 35 std::unique_ptr<Module> M = parseAssemblyString(Assembly, Error, Context); 36 37 std::string ErrMsg; 38 raw_string_ostream OS(ErrMsg); 39 Error.print("", OS); 40 41 assert(M && !verifyModule(*M, &errs())); 42 return M; 43 } 44 45 TEST(RandomIRBuilderTest, ShuffleVectorIncorrectOperands) { 46 // Test that we don't create load instruction as a source for the shuffle 47 // vector operation. 48 49 LLVMContext Ctx; 50 const char *Source = 51 "define <2 x i32> @test(<2 x i1> %cond, <2 x i32> %a) {\n" 52 " %A = alloca <2 x i32>\n" 53 " %I = insertelement <2 x i32> %a, i32 1, i32 1\n" 54 " ret <2 x i32> undef\n" 55 "}"; 56 auto M = parseAssembly(Source, Ctx); 57 58 fuzzerop::OpDescriptor Descr = fuzzerop::shuffleVectorDescriptor(1); 59 60 // Empty known types since we ShuffleVector descriptor doesn't care about them 61 RandomIRBuilder IB(Seed, {}); 62 63 // Get first basic block of the first function 64 Function &F = *M->begin(); 65 BasicBlock &BB = *F.begin(); 66 67 SmallVector<Instruction *, 32> Insts; 68 for (auto I = BB.getFirstInsertionPt(), E = BB.end(); I != E; ++I) 69 Insts.push_back(&*I); 70 71 // Pick first and second sources 72 SmallVector<Value *, 2> Srcs; 73 ASSERT_TRUE(Descr.SourcePreds[0].matches(Srcs, Insts[1])); 74 Srcs.push_back(Insts[1]); 75 ASSERT_TRUE(Descr.SourcePreds[1].matches(Srcs, Insts[1])); 76 Srcs.push_back(Insts[1]); 77 78 // Create new source. Check that it always matches with the descriptor. 79 // Run some iterations to account for random decisions. 80 for (int i = 0; i < 10; ++i) { 81 Value *LastSrc = IB.newSource(BB, Insts, Srcs, Descr.SourcePreds[2]); 82 ASSERT_TRUE(Descr.SourcePreds[2].matches(Srcs, LastSrc)); 83 } 84 } 85 86 TEST(RandomIRBuilderTest, InsertValueIndexes) { 87 // Check that we will generate correct indexes for the insertvalue operation 88 89 LLVMContext Ctx; 90 const char *Source = "%T = type {i8, i32, i64}\n" 91 "define void @test() {\n" 92 " %A = alloca %T\n" 93 " %L = load %T, %T* %A" 94 " ret void\n" 95 "}"; 96 auto M = parseAssembly(Source, Ctx); 97 98 fuzzerop::OpDescriptor IVDescr = fuzzerop::insertValueDescriptor(1); 99 100 std::vector<Type *> Types = {Type::getInt8Ty(Ctx), Type::getInt32Ty(Ctx), 101 Type::getInt64Ty(Ctx)}; 102 RandomIRBuilder IB(Seed, Types); 103 104 // Get first basic block of the first function 105 Function &F = *M->begin(); 106 BasicBlock &BB = *F.begin(); 107 108 // Pick first source 109 Instruction *Src = &*std::next(BB.begin()); 110 111 SmallVector<Value *, 2> Srcs(2); 112 ASSERT_TRUE(IVDescr.SourcePreds[0].matches({}, Src)); 113 Srcs[0] = Src; 114 115 // Generate constants for each of the types and check that we pick correct 116 // index for the given type 117 for (auto *T : Types) { 118 // Loop to account for possible random decisions 119 for (int i = 0; i < 10; ++i) { 120 // Create value we want to insert. Only it's type matters. 121 Srcs[1] = ConstantInt::get(T, 5); 122 123 // Try to pick correct index 124 Value *Src = 125 IB.findOrCreateSource(BB, &*BB.begin(), Srcs, IVDescr.SourcePreds[2]); 126 ASSERT_TRUE(IVDescr.SourcePreds[2].matches(Srcs, Src)); 127 } 128 } 129 } 130 131 TEST(RandomIRBuilderTest, ShuffleVectorSink) { 132 // Check that we will never use shuffle vector mask as a sink form the 133 // unrelated operation. 134 135 LLVMContext Ctx; 136 const char *SourceCode = 137 "define void @test(<4 x i32> %a) {\n" 138 " %S1 = shufflevector <4 x i32> %a, <4 x i32> %a, <4 x i32> undef\n" 139 " %S2 = shufflevector <4 x i32> %a, <4 x i32> %a, <4 x i32> undef\n" 140 " ret void\n" 141 "}"; 142 auto M = parseAssembly(SourceCode, Ctx); 143 144 fuzzerop::OpDescriptor IVDescr = fuzzerop::insertValueDescriptor(1); 145 146 RandomIRBuilder IB(Seed, {}); 147 148 // Get first basic block of the first function 149 Function &F = *M->begin(); 150 BasicBlock &BB = *F.begin(); 151 152 // Source is %S1 153 Instruction *Source = &*BB.begin(); 154 // Sink is %S2 155 SmallVector<Instruction *, 1> Sinks = {&*std::next(BB.begin())}; 156 157 // Loop to account for random decisions 158 for (int i = 0; i < 10; ++i) { 159 // Try to connect S1 to S2. We should always create new sink. 160 IB.connectToSink(BB, Sinks, Source); 161 ASSERT_TRUE(!verifyModule(*M, &errs())); 162 } 163 } 164 165 TEST(RandomIRBuilderTest, InsertValueArray) { 166 // Check that we can generate insertvalue for the vector operations 167 168 LLVMContext Ctx; 169 const char *SourceCode = "define void @test() {\n" 170 " %A = alloca [8 x i32]\n" 171 " %L = load [8 x i32], [8 x i32]* %A" 172 " ret void\n" 173 "}"; 174 auto M = parseAssembly(SourceCode, Ctx); 175 176 fuzzerop::OpDescriptor Descr = fuzzerop::insertValueDescriptor(1); 177 178 std::vector<Type *> Types = {Type::getInt8Ty(Ctx), Type::getInt32Ty(Ctx), 179 Type::getInt64Ty(Ctx)}; 180 RandomIRBuilder IB(Seed, Types); 181 182 // Get first basic block of the first function 183 Function &F = *M->begin(); 184 BasicBlock &BB = *F.begin(); 185 186 // Pick first source 187 Instruction *Source = &*std::next(BB.begin()); 188 ASSERT_TRUE(Descr.SourcePreds[0].matches({}, Source)); 189 190 SmallVector<Value *, 2> Srcs(2); 191 192 // Check that we can always pick the last two operands. 193 for (int i = 0; i < 10; ++i) { 194 Srcs[0] = Source; 195 Srcs[1] = IB.findOrCreateSource(BB, {Source}, Srcs, Descr.SourcePreds[1]); 196 IB.findOrCreateSource(BB, {}, Srcs, Descr.SourcePreds[2]); 197 } 198 } 199 200 TEST(RandomIRBuilderTest, Invokes) { 201 // Check that we never generate load or store after invoke instruction 202 203 LLVMContext Ctx; 204 const char *SourceCode = 205 "declare i32* @f()" 206 "declare i32 @personality_function()" 207 "define i32* @test() personality i32 ()* @personality_function {\n" 208 "entry:\n" 209 " %val = invoke i32* @f()\n" 210 " to label %normal unwind label %exceptional\n" 211 "normal:\n" 212 " ret i32* %val\n" 213 "exceptional:\n" 214 " %landing_pad4 = landingpad token cleanup\n" 215 " ret i32* undef\n" 216 "}"; 217 auto M = parseAssembly(SourceCode, Ctx); 218 219 std::vector<Type *> Types = {Type::getInt8Ty(Ctx)}; 220 RandomIRBuilder IB(Seed, Types); 221 222 // Get first basic block of the test function 223 Function &F = *M->getFunction("test"); 224 BasicBlock &BB = *F.begin(); 225 226 Instruction *Invoke = &*BB.begin(); 227 228 // Find source but never insert new load after invoke 229 for (int i = 0; i < 10; ++i) { 230 (void)IB.findOrCreateSource(BB, {Invoke}, {}, fuzzerop::anyIntType()); 231 ASSERT_TRUE(!verifyModule(*M, &errs())); 232 } 233 } 234 235 TEST(RandomIRBuilderTest, FirstClassTypes) { 236 // Check that we never insert new source as a load from non first class 237 // or unsized type. 238 239 LLVMContext Ctx; 240 const char *SourceCode = "%Opaque = type opaque\n" 241 "define void @test(i8* %ptr) {\n" 242 "entry:\n" 243 " %tmp = bitcast i8* %ptr to i32* (i32*)*\n" 244 " %tmp1 = bitcast i8* %ptr to %Opaque*\n" 245 " ret void\n" 246 "}"; 247 auto M = parseAssembly(SourceCode, Ctx); 248 249 std::vector<Type *> Types = {Type::getInt8Ty(Ctx)}; 250 RandomIRBuilder IB(Seed, Types); 251 252 Function &F = *M->getFunction("test"); 253 BasicBlock &BB = *F.begin(); 254 // Non first class type 255 Instruction *FuncPtr = &*BB.begin(); 256 // Unsized type 257 Instruction *OpaquePtr = &*std::next(BB.begin()); 258 259 for (int i = 0; i < 10; ++i) { 260 Value *V = IB.findOrCreateSource(BB, {FuncPtr, OpaquePtr}); 261 ASSERT_FALSE(isa<LoadInst>(V)); 262 } 263 } 264 265 TEST(RandomIRBuilderTest, SwiftError) { 266 // Check that we never pick swifterror value as a source for operation 267 // other than load, store and call. 268 269 LLVMContext Ctx; 270 const char *SourceCode = "declare void @use(i8** swifterror %err)" 271 "define void @test() {\n" 272 "entry:\n" 273 " %err = alloca swifterror i8*, align 8\n" 274 " call void @use(i8** swifterror %err)\n" 275 " ret void\n" 276 "}"; 277 auto M = parseAssembly(SourceCode, Ctx); 278 279 std::vector<Type *> Types = {Type::getInt8Ty(Ctx)}; 280 RandomIRBuilder IB(Seed, Types); 281 282 // Get first basic block of the test function 283 Function &F = *M->getFunction("test"); 284 BasicBlock &BB = *F.begin(); 285 Instruction *Alloca = &*BB.begin(); 286 287 fuzzerop::OpDescriptor Descr = fuzzerop::gepDescriptor(1); 288 289 for (int i = 0; i < 10; ++i) { 290 Value *V = IB.findOrCreateSource(BB, {Alloca}, {}, Descr.SourcePreds[0]); 291 ASSERT_FALSE(isa<AllocaInst>(V)); 292 } 293 } 294 295 } // namespace 296