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