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/Passes/PassBuilder.h" 22#include "llvm/Support/CommandLine.h" 23#include "llvm/Support/SourceMgr.h" 24#include "llvm/Support/TargetRegistry.h" 25#include "llvm/Support/TargetSelect.h" 26#include "llvm/Target/TargetMachine.h" 27 28using namespace llvm; 29 30static codegen::RegisterCodeGenFlags CGF; 31 32static 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. 36static cl::opt<std::string> PassPipeline( 37 "passes", 38 cl::desc("A textual description of the pass pipeline for testing")); 39 40static std::unique_ptr<IRMutator> Mutator; 41static std::unique_ptr<TargetMachine> TM; 42 43std::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 59extern "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 111extern "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 FAM.registerPass([&] { return PB.buildDefaultAAPipeline(); }); 148 PB.registerModuleAnalyses(MAM); 149 PB.registerCGSCCAnalyses(CGAM); 150 PB.registerFunctionAnalyses(FAM); 151 PB.registerLoopAnalyses(LAM); 152 PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); 153 154 auto Err = PB.parsePassPipeline(MPM, PassPipeline); 155 assert(!Err && "Should have been checked during fuzzer initialization"); 156 // Only fail with assert above, otherwise ignore the parsing error. 157 consumeError(std::move(Err)); 158 159 // Run passes which we need to test 160 // 161 162 MPM.run(*M, MAM); 163 164 // Check that passes resulted in a correct code 165 if (verifyModule(*M, &errs())) { 166 errs() << "Transformation resulted in an invalid module\n"; 167 abort(); 168 } 169 170 return 0; 171} 172 173static void handleLLVMFatalError(void *, const std::string &Message, bool) { 174 // TODO: Would it be better to call into the fuzzer internals directly? 175 dbgs() << "LLVM ERROR: " << Message << "\n" 176 << "Aborting to trigger fuzzer exit handling.\n"; 177 abort(); 178} 179 180extern "C" LLVM_ATTRIBUTE_USED int LLVMFuzzerInitialize( 181 int *argc, char ***argv) { 182 EnableDebugBuffering = true; 183 184 // Make sure we print the summary and the current unit when LLVM errors out. 185 install_fatal_error_handler(handleLLVMFatalError, nullptr); 186 187 // Initialize llvm 188 // 189 190 InitializeAllTargets(); 191 InitializeAllTargetMCs(); 192 193 PassRegistry &Registry = *PassRegistry::getPassRegistry(); 194 initializeCore(Registry); 195 initializeCoroutines(Registry); 196 initializeScalarOpts(Registry); 197 initializeObjCARCOpts(Registry); 198 initializeVectorization(Registry); 199 initializeIPO(Registry); 200 initializeAnalysis(Registry); 201 initializeTransformUtils(Registry); 202 initializeInstCombine(Registry); 203 initializeAggressiveInstCombine(Registry); 204 initializeInstrumentation(Registry); 205 initializeTarget(Registry); 206 207 // Parse input options 208 // 209 210 handleExecNameEncodedOptimizerOpts(*argv[0]); 211 parseFuzzerCLOpts(*argc, *argv); 212 213 // Create TargetMachine 214 // 215 216 if (TargetTripleStr.empty()) { 217 errs() << *argv[0] << ": -mtriple must be specified\n"; 218 exit(1); 219 } 220 Triple TargetTriple = Triple(Triple::normalize(TargetTripleStr)); 221 222 std::string Error; 223 const Target *TheTarget = 224 TargetRegistry::lookupTarget(codegen::getMArch(), TargetTriple, Error); 225 if (!TheTarget) { 226 errs() << *argv[0] << ": " << Error; 227 exit(1); 228 } 229 230 TargetOptions Options = 231 codegen::InitTargetOptionsFromCodeGenFlags(TargetTriple); 232 TM.reset(TheTarget->createTargetMachine( 233 TargetTriple.getTriple(), codegen::getCPUStr(), codegen::getFeaturesStr(), 234 Options, codegen::getExplicitRelocModel(), 235 codegen::getExplicitCodeModel(), CodeGenOpt::Default)); 236 assert(TM && "Could not allocate target machine!"); 237 238 // Check that pass pipeline is specified and correct 239 // 240 241 if (PassPipeline.empty()) { 242 errs() << *argv[0] << ": at least one pass should be specified\n"; 243 exit(1); 244 } 245 246 PassBuilder PB(TM.get()); 247 ModulePassManager MPM; 248 if (auto Err = PB.parsePassPipeline(MPM, PassPipeline)) { 249 errs() << *argv[0] << ": " << toString(std::move(Err)) << "\n"; 250 exit(1); 251 } 252 253 // Create mutator 254 // 255 256 Mutator = createOptMutator(); 257 258 return 0; 259} 260