Coverage Report

Created: 2021-08-24 07:12

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/tools/clang-fuzzer/handle-llvm/handle_llvm.cpp
Line
Count
Source (jump to first uncovered line)
1
//==-- handle_llvm.cpp - Helper function for Clang fuzzers -----------------==//
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
// Implements HandleLLVM for use by the Clang fuzzers. First runs a loop
10
// vectorizer optimization pass over the given IR code. Then mimics lli on both
11
// versions to JIT the generated code and execute it. Currently, functions are 
12
// executed on dummy inputs.
13
//
14
//===----------------------------------------------------------------------===//
15
16
#include "handle_llvm.h"
17
#include "input_arrays.h"
18
19
#include "llvm/ADT/Triple.h"
20
#include "llvm/Analysis/TargetLibraryInfo.h"
21
#include "llvm/Analysis/TargetTransformInfo.h"
22
#include "llvm/CodeGen/CommandFlags.h"
23
#include "llvm/CodeGen/MachineModuleInfo.h"
24
#include "llvm/CodeGen/TargetPassConfig.h"
25
#include "llvm/ExecutionEngine/JITEventListener.h"
26
#include "llvm/ExecutionEngine/JITSymbol.h"
27
#include "llvm/ExecutionEngine/MCJIT.h"
28
#include "llvm/ExecutionEngine/ObjectCache.h"
29
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
30
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
31
#include "llvm/IR/IRPrintingPasses.h"
32
#include "llvm/IR/LLVMContext.h"
33
#include "llvm/IR/LegacyPassManager.h"
34
#include "llvm/IR/LegacyPassNameParser.h"
35
#include "llvm/IR/Module.h"
36
#include "llvm/IR/Verifier.h"
37
#include "llvm/IRReader/IRReader.h"
38
#include "llvm/Pass.h"
39
#include "llvm/PassRegistry.h"
40
#include "llvm/Support/MemoryBuffer.h"
41
#include "llvm/Support/SourceMgr.h"
42
#include "llvm/Support/TargetRegistry.h"
43
#include "llvm/Support/TargetSelect.h"
44
#include "llvm/Target/TargetMachine.h"
45
#include "llvm/Transforms/IPO.h"
46
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
47
#include "llvm/Transforms/Vectorize.h"
48
49
using namespace llvm;
50
51
static codegen::RegisterCodeGenFlags CGF;
52
53
// Define a type for the functions that are compiled and executed
54
typedef void (*LLVMFunc)(int*, int*, int*, int);
55
56
// Helper function to parse command line args and find the optimization level
57
static void getOptLevel(const std::vector<const char *> &ExtraArgs,
58
0
                              CodeGenOpt::Level &OLvl) {
59
  // Find the optimization level from the command line args
60
0
  OLvl = CodeGenOpt::Default;
61
0
  for (auto &A : ExtraArgs) {
62
0
    if (A[0] == '-' && A[1] == 'O') {
63
0
      switch(A[2]) {
64
0
        case '0': OLvl = CodeGenOpt::None; break;
65
0
        case '1': OLvl = CodeGenOpt::Less; break;
66
0
        case '2': OLvl = CodeGenOpt::Default; break;
67
0
        case '3': OLvl = CodeGenOpt::Aggressive; break;
68
0
        default:
69
0
          errs() << "error: opt level must be between 0 and 3.\n";
70
0
          std::exit(1);
71
0
      }
72
0
    }
73
0
  }
74
0
}
75
76
0
static void ErrorAndExit(std::string message) {
77
0
  errs()<< "ERROR: " << message << "\n";
78
0
  std::exit(1);
79
0
}
80
81
// Helper function to add optimization passes to the TargetMachine at the 
82
// specified optimization level, OptLevel
83
static void AddOptimizationPasses(legacy::PassManagerBase &MPM,
84
                                  CodeGenOpt::Level OptLevel,
85
0
                                  unsigned SizeLevel) {
86
  // Create and initialize a PassManagerBuilder
87
0
  PassManagerBuilder Builder;
88
0
  Builder.OptLevel = OptLevel;
89
0
  Builder.SizeLevel = SizeLevel;
90
0
  Builder.Inliner = createFunctionInliningPass(OptLevel, SizeLevel, false);
91
0
  Builder.LoopVectorize = true;
92
0
  Builder.populateModulePassManager(MPM);
93
0
}
94
95
// Mimics the opt tool to run an optimization pass over the provided IR
96
0
static std::string OptLLVM(const std::string &IR, CodeGenOpt::Level OLvl) {
97
  // Create a module that will run the optimization passes
98
0
  SMDiagnostic Err;
99
0
  LLVMContext Context;
100
0
  std::unique_ptr<Module> M = parseIR(MemoryBufferRef(IR, "IR"), Err, Context);
101
0
  if (!M || verifyModule(*M, &errs()))
102
0
    ErrorAndExit("Could not parse IR");
103
104
0
  Triple ModuleTriple(M->getTargetTriple());
105
0
  const TargetOptions Options =
106
0
      codegen::InitTargetOptionsFromCodeGenFlags(ModuleTriple);
107
0
  std::string E;
108
0
  const Target *TheTarget =
109
0
      TargetRegistry::lookupTarget(codegen::getMArch(), ModuleTriple, E);
110
0
  if (!TheTarget)
111
0
    ErrorAndExit(E);
112
113
0
  std::unique_ptr<TargetMachine> TM(TheTarget->createTargetMachine(
114
0
      M->getTargetTriple(), codegen::getCPUStr(), codegen::getFeaturesStr(),
115
0
      Options, codegen::getExplicitRelocModel(),
116
0
      codegen::getExplicitCodeModel(), OLvl));
117
0
  if (!TM)
118
0
    ErrorAndExit("Could not create target machine");
119
120
0
  codegen::setFunctionAttributes(codegen::getCPUStr(),
121
0
                                 codegen::getFeaturesStr(), *M);
122
123
0
  legacy::PassManager Passes;
124
  
125
0
  Passes.add(new TargetLibraryInfoWrapperPass(ModuleTriple));
126
0
  Passes.add(createTargetTransformInfoWrapperPass(TM->getTargetIRAnalysis()));
127
128
0
  LLVMTargetMachine &LTM = static_cast<LLVMTargetMachine &>(*TM);
129
0
  Passes.add(LTM.createPassConfig(Passes));
130
131
0
  Passes.add(createVerifierPass());
132
133
0
  AddOptimizationPasses(Passes, OLvl, 0);
134
135
  // Add a pass that writes the optimized IR to an output stream
136
0
  std::string outString;
137
0
  raw_string_ostream OS(outString);
138
0
  Passes.add(createPrintModulePass(OS, "", false));
139
140
0
  Passes.run(*M);
141
142
0
  return OS.str();
143
0
}
144
145
// Takes a function and runs it on a set of inputs
146
// First determines whether f is the optimized or unoptimized function
147
0
static void RunFuncOnInputs(LLVMFunc f, int Arr[kNumArrays][kArraySize]) {
148
0
  for (int i = 0; i < kNumArrays / 3; i++)
149
0
    f(Arr[i], Arr[i + (kNumArrays / 3)], Arr[i + (2 * kNumArrays / 3)],
150
0
      kArraySize);
151
0
}
152
153
// Takes a string of IR and compiles it using LLVM's JIT Engine
154
0
static void CreateAndRunJITFunc(const std::string &IR, CodeGenOpt::Level OLvl) {
155
0
  SMDiagnostic Err;
156
0
  LLVMContext Context;
157
0
  std::unique_ptr<Module> M = parseIR(MemoryBufferRef(IR, "IR"), Err, Context);
158
0
  if (!M)
159
0
    ErrorAndExit("Could not parse IR");
160
161
0
  Function *EntryFunc = M->getFunction("foo");
162
0
  if (!EntryFunc)
163
0
    ErrorAndExit("Function not found in module");
164
165
0
  std::string ErrorMsg;
166
0
  Triple ModuleTriple(M->getTargetTriple());
167
168
0
  EngineBuilder builder(std::move(M));
169
0
  builder.setMArch(codegen::getMArch());
170
0
  builder.setMCPU(codegen::getCPUStr());
171
0
  builder.setMAttrs(codegen::getFeatureList());
172
0
  builder.setErrorStr(&ErrorMsg);
173
0
  builder.setEngineKind(EngineKind::JIT);
174
0
  builder.setMCJITMemoryManager(std::make_unique<SectionMemoryManager>());
175
0
  builder.setOptLevel(OLvl);
176
0
  builder.setTargetOptions(
177
0
      codegen::InitTargetOptionsFromCodeGenFlags(ModuleTriple));
178
179
0
  std::unique_ptr<ExecutionEngine> EE(builder.create());
180
0
  if (!EE)
181
0
    ErrorAndExit("Could not create execution engine");
182
183
0
  EE->finalizeObject();
184
0
  EE->runStaticConstructorsDestructors(false);
185
186
0
#if defined(__GNUC__) && !defined(__clang) &&                                  \
187
0
    ((__GNUC__ == 4) && (__GNUC_MINOR__ < 9))
188
// Silence
189
//
190
//   warning: ISO C++ forbids casting between pointer-to-function and
191
//   pointer-to-object [-Wpedantic]
192
//
193
// Since C++11 this casting is conditionally supported and GCC versions
194
// starting from 4.9.0 don't warn about the cast.
195
0
#pragma GCC diagnostic push
196
0
#pragma GCC diagnostic ignored "-Wpedantic"
197
0
#endif
198
0
  LLVMFunc f = reinterpret_cast<LLVMFunc>(EE->getPointerToFunction(EntryFunc));
199
0
#if defined(__GNUC__) && !defined(__clang) &&                                  \
200
0
    ((__GNUC__ == 4) && (__GNUC_MINOR__ < 9))
201
0
#pragma GCC diagnostic pop
202
0
#endif
203
204
  // Figure out if we are running the optimized func or the unoptimized func
205
0
  RunFuncOnInputs(f, (OLvl == CodeGenOpt::None) ? UnoptArrays : OptArrays);
206
207
0
  EE->runStaticConstructorsDestructors(true);
208
0
}
209
210
// Main fuzz target called by ExampleClangLLVMProtoFuzzer.cpp
211
// Mimics the lli tool to JIT the LLVM IR code and execute it
212
void clang_fuzzer::HandleLLVM(const std::string &IR,
213
0
                              const std::vector<const char *> &ExtraArgs) {
214
  // Populate OptArrays and UnoptArrays with the arrays from InputArrays
215
0
  memcpy(OptArrays, InputArrays, kTotalSize);
216
0
  memcpy(UnoptArrays, InputArrays, kTotalSize);
217
218
  // Parse ExtraArgs to set the optimization level
219
0
  CodeGenOpt::Level OLvl;
220
0
  getOptLevel(ExtraArgs, OLvl);
221
222
  // First we optimize the IR by running a loop vectorizer pass
223
0
  std::string OptIR = OptLLVM(IR, OLvl);
224
225
0
  CreateAndRunJITFunc(OptIR, OLvl);
226
0
  CreateAndRunJITFunc(IR, CodeGenOpt::None);
227
228
0
  if (memcmp(OptArrays, UnoptArrays, kTotalSize))
229
0
    ErrorAndExit("!!!BUG!!!");
230
231
0
  return;
232
0
}