1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 12:41:49 +01:00

[llvm-opt-fuzzer] Avoid adding incorrect inputs to the fuzzer corpus

Differential Revision: https://reviews.llvm.org/D42414

llvm-svn: 324225
This commit is contained in:
Igor Laevsky 2018-02-05 11:05:47 +00:00
parent 213729c26a
commit 4f2f540e75
4 changed files with 48 additions and 10 deletions

View File

@ -68,6 +68,12 @@ std::unique_ptr<Module> parseModule(const uint8_t *Data, size_t Size,
/// 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<Module> parseAndVerify(const uint8_t *Data, size_t Size,
LLVMContext &Context);
} // end llvm namespace
#endif // LLVM_FUZZMUTATE_FUZZER_CLI_H

View File

@ -18,6 +18,7 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/Verifier.h"
using namespace llvm;
@ -175,3 +176,12 @@ size_t llvm::writeModule(const Module &M, uint8_t *Dest, size_t MaxSize) {
memcpy(Dest, Buf.data(), Buf.size());
return Buf.size();
}
std::unique_ptr<Module> 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;
}

View File

@ -84,8 +84,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
return 0;
LLVMContext Context;
auto M = parseModule(Data, Size, Context);
if (!M || verifyModule(*M, &errs())) {
auto M = parseAndVerify(Data, Size, Context);
if (!M) {
errs() << "error: input module is broken!\n";
return 0;
}

View File

@ -57,23 +57,45 @@ extern "C" LLVM_ATTRIBUTE_USED size_t LLVMFuzzerCustomMutator(
"IR mutator should have been created during fuzzer initialization");
LLVMContext Context;
auto M = parseModule(Data, Size, Context);
if (!M || verifyModule(*M, &errs())) {
auto M = parseAndVerify(Data, Size, Context);
if (!M) {
errs() << "error: mutator input module is broken!\n";
return 0;
}
Mutator->mutateModule(*M, Seed, Size, MaxSize);
#ifndef NDEBUG
if (verifyModule(*M, &errs())) {
errs() << "mutation result doesn't pass verification\n";
M->dump();
abort();
// Avoid adding incorrect test cases to the corpus.
return 0;
}
std::string Buf;
{
raw_string_ostream OS(Buf);
WriteBitcodeToFile(M.get(), OS);
}
if (Buf.size() > MaxSize)
return 0;
// There are some invariants which are not checked by the verifier in favor
// of having them checked by the parser. They may be considered as bugs in the
// verifier and should be fixed there. However until all of those are covered
// we want to check for them explicitly. Otherwise we will add incorrect input
// to the corpus and this is going to confuse the fuzzer which will start
// exploration of the bitcode reader error handling code.
auto NewM = parseAndVerify(
reinterpret_cast<const uint8_t*>(Buf.data()), Buf.size(), Context);
if (!NewM) {
errs() << "mutator failed to re-read the module\n";
M->dump();
return 0;
}
#endif
return writeModule(*M, Data, MaxSize);
memcpy(Data, Buf.data(), Buf.size());
return Buf.size();
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
@ -87,8 +109,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
//
LLVMContext Context;
auto M = parseModule(Data, Size, Context);
if (!M || verifyModule(*M, &errs())) {
auto M = parseAndVerify(Data, Size, Context);
if (!M) {
errs() << "error: input module is broken!\n";
return 0;
}