/// 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
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/IR/Verifier.h"
using namespace llvm;
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;
+}
"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) {
//
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;
}