Index: lib/Fuzzer/FuzzerFnAdapter.h =================================================================== --- lib/Fuzzer/FuzzerFnAdapter.h +++ lib/Fuzzer/FuzzerFnAdapter.h @@ -15,13 +15,17 @@ #ifndef LLVM_FUZZER_ADAPTER_H #define LLVM_FUZZER_ADAPTER_H +#include #include #include +#include #include #include #include +#include "FuzzerInterface.h" + namespace fuzzer { /// Unpacks bytes from \p Data according to \p F argument types @@ -53,10 +57,38 @@ template size_t UnpackSingle(const uint8_t *Data, size_t Size, T *Value); +template +size_t PackPrimitive(const T& Value, uint8_t* Data, size_t Size) { + if (Size < sizeof(T)) + return Size; + *reinterpret_cast(Data) = Value; + return Size - sizeof(T); +} + +template +size_t PackSingle(const T& Value, uint8_t *Data, size_t Size); + +template +size_t MutateSingle(T* Value, size_t MaxSize); + +template +size_t MutatePrimitive(T* Value) { + Mutate(reinterpret_cast(Value), sizeof(T), sizeof(T)); + return sizeof(T); +} + #define UNPACK_SINGLE_PRIMITIVE(Type) \ template <> \ size_t UnpackSingle(const uint8_t *Data, size_t Size, Type *Value) { \ return UnpackPrimitive(Data, Size, Value); \ + } \ + template <> \ + size_t PackSingle(const Type& Value, uint8_t *Data, size_t Size) { \ + return PackPrimitive(Value, Data, Size); \ + } \ + template <> \ + size_t MutateSingle(Type* Value, size_t MaxSize) { \ + return MutatePrimitive(Value); \ } UNPACK_SINGLE_PRIMITIVE(char) @@ -103,6 +135,26 @@ return Size - Len - 1; } +template <> +size_t PackSingle(const std::string& Value, uint8_t *Data, size_t Size) { + size_t Len = Value.size(); + if (Size < 1 + Len) + return Size; + assert(Len < 256); + *Data = static_cast(Len); + memcpy(Data + 1, Value.c_str(), Len); + return Size - Len - 1; +} + +template <> +size_t MutateSingle(std::string* Value, size_t MaxSize) { + size_t Len = Value->size(); + Value->resize(MaxSize); + size_t NewLen = Mutate(reinterpret_cast(&((*Value)[0u])), Len, MaxSize); + Value->resize(NewLen); + return NewLen; +} + // Unpacking into arbitrary tuple. // Recursion guard. @@ -130,6 +182,31 @@ return UnpackImpl<0, std::tuple>(Data, Size, Tuple); } +// Pack aribtrary tuple into bytes. + +template +typename std::enable_if::value, size_t>::type +PackImpl(const TupleT& Tuple, uint8_t *Data, size_t Size) { + return Size; +} + +// Unpack tuple elements starting from Nth. +template +typename std::enable_if::value, size_t>::type +PackImpl(const TupleT& Tuple, uint8_t *Data, size_t Size) { + size_t NewSize = PackSingle(std::get(Tuple), Data, Size); + if (NewSize == Size) { + return Size; + } + + return (Size - NewSize) + PackImpl(Tuple, Data + (Size - NewSize), NewSize); +} + +template +size_t Pack(const std::tuple& Tuple, uint8_t *Data, size_t Size) { + return PackImpl<0, std::tuple>(Tuple, Data, Size); +} + // Helper integer sequence templates. template struct Seq {}; @@ -175,12 +252,58 @@ return true; } + +using MutatorFn = std::function; + +template +typename std::enable_if::type +BuildMutators(std::vector* Mutators, std::tuple* Tuple) { } + +template +typename std::enable_if::type +BuildMutators(std::vector* Mutators, std::tuple* Tuple) { + auto ValuePtr = &std::get(*Tuple); + Mutators->push_back([ValuePtr](size_t MaxSize) { + return MutateSingle(ValuePtr, MaxSize); + }); + BuildMutators(Mutators, Tuple); +} + + +template +void Mutate(std::tuple* Tuple, size_t MaxSize, unsigned int Seed) { + std::mt19937 Random(Seed); + + std::vector Mutators; + BuildMutators<0, Args...>(&Mutators, Tuple); + + for (int Iter = 0; Iter < 10; Iter++) { + size_t FieldIdx = Random() % sizeof...(Args); + Mutators[FieldIdx](MaxSize); + } +} + +template size_t AdaptMutator(Fn F, uint8_t *Data, size_t Size, + size_t MaxSize, unsigned int Seed) { + typename FnTraits::ArgsTupleT Tuple; + Unpack(Data, Size, &Tuple); + Mutate(&Tuple, MaxSize, Seed); + size_t NewSize = Pack(Tuple, Data, MaxSize); + assert(NewSize > 0); + return NewSize; +} + } // namespace impl template bool Adapt(Fn F, const uint8_t *Data, size_t Size) { return impl::UnpackAndApply(F, Data, Size); } +template size_t AdaptMutator(Fn F, uint8_t *Data, size_t Size, + size_t MaxSize, unsigned int Seed) { + return impl::AdaptMutator(F, Data, Size, MaxSize, Seed); +} + } // namespace fuzzer #endif Index: lib/Fuzzer/test/CMakeLists.txt =================================================================== --- lib/Fuzzer/test/CMakeLists.txt +++ lib/Fuzzer/test/CMakeLists.txt @@ -28,6 +28,7 @@ SimpleCmpTest SimpleDictionaryTest SimpleFnAdapterTest + SimpleFnAdapterMutatorTest SimpleHashTest SimpleTest StrcmpTest Index: lib/Fuzzer/test/SimpleFnAdapterMutatorTest.cpp =================================================================== --- /dev/null +++ lib/Fuzzer/test/SimpleFnAdapterMutatorTest.cpp @@ -0,0 +1,24 @@ +#include +#include + +#include "FuzzerInternal.h" +#include "FuzzerFnAdapter.h" + +static void TestFn(std::string S1, std::string S2) { + if (S1.size() > 0 && S1 == S2) { + std::cout << "BINGO; Found the target, exiting\n"; + exit(0); + } +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + fuzzer::Adapt(TestFn, Data, Size); + return 0; +} + + +extern "C" size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, + size_t MaxSize, unsigned int Seed) { + return fuzzer::AdaptMutator(TestFn, Data, Size, MaxSize, Seed); +} + Index: lib/Fuzzer/test/fuzzer-fn-adapter-mutator.test =================================================================== --- /dev/null +++ lib/Fuzzer/test/fuzzer-fn-adapter-mutator.test @@ -0,0 +1,4 @@ +RUN: LLVMFuzzer-SimpleFnAdapterMutatorTest 2>&1 | FileCheck %s + +CHECK: BINGO +