1 //===--- llvm-opt-fuzzer.cpp - Fuzzer for instruction selection ----------===// 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 // Tool to fuzz optimization passes using libFuzzer. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "llvm/Bitcode/BitcodeReader.h" 14 #include "llvm/Bitcode/BitcodeWriter.h" 15 #include "llvm/CodeGen/CommandFlags.h" 16 #include "llvm/FuzzMutate/FuzzerCLI.h" 17 #include "llvm/FuzzMutate/IRMutator.h" 18 #include "llvm/IR/Verifier.h" 19 #include "llvm/MC/TargetRegistry.h" 20 #include "llvm/Passes/PassBuilder.h" 21 #include "llvm/Support/CommandLine.h" 22 #include "llvm/Support/SourceMgr.h" 23 #include "llvm/Support/TargetSelect.h" 24 #include "llvm/Target/TargetMachine.h" 25 26 using namespace llvm; 27 28 static codegen::RegisterCodeGenFlags CGF; 29 30 static cl::opt<std::string> 31 TargetTripleStr("mtriple", cl::desc("Override target triple for module")); 32 33 // Passes to run for this fuzzer instance. Expects new pass manager syntax. 34 static cl::opt<std::string> PassPipeline( 35 "passes", 36 cl::desc("A textual description of the pass pipeline for testing")); 37 38 static std::unique_ptr<IRMutator> Mutator; 39 static std::unique_ptr<TargetMachine> TM; 40 41 std::unique_ptr<IRMutator> createOptMutator() { 42 std::vector<TypeGetter> Types{ 43 Type::getInt1Ty, Type::getInt8Ty, Type::getInt16Ty, Type::getInt32Ty, 44 Type::getInt64Ty, Type::getFloatTy, Type::getDoubleTy}; 45 46 std::vector<std::unique_ptr<IRMutationStrategy>> Strategies; 47 Strategies.push_back(std::make_unique<InjectorIRStrategy>( 48 InjectorIRStrategy::getDefaultOps())); 49 Strategies.push_back(std::make_unique<InstDeleterIRStrategy>()); 50 Strategies.push_back(std::make_unique<InstModificationIRStrategy>()); 51 52 return std::make_unique<IRMutator>(std::move(Types), std::move(Strategies)); 53 } 54 55 extern "C" LLVM_ATTRIBUTE_USED size_t LLVMFuzzerCustomMutator( 56 uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed) { 57 58 assert(Mutator && 59 "IR mutator should have been created during fuzzer initialization"); 60 61 LLVMContext Context; 62 auto M = parseAndVerify(Data, Size, Context); 63 if (!M) { 64 errs() << "error: mutator input module is broken!\n"; 65 return 0; 66 } 67 68 Mutator->mutateModule(*M, Seed, MaxSize); 69 70 if (verifyModule(*M, &errs())) { 71 errs() << "mutation result doesn't pass verification\n"; 72 #ifndef NDEBUG 73 M->dump(); 74 #endif 75 // Avoid adding incorrect test cases to the corpus. 76 return 0; 77 } 78 79 std::string Buf; 80 { 81 raw_string_ostream OS(Buf); 82 WriteBitcodeToFile(*M, OS); 83 } 84 if (Buf.size() > MaxSize) 85 return 0; 86 87 // There are some invariants which are not checked by the verifier in favor 88 // of having them checked by the parser. They may be considered as bugs in the 89 // verifier and should be fixed there. However until all of those are covered 90 // we want to check for them explicitly. Otherwise we will add incorrect input 91 // to the corpus and this is going to confuse the fuzzer which will start 92 // exploration of the bitcode reader error handling code. 93 auto NewM = parseAndVerify(reinterpret_cast<const uint8_t *>(Buf.data()), 94 Buf.size(), Context); 95 if (!NewM) { 96 errs() << "mutator failed to re-read the module\n"; 97 #ifndef NDEBUG 98 M->dump(); 99 #endif 100 return 0; 101 } 102 103 memcpy(Data, Buf.data(), Buf.size()); 104 return Buf.size(); 105 } 106 107 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { 108 assert(TM && "Should have been created during fuzzer initialization"); 109 110 if (Size <= 1) 111 // We get bogus data given an empty corpus - ignore it. 112 return 0; 113 114 // Parse module 115 // 116 117 LLVMContext Context; 118 auto M = parseAndVerify(Data, Size, Context); 119 if (!M) { 120 errs() << "error: input module is broken!\n"; 121 return 0; 122 } 123 124 // Set up target dependant options 125 // 126 127 M->setTargetTriple(TM->getTargetTriple().normalize()); 128 M->setDataLayout(TM->createDataLayout()); 129 codegen::setFunctionAttributes(TM->getTargetCPU(), 130 TM->getTargetFeatureString(), *M); 131 132 // Create pass pipeline 133 // 134 135 PassBuilder PB(TM.get()); 136 137 LoopAnalysisManager LAM; 138 FunctionAnalysisManager FAM; 139 CGSCCAnalysisManager CGAM; 140 ModulePassManager MPM; 141 ModuleAnalysisManager MAM; 142 143 PB.registerModuleAnalyses(MAM); 144 PB.registerCGSCCAnalyses(CGAM); 145 PB.registerFunctionAnalyses(FAM); 146 PB.registerLoopAnalyses(LAM); 147 PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); 148 149 auto Err = PB.parsePassPipeline(MPM, PassPipeline); 150 assert(!Err && "Should have been checked during fuzzer initialization"); 151 // Only fail with assert above, otherwise ignore the parsing error. 152 consumeError(std::move(Err)); 153 154 // Run passes which we need to test 155 // 156 157 MPM.run(*M, MAM); 158 159 // Check that passes resulted in a correct code 160 if (verifyModule(*M, &errs())) { 161 errs() << "Transformation resulted in an invalid module\n"; 162 abort(); 163 } 164 165 return 0; 166 } 167 168 static void handleLLVMFatalError(void *, const char *Message, bool) { 169 // TODO: Would it be better to call into the fuzzer internals directly? 170 dbgs() << "LLVM ERROR: " << Message << "\n" 171 << "Aborting to trigger fuzzer exit handling.\n"; 172 abort(); 173 } 174 175 extern "C" LLVM_ATTRIBUTE_USED int LLVMFuzzerInitialize(int *argc, 176 char ***argv) { 177 EnableDebugBuffering = true; 178 StringRef ExecName = *argv[0]; 179 180 // Make sure we print the summary and the current unit when LLVM errors out. 181 install_fatal_error_handler(handleLLVMFatalError, nullptr); 182 183 // Initialize llvm 184 // 185 186 InitializeAllTargets(); 187 InitializeAllTargetMCs(); 188 189 // Parse input options 190 // 191 192 handleExecNameEncodedOptimizerOpts(ExecName); 193 parseFuzzerCLOpts(*argc, *argv); 194 195 // Create TargetMachine 196 // 197 if (TargetTripleStr.empty()) { 198 errs() << ExecName << ": -mtriple must be specified\n"; 199 exit(1); 200 } 201 ExitOnError ExitOnErr(std::string(ExecName) + ": error:"); 202 TM = ExitOnErr(codegen::createTargetMachineForTriple( 203 Triple::normalize(TargetTripleStr))); 204 205 // Check that pass pipeline is specified and correct 206 // 207 208 if (PassPipeline.empty()) { 209 errs() << ExecName << ": at least one pass should be specified\n"; 210 exit(1); 211 } 212 213 PassBuilder PB(TM.get()); 214 ModulePassManager MPM; 215 if (auto Err = PB.parsePassPipeline(MPM, PassPipeline)) { 216 errs() << ExecName << ": " << toString(std::move(Err)) << "\n"; 217 exit(1); 218 } 219 220 // Create mutator 221 // 222 223 Mutator = createOptMutator(); 224 225 return 0; 226 } 227