llvm-isel-fuzzer: Handle a subset of backend flags in the executable name

Here we add a secondary option parser to llvm-isel-fuzzer (and provide
it for use with other fuzzers). With this, you can copy the fuzzer to
a name like llvm-isel-fuzzer:aarch64-gisel for a fuzzer that fuzzer
AArch64 with GlobalISel enabled, or fuzzer:x86_64 to fuzz x86, with no
flags required. This should be useful for running these in OSS-Fuzz.

Note that this handrolls a subset of cl::opts to recognize, rather
than embedding a complete command parser for argv[0]. If we find we
really need the flexibility of handling arbitrary options at some
point we can rethink this.

llvm-svn: 315545
This commit is contained in:
Justin Bogner 2017-10-12 01:57:49 +00:00
parent b9249fcac2
commit 2b300def19
6 changed files with 87 additions and 1 deletions

View File

@ -76,6 +76,13 @@ the following command would fuzz AArch64 with :doc:`GlobalISel`:
% bin/llvm-isel-fuzzer <corpus-dir> -ignore_remaining_args=1 -mtriple aarch64 -global-isel -O0
Some flags can also be specified in the binary name itself in order to support
OSS Fuzz, which has trouble with required arguments. To do this, you can copy
or move ``llvm-isel-fuzzer`` to ``llvm-isel-fuzzer:x-y-z``, where x, y, and z
are architecture names (``aarch64``, ``x86_64``), optimization levels (``O0``,
``O2``), or specific keywords like ``gisel`` for enabling global instruction
selection.
llvm-mc-assemble-fuzzer
-----------------------

View File

@ -15,6 +15,7 @@
#ifndef LLVM_FUZZMUTATE_FUZZER_CLI_H
#define LLVM_FUZZMUTATE_FUZZER_CLI_H
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/DataTypes.h"
namespace llvm {
@ -24,6 +25,17 @@ namespace llvm {
/// This handles all arguments after -ignore_remaining_args=1 as cl::opts.
void parseFuzzerCLOpts(int ArgC, char *ArgV[]);
/// Handle backend options that are encoded in the executable name.
///
/// Parses some common backend options out of a specially crafted executable
/// name (argv[0]). For example, a name like llvm-foo-fuzzer:aarch64-gisel might
/// set up an AArch64 triple and the Global ISel selector. This should be called
/// *before* parseFuzzerCLOpts if calling both.
///
/// This is meant to be used for environments like OSS-Fuzz that aren't capable
/// of passing in command line arguments in the normal way.
void handleExecNameEncodedBEOpts(StringRef ExecName);
using FuzzerTestFun = int (*)(const uint8_t *Data, size_t Size);
using FuzzerInitFun = int (*)(int *argc, char ***argv);

View File

@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/FuzzMutate/FuzzerCLI.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Error.h"
@ -31,6 +31,42 @@ void llvm::parseFuzzerCLOpts(int ArgC, char *ArgV[]) {
cl::ParseCommandLineOptions(CLArgs.size(), CLArgs.data());
}
void llvm::handleExecNameEncodedBEOpts(StringRef ExecName) {
std::vector<std::string> Args{ExecName};
auto NameAndArgs = ExecName.split(':');
if (NameAndArgs.second.empty())
return;
SmallVector<StringRef, 4> Opts;
NameAndArgs.second.split(Opts, '-');
for (StringRef Opt : Opts) {
if (Opt.equals("gisel")) {
Args.push_back("-global-isel");
// For now we default GlobalISel to -O0
Args.push_back("-O0");
} else if (Opt.startswith("O")) {
Args.push_back("-" + Opt.str());
} else if (auto Arch = Triple::getArchTypeForLLVMName(Opt)) {
Args.push_back("-mtriple=" + Opt.str());
} else {
errs() << ExecName << ": Unknown option: " << Opt << ".\n";
exit(1);
}
}
errs() << NameAndArgs.first << ": Injected args:";
for (int I = 1, E = Args.size(); I < E; ++I)
errs() << " " << Args[I];
errs() << "\n";
std::vector<const char *> CLArgs;
CLArgs.reserve(Args.size());
for (std::string &S : Args)
CLArgs.push_back(S.c_str());
cl::ParseCommandLineOptions(CLArgs.size(), CLArgs.data());
}
int llvm::runFuzzerOnInputs(int ArgC, char *ArgV[], FuzzerTestFun TestOne,
FuzzerInitFun Init) {
errs() << "*** This tool was not linked to libFuzzer.\n"

View File

@ -0,0 +1,15 @@
; REQUIRES: aarch64-registered-target
; RUN: echo > %t.input
; RUN: cp llvm-isel-fuzzer %t.bin:aarch64
; RUN: %t.bin:aarch64 %t.input 2>&1 | FileCheck -check-prefix=AARCH64 %s
; AARCH64: Injected args: -mtriple=aarch64
; RUN: mv %t.bin:aarch64 %t.bin:aarch64-O1
; RUN: %t.bin:aarch64-O1 %t.input 2>&1 | FileCheck -check-prefix=OPT-AFTER %s
; OPT-AFTER: Injected args: -mtriple=aarch64 -O1
; RUN: mv %t.bin:aarch64-O1 %t.bin:O3-aarch64
; RUN: %t.bin:O3-aarch64 %t.input 2>&1 | FileCheck -check-prefix=OPT-BEFORE %s
; OPT-BEFORE: Injected args: -O3 -mtriple=aarch64

View File

@ -0,0 +1,15 @@
; RUN: echo > %t.input
; RUN: cp llvm-isel-fuzzer %t.bin:gisel
; RUN: not %t.bin:gisel %t.input 2>&1 | FileCheck -check-prefix=GISEL %s
; GISEL: Injected args: -global-isel -O0
; GISEL: -mtriple must be specified
; RUN: cp llvm-isel-fuzzer %t.bin:gisel-O2
; RUN: not %t.bin:gisel-O2 %t.input 2>&1 | FileCheck -check-prefix=GISEL-O2 %s
; GISEL-O2: Injected args: -global-isel -O0 -O2
; GISEL-O2: -mtriple must be specified
; RUN: cp llvm-isel-fuzzer %t.bin:unexist
; RUN: not %t.bin:unexist %t.input 2>&1 | FileCheck -check-prefix=NO-OPT %s
; NO-OPT: Unknown option:

View File

@ -150,6 +150,7 @@ extern "C" LLVM_ATTRIBUTE_USED int LLVMFuzzerInitialize(int *argc,
InitializeAllAsmPrinters();
InitializeAllAsmParsers();
handleExecNameEncodedBEOpts(*argv[0]);
parseFuzzerCLOpts(*argc, *argv);
if (TargetTriple.empty()) {