diff --git a/llvm/include/llvm/FuzzMutate/FuzzerCLI.h b/llvm/include/llvm/FuzzMutate/FuzzerCLI.h --- a/llvm/include/llvm/FuzzMutate/FuzzerCLI.h +++ b/llvm/include/llvm/FuzzMutate/FuzzerCLI.h @@ -20,8 +20,6 @@ namespace llvm { -class LLVMContext; -class Module; class StringRef; /// Parse cl::opts from a fuzz target commandline. @@ -54,29 +52,6 @@ int runFuzzerOnInputs(int ArgC, char *ArgV[], FuzzerTestFun TestOne, FuzzerInitFun Init = [](int *, char ***) { return 0; }); -/// Fuzzer friendly interface for the llvm bitcode parser. -/// -/// \param Data Bitcode we are going to parse -/// \param Size Size of the 'Data' in bytes -/// \return New module or nullptr in case of error -std::unique_ptr parseModule(const uint8_t *Data, size_t Size, - LLVMContext &Context); - -/// Fuzzer friendly interface for the llvm bitcode printer. -/// -/// \param M Module to print -/// \param Dest Location to store serialized module -/// \param MaxSize Size of the destination buffer -/// \return Number of bytes that were written. When module size exceeds MaxSize -/// returns 0 and leaves Dest unchanged. -size_t writeModule(const Module &M, uint8_t *Dest, size_t MaxSize); - -/// Try to parse module and verify it. May output verification errors to the -/// errs(). -/// \return New module or nullptr in case of error. -std::unique_ptr parseAndVerify(const uint8_t *Data, size_t Size, - LLVMContext &Context); - -} // end llvm namespace +} // namespace llvm #endif // LLVM_FUZZMUTATE_FUZZERCLI_H diff --git a/llvm/include/llvm/FuzzMutate/IRMutator.h b/llvm/include/llvm/FuzzMutate/IRMutator.h --- a/llvm/include/llvm/FuzzMutate/IRMutator.h +++ b/llvm/include/llvm/FuzzMutate/IRMutator.h @@ -10,6 +10,9 @@ // configurable set of strategies. Some common strategies are also included // here. // +// Fuzzer-friendly (de)serialization functions are also provided, as these +// are usually needed when mutating IR. +// //===----------------------------------------------------------------------===// #ifndef LLVM_FUZZMUTATE_IRMUTATOR_H @@ -113,6 +116,29 @@ void mutate(Instruction &Inst, RandomIRBuilder &IB) override; }; +/// Fuzzer friendly interface for the llvm bitcode parser. +/// +/// \param Data Bitcode we are going to parse +/// \param Size Size of the 'Data' in bytes +/// \return New module or nullptr in case of error +std::unique_ptr parseModule(const uint8_t *Data, size_t Size, + LLVMContext &Context); + +/// Fuzzer friendly interface for the llvm bitcode printer. +/// +/// \param M Module to print +/// \param Dest Location to store serialized module +/// \param MaxSize Size of the destination buffer +/// \return Number of bytes that were written. When module size exceeds MaxSize +/// returns 0 and leaves Dest unchanged. +size_t writeModule(const Module &M, uint8_t *Dest, size_t MaxSize); + +/// Try to parse module and verify it. May output verification errors to the +/// errs(). +/// \return New module or nullptr in case of error. +std::unique_ptr parseAndVerify(const uint8_t *Data, size_t Size, + LLVMContext &Context); + } // end llvm namespace #endif // LLVM_FUZZMUTATE_IRMUTATOR_H diff --git a/llvm/lib/FuzzMutate/FuzzerCLI.cpp b/llvm/lib/FuzzMutate/FuzzerCLI.cpp --- a/llvm/lib/FuzzMutate/FuzzerCLI.cpp +++ b/llvm/lib/FuzzMutate/FuzzerCLI.cpp @@ -9,14 +9,8 @@ #include "llvm/FuzzMutate/FuzzerCLI.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" -#include "llvm/Bitcode/BitcodeReader.h" -#include "llvm/Bitcode/BitcodeWriter.h" -#include "llvm/IR/Verifier.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/Error.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -165,44 +159,3 @@ } return 0; } - -std::unique_ptr llvm::parseModule( - const uint8_t *Data, size_t Size, LLVMContext &Context) { - - if (Size <= 1) - // We get bogus data given an empty corpus - just create a new module. - return std::make_unique("M", Context); - - auto Buffer = MemoryBuffer::getMemBuffer( - StringRef(reinterpret_cast(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()); -} - -size_t llvm::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 llvm::parseAndVerify(const uint8_t *Data, size_t Size, - LLVMContext &Context) { - auto M = parseModule(Data, Size, Context); - if (!M || verifyModule(*M, &errs())) - return nullptr; - - return M; -} diff --git a/llvm/lib/FuzzMutate/IRMutator.cpp b/llvm/lib/FuzzMutate/IRMutator.cpp --- a/llvm/lib/FuzzMutate/IRMutator.cpp +++ b/llvm/lib/FuzzMutate/IRMutator.cpp @@ -9,6 +9,8 @@ #include "llvm/FuzzMutate/IRMutator.h" #include "llvm/ADT/Optional.h" #include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/Bitcode/BitcodeReader.h" +#include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/FuzzMutate/Operations.h" #include "llvm/FuzzMutate/Random.h" #include "llvm/FuzzMutate/RandomIRBuilder.h" @@ -17,6 +19,9 @@ #include "llvm/IR/InstIterator.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Verifier.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SourceMgr.h" #include "llvm/Transforms/Scalar/DCE.h" using namespace llvm; @@ -243,3 +248,44 @@ if (RS) RS.getSelection()(); } + +std::unique_ptr llvm::parseModule(const uint8_t *Data, size_t Size, + LLVMContext &Context) { + + if (Size <= 1) + // We get bogus data given an empty corpus - just create a new module. + return std::make_unique("M", Context); + + auto Buffer = MemoryBuffer::getMemBuffer( + StringRef(reinterpret_cast(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()); +} + +size_t llvm::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 llvm::parseAndVerify(const uint8_t *Data, size_t Size, + LLVMContext &Context) { + auto M = parseModule(Data, Size, Context); + if (!M || verifyModule(*M, &errs())) + return nullptr; + + return M; +}