[PATCH] D36275: Implement llvm-isel-fuzzer for fuzzing instruction selection

Justin Bogner via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 11 10:11:24 PDT 2017


ping

Justin Bogner via Phabricator via llvm-commits <llvm-commits at lists.llvm.org> writes:
> bogner updated this revision to Diff 109634.
> bogner marked 3 inline comments as done.
> bogner added inline comments.
>
> ================
> Comment at: tools/llvm-isel-fuzzer/llvm-isel-fuzzer.cpp:99
> +  std::unique_ptr<Module> M;
> +  if (Size == 0 || (Size == 1 && *Data == '\n'))
> +    // We get bogus data given an empty corpus - just create a new module.
> ----------------
> kcc wrote:
>> Will it be simpler and better to just assume that Size <= 1 is
>> uninteresting and means a new module?
> Makes sense, I'll do that.
>
>
> ================
> Comment at: tools/llvm-isel-fuzzer/llvm-isel-fuzzer.cpp:117
> +    errs() << "Mutator failed to make progress.\n";
> +    return 1;
> +  }
> ----------------
> kcc wrote:
>> currently the non-zero return value for LLVMFuzzerTestOneInput will
>> call an error in libFuzzer.
>> Also, an ideal fuzz target must tolerate any kind of input, even if
>> we never expect to see it.
> Calling an error is kind of the point here. We get here when the
> mutator can't do any work (due to MutateImpl giving up and returning '
> ', which is also not part of the contract), but to return 0 would mean
> we just spin forever doing nothing rather than alert the user that
> there's a problem.
>
> That said, this is much less of a problem now that the default max_len
> was bumped to 4096. When it was 64 you'd hit this very quickly if you
> forgot to override that. I'm fairly comfortable just returning zero
> here now, I think.
>
> https://reviews.llvm.org/D36275
>
> Files:
>   tools/llvm-isel-fuzzer/CMakeLists.txt
>   tools/llvm-isel-fuzzer/llvm-isel-fuzzer.cpp
>
> Index: tools/llvm-isel-fuzzer/llvm-isel-fuzzer.cpp
> ===================================================================
> --- /dev/null
> +++ tools/llvm-isel-fuzzer/llvm-isel-fuzzer.cpp
> @@ -0,0 +1,213 @@
> +//===--- llvm-isel-fuzzer.cpp - Fuzzer for instruction selection ----------===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// Tool to fuzz instruction selection using libFuzzer.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#include "FuzzerInterface.h"
> +#include "llvm/ADT/StringRef.h"
> +#include "llvm/Analysis/TargetLibraryInfo.h"
> +#include "llvm/Bitcode/BitcodeReader.h"
> +#include "llvm/Bitcode/BitcodeWriter.h"
> +#include "llvm/CodeGen/CommandFlags.h"
> +#include "llvm/FuzzMutate/IRMutator.h"
> +#include "llvm/FuzzMutate/Operations.h"
> +#include "llvm/FuzzMutate/Random.h"
> +#include "llvm/IR/Constants.h"
> +#include "llvm/IR/LLVMContext.h"
> +#include "llvm/IR/LegacyPassManager.h"
> +#include "llvm/IR/Module.h"
> +#include "llvm/IR/Verifier.h"
> +#include "llvm/IRReader/IRReader.h"
> +#include "llvm/Support/DataTypes.h"
> +#include "llvm/Support/Debug.h"
> +#include "llvm/Support/SourceMgr.h"
> +#include "llvm/Support/TargetRegistry.h"
> +#include "llvm/Support/TargetSelect.h"
> +#include "llvm/Target/TargetMachine.h"
> +#include <random>
> +
> +#define DEBUG_TYPE "isel-fuzzer"
> +
> +using namespace llvm;
> +
> +static cl::opt<char>
> +OptLevel("O",
> +         cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
> +                  "(default = '-O2')"),
> +         cl::Prefix,
> +         cl::ZeroOrMore,
> +         cl::init(' '));
> +
> +static cl::opt<std::string>
> +TargetTriple("mtriple", cl::desc("Override target triple for module"));
> +
> +static std::unique_ptr<TargetMachine> TM;
> +static std::unique_ptr<IRMutator> Mutator;
> +
> +static std::unique_ptr<Module> parseModule(const uint8_t *Data, size_t Size,
> +                                           LLVMContext &Context) {
> +  auto Buffer = MemoryBuffer::getMemBuffer(
> +      StringRef(reinterpret_cast<const char *>(Data), Size), "Fuzzer input",
> +      /*RequiresNullTerminator=*/false);
> +
> +  SMDiagnostic Err;
> +  auto M = parseBitcodeFile(Buffer->getMemBufferRef(), Context);
> +  if (Error E = M.takeError()) {
> +    errs() << toString(std::move(E)) << "\n";
> +    return nullptr;
> +  }
> +  return std::move(M.get());
> +}
> +
> +static size_t writeModule(const Module &M, uint8_t *Dest, size_t MaxSize) {
> +  std::string Buf;
> +  {
> +    raw_string_ostream OS(Buf);
> +    WriteBitcodeToFile(&M, OS);
> +  }
> +  if (Buf.size() > MaxSize)
> +    return 0;
> +  memcpy(Dest, Buf.data(), Buf.size());
> +  return Buf.size();
> +}
> +
> +std::unique_ptr<IRMutator> createISelMutator() {
> +  std::vector<TypeGetter> Types{
> +      Type::getInt1Ty,  Type::getInt8Ty,  Type::getInt16Ty, Type::getInt32Ty,
> +      Type::getInt64Ty, Type::getFloatTy, Type::getDoubleTy};
> +
> +  std::vector<std::unique_ptr<IRMutationStrategy>> Strategies;
> +  Strategies.emplace_back(
> +      new InjectorIRStrategy(InjectorIRStrategy::getDefaultOps()));
> +  Strategies.emplace_back(new InstDeleterIRStrategy());
> +
> +  return make_unique<IRMutator>(std::move(Types), std::move(Strategies));
> +}
> +
> +extern "C" LLVM_ATTRIBUTE_USED size_t LLVMFuzzerCustomMutator(
> +    uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed) {
> +  LLVMContext Context;
> +  std::unique_ptr<Module> M;
> +  if (Size <= 1)
> +    // We get bogus data given an empty corpus - just create a new module.
> +    M.reset(new Module("M", Context));
> +  else
> +    M = parseModule(Data, Size, Context);
> +
> +  Mutator->mutateModule(*M, Seed, Size, MaxSize);
> +
> +  return writeModule(*M, Data, MaxSize);
> +}
> +
> +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
> +  if (Size <= 1)
> +    // We get bogus data given an empty corpus - ignore it.
> +    return 0;
> +
> +  LLVMContext Context;
> +  auto M = parseModule(Data, Size, Context);
> +  if (!M || verifyModule(*M, &errs())) {
> +    errs() << "error: input module is broken!\n";
> +    return 1;
> +  }
> +
> +  // Set up the module to build for our target.
> +  M->setTargetTriple(TM->getTargetTriple().normalize());
> +  M->setDataLayout(TM->createDataLayout());
> +
> +  // Build up a PM to do instruction selection.
> +  legacy::PassManager PM;
> +  TargetLibraryInfoImpl TLII(TM->getTargetTriple());
> +  PM.add(new TargetLibraryInfoWrapperPass(TLII));
> +  raw_null_ostream OS;
> +  TM->addPassesToEmitFile(PM, OS, TargetMachine::CGFT_Null);
> +  PM.run(*M);
> +
> +  return 0;
> +}
> +
> +/// Parse command line options, but ignore anything before '--'.
> +static void parseCLOptsAfterDashDash(int argc, char *argv[]) {
> +  std::vector<const char *> CLArgs;
> +  CLArgs.push_back(argv[0]);
> +
> +  int I = 1;
> +  while (I < argc)
> +    if (StringRef(argv[I++]).equals("-ignore_remaining_args=1"))
> +      break;
> +  while (I < argc)
> +    CLArgs.push_back(argv[I++]);
> +
> +  cl::ParseCommandLineOptions(CLArgs.size(), CLArgs.data());
> +}
> +
> +static void handleLLVMFatalError(void *, const std::string &Message, bool) {
> +  // TODO: Would it be better to call into the fuzzer internals directly?
> +  dbgs() << "LLVM ERROR: " << Message << "\n"
> +         << "Aborting to trigger fuzzer exit handling.\n";
> +  abort();
> +}
> +
> +extern "C" LLVM_ATTRIBUTE_USED int LLVMFuzzerInitialize(int *argc,
> +                                                        char ***argv) {
> +  EnableDebugBuffering = true;
> +
> +  InitializeAllTargets();
> +  InitializeAllTargetMCs();
> +  InitializeAllAsmPrinters();
> +  InitializeAllAsmParsers();
> +
> +  parseCLOptsAfterDashDash(*argc, *argv);
> +
> +  if (TargetTriple.empty()) {
> +    errs() << *argv[0] << ": -mtriple must be specified\n";
> +    return 1;
> +  }
> +
> +  Triple TheTriple = Triple(Triple::normalize(TargetTriple));
> +
> +  // Get the target specific parser.
> +  std::string Error;
> +  const Target *TheTarget =
> +      TargetRegistry::lookupTarget(MArch, TheTriple, Error);
> +  if (!TheTarget) {
> +    errs() << argv[0] << ": " << Error;
> +    return 1;
> +  }
> +
> +  // Set up the pipeline like llc does.
> +  std::string CPUStr = getCPUStr(), FeaturesStr = getFeaturesStr();
> +
> +  CodeGenOpt::Level OLvl = CodeGenOpt::Default;
> +  switch (OptLevel) {
> +  default:
> +    errs() << argv[0] << ": invalid optimization level.\n";
> +    return 1;
> +  case ' ': break;
> +  case '0': OLvl = CodeGenOpt::None; break;
> +  case '1': OLvl = CodeGenOpt::Less; break;
> +  case '2': OLvl = CodeGenOpt::Default; break;
> +  case '3': OLvl = CodeGenOpt::Aggressive; break;
> +  }
> +
> +  TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
> +  TM.reset(TheTarget->createTargetMachine(TheTriple.getTriple(), CPUStr,
> +                                          FeaturesStr, Options, getRelocModel(),
> +                                          getCodeModel(), OLvl));
> +  assert(TM && "Could not allocate target machine!");
> +
> +  // Make sure we print the summary and the current unit when LLVM errors out.
> +  install_fatal_error_handler(handleLLVMFatalError, nullptr);
> +
> +  // Finally, create our mutator.
> +  Mutator = createISelMutator();
> +  return 0;
> +}
> Index: tools/llvm-isel-fuzzer/CMakeLists.txt
> ===================================================================
> --- /dev/null
> +++ tools/llvm-isel-fuzzer/CMakeLists.txt
> @@ -0,0 +1,23 @@
> +if( LLVM_USE_SANITIZE_COVERAGE )
> +  include_directories(BEFORE
> +    ${CMAKE_CURRENT_SOURCE_DIR}/../../lib/Fuzzer)
> +
> +  set(LLVM_LINK_COMPONENTS
> +      ${LLVM_TARGETS_TO_BUILD}
> +      Analysis
> +      AsmPrinter
> +      CodeGen
> +      Core
> +      FuzzMutate
> +      IRReader
> +      MC
> +      ScalarOpts
> +      SelectionDAG
> +      Support
> +      Target
> +  )
> +  add_llvm_tool(llvm-isel-fuzzer
> +                llvm-isel-fuzzer.cpp)
> +  target_link_libraries(llvm-isel-fuzzer
> +                        LLVMFuzzer)
> +endif()
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits


More information about the llvm-commits mailing list