Coverage Report

Created: 2020-02-15 09:57

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