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