From a5969ce15f79622b5c5ea399e05c4606fda99074 Mon Sep 17 00:00:00 2001 From: Justin Bogner Date: Thu, 12 Oct 2017 01:57:49 +0000 Subject: [PATCH] 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 --- llvm/docs/FuzzingLLVM.rst | 7 ++++ llvm/include/llvm/FuzzMutate/FuzzerCLI.h | 12 ++++++ llvm/lib/FuzzMutate/FuzzerCLI.cpp | 38 ++++++++++++++++++- .../aarch64-execname-options.ll | 15 ++++++++ .../llvm-isel-fuzzer/execname-options.ll | 15 ++++++++ .../llvm-isel-fuzzer/llvm-isel-fuzzer.cpp | 1 + 6 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 llvm/test/tools/llvm-isel-fuzzer/aarch64-execname-options.ll create mode 100644 llvm/test/tools/llvm-isel-fuzzer/execname-options.ll diff --git a/llvm/docs/FuzzingLLVM.rst b/llvm/docs/FuzzingLLVM.rst index 6aa0be7d19ff..279ea668e76f 100644 --- a/llvm/docs/FuzzingLLVM.rst +++ b/llvm/docs/FuzzingLLVM.rst @@ -76,6 +76,13 @@ the following command would fuzz AArch64 with :doc:`GlobalISel`: % bin/llvm-isel-fuzzer -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 ----------------------- diff --git a/llvm/include/llvm/FuzzMutate/FuzzerCLI.h b/llvm/include/llvm/FuzzMutate/FuzzerCLI.h index 83c8356247e1..4cb32cefc917 100644 --- a/llvm/include/llvm/FuzzMutate/FuzzerCLI.h +++ b/llvm/include/llvm/FuzzMutate/FuzzerCLI.h @@ -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); diff --git a/llvm/lib/FuzzMutate/FuzzerCLI.cpp b/llvm/lib/FuzzMutate/FuzzerCLI.cpp index 3b71cde5af7c..144f1f579ea4 100644 --- a/llvm/lib/FuzzMutate/FuzzerCLI.cpp +++ b/llvm/lib/FuzzMutate/FuzzerCLI.cpp @@ -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 Args{ExecName}; + + auto NameAndArgs = ExecName.split(':'); + if (NameAndArgs.second.empty()) + return; + + SmallVector 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 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" diff --git a/llvm/test/tools/llvm-isel-fuzzer/aarch64-execname-options.ll b/llvm/test/tools/llvm-isel-fuzzer/aarch64-execname-options.ll new file mode 100644 index 000000000000..e3974b54ca57 --- /dev/null +++ b/llvm/test/tools/llvm-isel-fuzzer/aarch64-execname-options.ll @@ -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 diff --git a/llvm/test/tools/llvm-isel-fuzzer/execname-options.ll b/llvm/test/tools/llvm-isel-fuzzer/execname-options.ll new file mode 100644 index 000000000000..8ebc1e96ddc8 --- /dev/null +++ b/llvm/test/tools/llvm-isel-fuzzer/execname-options.ll @@ -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: diff --git a/llvm/tools/llvm-isel-fuzzer/llvm-isel-fuzzer.cpp b/llvm/tools/llvm-isel-fuzzer/llvm-isel-fuzzer.cpp index 314acdb5087d..164c85f95166 100644 --- a/llvm/tools/llvm-isel-fuzzer/llvm-isel-fuzzer.cpp +++ b/llvm/tools/llvm-isel-fuzzer/llvm-isel-fuzzer.cpp @@ -150,6 +150,7 @@ extern "C" LLVM_ATTRIBUTE_USED int LLVMFuzzerInitialize(int *argc, InitializeAllAsmPrinters(); InitializeAllAsmParsers(); + handleExecNameEncodedBEOpts(*argv[0]); parseFuzzerCLOpts(*argc, *argv); if (TargetTriple.empty()) {