From: Karl Schimpf Date: Mon, 31 Aug 2015 17:55:32 +0000 (+0000) Subject: Build a lib/Fuzzer version for llvm-as. X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=commitdiff_plain;h=1318d71a755481fc0d43be15a4611db96263896d Build a lib/Fuzzer version for llvm-as. Summary: This CL is associated with a fuzzing effort to find bugs in LLVM. The first step is to fuzz llvm-as to find potential issues in generating IR. Both afl-fuzz and LLVM's lib/Fuzzer are being used. This CL introduces the executable that implements the in-process fuzzer using LLVM's lib/Fuzzer. The motivation for using lib/Fuzzer is based on time comparisons between afl-fuzz and lib/Fuzzer. Early results show that per-process, the lib/Fuzzer implemenation of llvm-as (i.e. this CL) generates over 30 times the number of mutations found by afl-fuzz, per hour runtime. The speedup is due to the removal of overhead of forking a process, and loading the executable into memory. I placed this under the tools directory, since it is an executable. It is also only conditionally built if (using cmake) the flag LLVM_USEE_SANITIZE_COVERAGE is used, so that it isn't built by default. Reviewers: kcc, filcab Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D12438 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@246458 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/tools/llvm-as-fuzzer/CMakeLists.txt b/tools/llvm-as-fuzzer/CMakeLists.txt new file mode 100644 index 00000000000..ff9bdaaf4c4 --- /dev/null +++ b/tools/llvm-as-fuzzer/CMakeLists.txt @@ -0,0 +1,13 @@ +if( LLVM_USE_SANITIZE_COVERAGE ) + set(LLVM_LINK_COMPONENTS + AsmParser + BitWriter + Core + Support + ) + add_llvm_tool(llvm-as-fuzzer + llvm-as-fuzzer.cpp) + target_link_libraries(llvm-as-fuzzer + LLVMFuzzer + ) +endif() diff --git a/tools/llvm-as-fuzzer/llvm-as-fuzzer.cpp b/tools/llvm-as-fuzzer/llvm-as-fuzzer.cpp new file mode 100644 index 00000000000..47cea87cc37 --- /dev/null +++ b/tools/llvm-as-fuzzer/llvm-as-fuzzer.cpp @@ -0,0 +1,75 @@ +//===--- fuzz-llvm-as.cpp - Fuzzer for llvm-as using lib/Fuzzer -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Build tool to fuzz the LLVM assembler (llvm-as) using +// lib/Fuzzer. The main reason for using this tool is that it is much +// faster than using afl-fuzz, since it is run in-process. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringRef.h" +#include "llvm/AsmParser/Parser.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Verifier.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/SourceMgr.h" + +#include + +using namespace llvm; + +static jmp_buf JmpBuf; + +namespace { + +void MyFatalErrorHandler(void *user_data, const std::string& reason, + bool gen_crash_diag) { + // Don't bother printing reason, just return to the test function, + // since a fatal error represents a successful parse (i.e. it correctly + // terminated with an error message to the user). + longjmp(JmpBuf, 1); +} + +static bool InstalledHandler = false; + +} // end of anonymous namespace + +extern "C" void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + + // Allocate space for locals before setjmp so that memory can be collected + // if parse exits prematurely (via longjmp). + StringRef Input((const char *)Data, Size); + // Note: We need to create a buffer to add a null terminator to the + // end of the input string. The parser assumes that the string + // parsed is always null terminated. + std::unique_ptr MemBuf = MemoryBuffer::getMemBufferCopy(Input); + SMDiagnostic Err; + LLVMContext &Context = getGlobalContext(); + std::unique_ptr M; + + if (setjmp(JmpBuf)) + // If reached, we have returned with non-zero status, so exit. + return; + + // TODO(kschimpf) Write a main to do this initialization. + if (!InstalledHandler) { + llvm::install_fatal_error_handler(::MyFatalErrorHandler, nullptr); + InstalledHandler = true; + } + + M = parseAssembly(MemBuf->getMemBufferRef(), Err, Context); + + if (!M.get()) + return; + + verifyModule(*M.get()); +}