llvm-project

Форк
0
/
llvm-opt-fuzzer.cpp 
226 строк · 6.5 Кб
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

179
  // Make sure we print the summary and the current unit when LLVM errors out.
180
  install_fatal_error_handler(handleLLVMFatalError, nullptr);
181

182
  // Initialize llvm
183
  //
184

185
  InitializeAllTargets();
186
  InitializeAllTargetMCs();
187

188
  // Parse input options
189
  //
190

191
  handleExecNameEncodedOptimizerOpts(*argv[0]);
192
  parseFuzzerCLOpts(*argc, *argv);
193

194
  // Create TargetMachine
195
  //
196

197
  if (TargetTripleStr.empty()) {
198
    errs() << *argv[0] << ": -mtriple must be specified\n";
199
    exit(1);
200
  }
201
  ExitOnError ExitOnErr(std::string(*argv[0]) + ": 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() << *argv[0] << ": 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() << *argv[0] << ": " << toString(std::move(Err)) << "\n";
217
    exit(1);
218
  }
219

220
  // Create mutator
221
  //
222

223
  Mutator = createOptMutator();
224

225
  return 0;
226
}
227

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.