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