[compiler-rt] c5d7251 - Revert "Refactor mutation strategies into a standalone library"
Marco Vanotti via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 2 09:45:22 PDT 2021
Author: Marco Vanotti
Date: 2021-07-02T09:45:11-07:00
New Revision: c5d725172d4d919dcdc5a64a21699b6309a7b872
URL: https://github.com/llvm/llvm-project/commit/c5d725172d4d919dcdc5a64a21699b6309a7b872
DIFF: https://github.com/llvm/llvm-project/commit/c5d725172d4d919dcdc5a64a21699b6309a7b872.diff
LOG: Revert "Refactor mutation strategies into a standalone library"
This reverts commit 361f742f168de0f0f256802a329c19d081615d0d.
Added:
compiler-rt/lib/fuzzer/FuzzerCrossOver.cpp
compiler-rt/lib/fuzzer/FuzzerDictionary.h
Modified:
compiler-rt/lib/fuzzer/CMakeLists.txt
compiler-rt/lib/fuzzer/FuzzerDefs.h
compiler-rt/lib/fuzzer/FuzzerDriver.cpp
compiler-rt/lib/fuzzer/FuzzerInternal.h
compiler-rt/lib/fuzzer/FuzzerLoop.cpp
compiler-rt/lib/fuzzer/FuzzerMutate.cpp
compiler-rt/lib/fuzzer/FuzzerMutate.h
compiler-rt/lib/fuzzer/FuzzerRandom.h
compiler-rt/lib/fuzzer/FuzzerTracePC.cpp
compiler-rt/lib/fuzzer/FuzzerTracePC.h
compiler-rt/lib/fuzzer/FuzzerUtil.h
compiler-rt/lib/fuzzer/FuzzerUtilFuchsia.cpp
compiler-rt/lib/fuzzer/FuzzerUtilPosix.cpp
compiler-rt/lib/fuzzer/FuzzerUtilWindows.cpp
compiler-rt/lib/fuzzer/build.sh
compiler-rt/lib/fuzzer/tests/CMakeLists.txt
compiler-rt/lib/fuzzer/tests/FuzzerUnittest.cpp
compiler-rt/test/fuzzer/CMakeLists.txt
Removed:
compiler-rt/lib/fuzzer/mutagen/CMakeLists.txt
compiler-rt/lib/fuzzer/mutagen/Mutagen.cpp
compiler-rt/lib/fuzzer/mutagen/Mutagen.h
compiler-rt/lib/fuzzer/mutagen/MutagenCrossOver.cpp
compiler-rt/lib/fuzzer/mutagen/MutagenDictionary.h
compiler-rt/lib/fuzzer/mutagen/MutagenDispatcher.cpp
compiler-rt/lib/fuzzer/mutagen/MutagenDispatcher.h
compiler-rt/lib/fuzzer/mutagen/MutagenSequence.h
compiler-rt/lib/fuzzer/mutagen/MutagenUtil.h
compiler-rt/lib/fuzzer/mutagen/MutagenUtilPosix.cpp
compiler-rt/lib/fuzzer/mutagen/MutagenUtilWindows.cpp
compiler-rt/lib/fuzzer/mutagen/build.sh
compiler-rt/lib/fuzzer/tests/MutagenUnittest.cpp
################################################################################
diff --git a/compiler-rt/lib/fuzzer/CMakeLists.txt b/compiler-rt/lib/fuzzer/CMakeLists.txt
index e27cf8d5e6fe8..3201ed279a621 100644
--- a/compiler-rt/lib/fuzzer/CMakeLists.txt
+++ b/compiler-rt/lib/fuzzer/CMakeLists.txt
@@ -1,4 +1,5 @@
set(LIBFUZZER_SOURCES
+ FuzzerCrossOver.cpp
FuzzerDataFlowTrace.cpp
FuzzerDriver.cpp
FuzzerExtFunctionsDlsym.cpp
@@ -28,6 +29,7 @@ set(LIBFUZZER_HEADERS
FuzzerCorpus.h
FuzzerDataFlowTrace.h
FuzzerDefs.h
+ FuzzerDictionary.h
FuzzerExtFunctions.def
FuzzerExtFunctions.h
FuzzerFlags.def
@@ -82,32 +84,6 @@ else()
endif()
endif()
-macro(partially_link_libcxx name dir arch)
- if(${arch} MATCHES "i386")
- set(EMULATION_ARGUMENT "-m" "elf_i386")
- else()
- set(EMULATION_ARGUMENT "")
- endif()
- set(cxx_${arch}_merge_dir "${CMAKE_CURRENT_BINARY_DIR}/cxx_${arch}_merge.dir")
- file(MAKE_DIRECTORY ${cxx_${arch}_merge_dir})
- add_custom_command(TARGET clang_rt.${name}-${arch} POST_BUILD
- COMMAND ${CMAKE_LINKER} ${EMULATION_ARGUMENT} --whole-archive "$<TARGET_LINKER_FILE:clang_rt.${name}-${arch}>" --no-whole-archive ${dir}/lib/libc++.a -r -o ${name}.o
- COMMAND ${CMAKE_OBJCOPY} --localize-hidden ${name}.o
- COMMAND ${CMAKE_COMMAND} -E remove "$<TARGET_LINKER_FILE:clang_rt.${name}-${arch}>"
- COMMAND ${CMAKE_AR} qcs "$<TARGET_LINKER_FILE:clang_rt.${name}-${arch}>" ${name}.o
- WORKING_DIRECTORY ${cxx_${arch}_merge_dir}
- )
-endmacro()
-
-add_subdirectory(mutagen)
-foreach(X IN LISTS LIBFUZZER_MUTAGEN_SOURCES)
- list(APPEND LIBFUZZER_SOURCES "mutagen/${X}")
-endforeach()
-foreach(X IN LISTS LIBFUZZER_MUTAGEN_HEADERS)
- list(APPEND LIBFUZZER_HEADERS "mutagen/${X}")
-endforeach()
-include_directories(.)
-
add_compiler_rt_component(fuzzer)
add_compiler_rt_object_libraries(RTfuzzer
@@ -159,6 +135,23 @@ add_compiler_rt_runtime(clang_rt.fuzzer_interceptors
if(OS_NAME MATCHES "Linux|Fuchsia" AND
COMPILER_RT_LIBCXX_PATH AND
COMPILER_RT_LIBCXXABI_PATH)
+ macro(partially_link_libcxx name dir arch)
+ if(${arch} MATCHES "i386")
+ set(EMULATION_ARGUMENT "-m" "elf_i386")
+ else()
+ set(EMULATION_ARGUMENT "")
+ endif()
+ set(cxx_${arch}_merge_dir "${CMAKE_CURRENT_BINARY_DIR}/cxx_${arch}_merge.dir")
+ file(MAKE_DIRECTORY ${cxx_${arch}_merge_dir})
+ add_custom_command(TARGET clang_rt.${name}-${arch} POST_BUILD
+ COMMAND ${CMAKE_LINKER} ${EMULATION_ARGUMENT} --whole-archive "$<TARGET_LINKER_FILE:clang_rt.${name}-${arch}>" --no-whole-archive ${dir}/lib/libc++.a -r -o ${name}.o
+ COMMAND ${CMAKE_OBJCOPY} --localize-hidden ${name}.o
+ COMMAND ${CMAKE_COMMAND} -E remove "$<TARGET_LINKER_FILE:clang_rt.${name}-${arch}>"
+ COMMAND ${CMAKE_AR} qcs "$<TARGET_LINKER_FILE:clang_rt.${name}-${arch}>" ${name}.o
+ WORKING_DIRECTORY ${cxx_${arch}_merge_dir}
+ )
+ endmacro()
+
foreach(arch ${FUZZER_SUPPORTED_ARCH})
get_target_flags_for_arch(${arch} TARGET_CFLAGS)
set(LIBCXX_${arch}_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/libcxx_fuzzer_${arch})
diff --git a/compiler-rt/lib/fuzzer/mutagen/MutagenCrossOver.cpp b/compiler-rt/lib/fuzzer/FuzzerCrossOver.cpp
similarity index 86%
rename from compiler-rt/lib/fuzzer/mutagen/MutagenCrossOver.cpp
rename to compiler-rt/lib/fuzzer/FuzzerCrossOver.cpp
index 0fcffaf68ddf4..83d9f8d47cb18 100644
--- a/compiler-rt/lib/fuzzer/mutagen/MutagenCrossOver.cpp
+++ b/compiler-rt/lib/fuzzer/FuzzerCrossOver.cpp
@@ -1,4 +1,4 @@
-//===- MutagenCrossOver.cpp - Cross over two test inputs ------------------===//
+//===- FuzzerCrossOver.cpp - Cross over two test inputs -------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -8,11 +8,12 @@
// Cross over test inputs.
//===----------------------------------------------------------------------===//
+#include "FuzzerDefs.h"
+#include "FuzzerMutate.h"
#include "FuzzerRandom.h"
-#include "MutagenDispatcher.h"
#include <cstring>
-namespace mutagen {
+namespace fuzzer {
// Cross Data1 and Data2, store the result (up to MaxOutSize bytes) in Out.
size_t MutationDispatcher::CrossOver(const uint8_t *Data1, size_t Size1,
@@ -39,12 +40,12 @@ size_t MutationDispatcher::CrossOver(const uint8_t *Data1, size_t Size1,
(*InPos) += ExtraSize;
}
// Use the other input data on the next iteration.
- InPos = CurrentlyUsingFirstData ? &Pos2 : &Pos1;
+ InPos = CurrentlyUsingFirstData ? &Pos2 : &Pos1;
InSize = CurrentlyUsingFirstData ? Size2 : Size1;
- Data = CurrentlyUsingFirstData ? Data2 : Data1;
+ Data = CurrentlyUsingFirstData ? Data2 : Data1;
CurrentlyUsingFirstData = !CurrentlyUsingFirstData;
}
return OutPos;
}
-} // namespace mutagen
+} // namespace fuzzer
diff --git a/compiler-rt/lib/fuzzer/FuzzerDefs.h b/compiler-rt/lib/fuzzer/FuzzerDefs.h
index 36820b61c2aa5..1a2752af2f4d5 100644
--- a/compiler-rt/lib/fuzzer/FuzzerDefs.h
+++ b/compiler-rt/lib/fuzzer/FuzzerDefs.h
@@ -15,18 +15,21 @@
#include <cstddef>
#include <cstdint>
#include <cstring>
-#include <limits>
#include <memory>
#include <set>
#include <string>
#include <vector>
+
namespace fuzzer {
template <class T> T Min(T a, T b) { return a < b ? a : b; }
template <class T> T Max(T a, T b) { return a > b ? a : b; }
class Random;
+class Dictionary;
+class DictionaryEntry;
+class MutationDispatcher;
struct FuzzingOptions;
class InputCorpus;
struct InputInfo;
@@ -57,37 +60,6 @@ using Set = std::set<T, std::less<T>, fuzzer_allocator<T>>;
typedef Vector<uint8_t> Unit;
typedef Vector<Unit> UnitVector;
-
-// A simple POD sized array of bytes.
-template <size_t kMaxSizeT> class FixedWord {
-public:
- static const size_t kMaxSize = kMaxSizeT;
- FixedWord() { memset(Data, 0, kMaxSize); }
- FixedWord(const uint8_t *B, size_t S) { Set(B, S); }
-
- void Set(const uint8_t *B, size_t S) {
- static_assert(kMaxSizeT <= std::numeric_limits<uint8_t>::max(),
- "FixedWord::kMaxSizeT cannot fit in a uint8_t.");
- assert(S <= kMaxSize);
- memcpy(Data, B, S);
- Size = static_cast<uint8_t>(S);
- }
-
- bool operator==(const FixedWord<kMaxSize> &w) const {
- return Size == w.Size && 0 == memcmp(Data, w.Data, Size);
- }
-
- static size_t GetMaxSize() { return kMaxSize; }
- const uint8_t *data() const { return Data; }
- uint8_t size() const { return Size; }
-
-private:
- uint8_t Size = 0;
- uint8_t Data[kMaxSize];
-};
-
-typedef FixedWord<64> Word;
-
typedef int (*UserCallback)(const uint8_t *Data, size_t Size);
int FuzzerDriver(int *argc, char ***argv, UserCallback Callback);
diff --git a/compiler-rt/lib/fuzzer/FuzzerDictionary.h b/compiler-rt/lib/fuzzer/FuzzerDictionary.h
new file mode 100644
index 0000000000000..db55907d93631
--- /dev/null
+++ b/compiler-rt/lib/fuzzer/FuzzerDictionary.h
@@ -0,0 +1,120 @@
+//===- FuzzerDictionary.h - Internal header for the Fuzzer ------*- C++ -* ===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// fuzzer::Dictionary
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FUZZER_DICTIONARY_H
+#define LLVM_FUZZER_DICTIONARY_H
+
+#include "FuzzerDefs.h"
+#include "FuzzerIO.h"
+#include "FuzzerUtil.h"
+#include <algorithm>
+#include <limits>
+
+namespace fuzzer {
+// A simple POD sized array of bytes.
+template <size_t kMaxSizeT> class FixedWord {
+public:
+ static const size_t kMaxSize = kMaxSizeT;
+ FixedWord() {}
+ FixedWord(const uint8_t *B, size_t S) { Set(B, S); }
+
+ void Set(const uint8_t *B, size_t S) {
+ static_assert(kMaxSizeT <= std::numeric_limits<uint8_t>::max(),
+ "FixedWord::kMaxSizeT cannot fit in a uint8_t.");
+ assert(S <= kMaxSize);
+ memcpy(Data, B, S);
+ Size = static_cast<uint8_t>(S);
+ }
+
+ bool operator==(const FixedWord<kMaxSize> &w) const {
+ return Size == w.Size && 0 == memcmp(Data, w.Data, Size);
+ }
+
+ static size_t GetMaxSize() { return kMaxSize; }
+ const uint8_t *data() const { return Data; }
+ uint8_t size() const { return Size; }
+
+private:
+ uint8_t Size = 0;
+ uint8_t Data[kMaxSize];
+};
+
+typedef FixedWord<64> Word;
+
+class DictionaryEntry {
+ public:
+ DictionaryEntry() {}
+ DictionaryEntry(Word W) : W(W) {}
+ DictionaryEntry(Word W, size_t PositionHint) : W(W), PositionHint(PositionHint) {}
+ const Word &GetW() const { return W; }
+
+ bool HasPositionHint() const { return PositionHint != std::numeric_limits<size_t>::max(); }
+ size_t GetPositionHint() const {
+ assert(HasPositionHint());
+ return PositionHint;
+ }
+ void IncUseCount() { UseCount++; }
+ void IncSuccessCount() { SuccessCount++; }
+ size_t GetUseCount() const { return UseCount; }
+ size_t GetSuccessCount() const {return SuccessCount; }
+
+ void Print(const char *PrintAfter = "\n") {
+ PrintASCII(W.data(), W.size());
+ if (HasPositionHint())
+ Printf("@%zd", GetPositionHint());
+ Printf("%s", PrintAfter);
+ }
+
+private:
+ Word W;
+ size_t PositionHint = std::numeric_limits<size_t>::max();
+ size_t UseCount = 0;
+ size_t SuccessCount = 0;
+};
+
+class Dictionary {
+ public:
+ static const size_t kMaxDictSize = 1 << 14;
+
+ bool ContainsWord(const Word &W) const {
+ return std::any_of(begin(), end(), [&](const DictionaryEntry &DE) {
+ return DE.GetW() == W;
+ });
+ }
+ const DictionaryEntry *begin() const { return &DE[0]; }
+ const DictionaryEntry *end() const { return begin() + Size; }
+ DictionaryEntry & operator[] (size_t Idx) {
+ assert(Idx < Size);
+ return DE[Idx];
+ }
+ void push_back(DictionaryEntry DE) {
+ if (Size < kMaxDictSize)
+ this->DE[Size++] = DE;
+ }
+ void clear() { Size = 0; }
+ bool empty() const { return Size == 0; }
+ size_t size() const { return Size; }
+
+private:
+ DictionaryEntry DE[kMaxDictSize];
+ size_t Size = 0;
+};
+
+// Parses one dictionary entry.
+// If successful, write the enty to Unit and returns true,
+// otherwise returns false.
+bool ParseOneDictionaryEntry(const std::string &Str, Unit *U);
+// Parses the dictionary file, fills Units, returns true iff all lines
+// were parsed successfully.
+bool ParseDictionaryFile(const std::string &Text, Vector<Unit> *Units);
+
+} // namespace fuzzer
+
+#endif // LLVM_FUZZER_DICTIONARY_H
diff --git a/compiler-rt/lib/fuzzer/FuzzerDriver.cpp b/compiler-rt/lib/fuzzer/FuzzerDriver.cpp
index 38efc2e18863c..ceaa9070512f0 100644
--- a/compiler-rt/lib/fuzzer/FuzzerDriver.cpp
+++ b/compiler-rt/lib/fuzzer/FuzzerDriver.cpp
@@ -19,16 +19,15 @@
#include "FuzzerPlatform.h"
#include "FuzzerRandom.h"
#include "FuzzerTracePC.h"
-#include "mutagen/MutagenDispatcher.h"
#include <algorithm>
#include <atomic>
#include <chrono>
#include <cstdlib>
#include <cstring>
-#include <fstream>
#include <mutex>
#include <string>
#include <thread>
+#include <fstream>
// This function should be present in the libFuzzer so that the client
// binary can test for its existence.
@@ -804,9 +803,8 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
ReadCorpora(*Inputs, {}));
}
- LLVMMutagenConfiguration Config;
- ConfigureMutagen(Seed, Options, &Config);
- auto *MD = new MutationDispatcher(&Config);
+ Random Rand(Seed);
+ auto *MD = new MutationDispatcher(Rand, Options);
auto *Corpus = new InputCorpus(Options.OutputCorpus, Entropic);
auto *F = new Fuzzer(Callback, *Corpus, *MD, Options);
diff --git a/compiler-rt/lib/fuzzer/FuzzerInternal.h b/compiler-rt/lib/fuzzer/FuzzerInternal.h
index a629c3d02f774..37c8a01dc3c64 100644
--- a/compiler-rt/lib/fuzzer/FuzzerInternal.h
+++ b/compiler-rt/lib/fuzzer/FuzzerInternal.h
@@ -18,7 +18,6 @@
#include "FuzzerOptions.h"
#include "FuzzerSHA1.h"
#include "FuzzerValueBitMap.h"
-#include "mutagen/MutagenDispatcher.h"
#include <algorithm>
#include <atomic>
#include <chrono>
@@ -27,12 +26,8 @@
#include <string.h>
namespace fuzzer {
-namespace {
using namespace std::chrono;
-using mutagen::MutationDispatcher;
-
-} // namespace
class Fuzzer {
public:
diff --git a/compiler-rt/lib/fuzzer/FuzzerLoop.cpp b/compiler-rt/lib/fuzzer/FuzzerLoop.cpp
index d50277e9f2a0d..86a78ab751741 100644
--- a/compiler-rt/lib/fuzzer/FuzzerLoop.cpp
+++ b/compiler-rt/lib/fuzzer/FuzzerLoop.cpp
@@ -177,7 +177,7 @@ void Fuzzer::DumpCurrentUnit(const char *Prefix) {
if (!CurrentUnitData)
return; // Happens when running individual inputs.
ScopedDisableMsanInterceptorChecks S;
- PrintMutationSequence(MD);
+ MD.PrintMutationSequence();
Printf("; base unit: %s\n", Sha1ToString(BaseSha1).c_str());
size_t UnitSize = CurrentUnitSize;
if (UnitSize <= kMaxUnitSizeToPrint) {
@@ -539,9 +539,8 @@ bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile,
TimeOfUnit, UniqFeatureSetTmp, DFT, II);
WriteFeatureSetToFile(Options.FeaturesDir, Sha1ToString(NewII->Sha1),
NewII->UniqFeatureSet);
- const auto &MS = MD.MutationSequence();
WriteEdgeToMutationGraphFile(Options.MutationGraphFile, NewII, II,
- MS.GetString());
+ MD.MutationSequence());
return true;
}
if (II && FoundUniqFeaturesOfII &&
@@ -653,7 +652,7 @@ void Fuzzer::PrintStatusForNewUnit(const Unit &U, const char *Text) {
PrintStats(Text, "");
if (Options.Verbosity) {
Printf(" L: %zd/%zd ", U.size(), Corpus.MaxInputSize());
- PrintMutationSequence(MD, Options.Verbosity >= 2);
+ MD.PrintMutationSequence(Options.Verbosity >= 2);
Printf("\n");
}
}
@@ -899,7 +898,7 @@ void Fuzzer::Loop(Vector<SizedFile> &CorporaFiles) {
}
PrintStats("DONE ", "\n");
- PrintRecommendedDictionary(MD);
+ MD.PrintRecommendedDictionary();
}
void Fuzzer::MinimizeCrashLoop(const Unit &U) {
diff --git a/compiler-rt/lib/fuzzer/FuzzerMutate.cpp b/compiler-rt/lib/fuzzer/FuzzerMutate.cpp
index bbce4aab58024..4650f1beceacd 100644
--- a/compiler-rt/lib/fuzzer/FuzzerMutate.cpp
+++ b/compiler-rt/lib/fuzzer/FuzzerMutate.cpp
@@ -1,77 +1,497 @@
-//===- FuzzerMutate.cpp - Mutation utilities -----------------------------===//
+//===- FuzzerMutate.cpp - Mutate a test input -----------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
-// Mutate utilities.
+// Mutate a test input.
//===----------------------------------------------------------------------===//
-#include "FuzzerMutate.h"
+#include "FuzzerDefs.h"
#include "FuzzerExtFunctions.h"
#include "FuzzerIO.h"
+#include "FuzzerMutate.h"
+#include "FuzzerOptions.h"
#include "FuzzerTracePC.h"
-#include "FuzzerUtil.h"
namespace fuzzer {
-namespace {
-void FromTORC4(size_t Idx, uint32_t *A, uint32_t *B) {
- const auto &X = TPC.TORC4.Get(Idx);
- *A = X.A;
- *B = X.B;
+const size_t Dictionary::kMaxDictSize;
+static const size_t kMaxMutationsToPrint = 10;
+
+static void PrintASCII(const Word &W, const char *PrintAfter) {
+ PrintASCII(W.data(), W.size(), PrintAfter);
+}
+
+MutationDispatcher::MutationDispatcher(Random &Rand,
+ const FuzzingOptions &Options)
+ : Rand(Rand), Options(Options) {
+ DefaultMutators.insert(
+ DefaultMutators.begin(),
+ {
+ {&MutationDispatcher::Mutate_EraseBytes, "EraseBytes"},
+ {&MutationDispatcher::Mutate_InsertByte, "InsertByte"},
+ {&MutationDispatcher::Mutate_InsertRepeatedBytes,
+ "InsertRepeatedBytes"},
+ {&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"},
+ {&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"},
+ {&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"},
+ {&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"},
+ {&MutationDispatcher::Mutate_ChangeBinaryInteger, "ChangeBinInt"},
+ {&MutationDispatcher::Mutate_CopyPart, "CopyPart"},
+ {&MutationDispatcher::Mutate_CrossOver, "CrossOver"},
+ {&MutationDispatcher::Mutate_AddWordFromManualDictionary,
+ "ManualDict"},
+ {&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary,
+ "PersAutoDict"},
+ });
+ if(Options.UseCmp)
+ DefaultMutators.push_back(
+ {&MutationDispatcher::Mutate_AddWordFromTORC, "CMP"});
+
+ if (EF->LLVMFuzzerCustomMutator)
+ Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom"});
+ else
+ Mutators = DefaultMutators;
+
+ if (EF->LLVMFuzzerCustomCrossOver)
+ Mutators.push_back(
+ {&MutationDispatcher::Mutate_CustomCrossOver, "CustomCrossOver"});
+}
+
+static char RandCh(Random &Rand) {
+ if (Rand.RandBool())
+ return static_cast<char>(Rand(256));
+ const char Special[] = "!*'();:@&=+$,/?%#[]012Az-`~.\xff\x00";
+ return Special[Rand(sizeof(Special) - 1)];
+}
+
+size_t MutationDispatcher::Mutate_Custom(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ if (EF->__msan_unpoison)
+ EF->__msan_unpoison(Data, Size);
+ if (EF->__msan_unpoison_param)
+ EF->__msan_unpoison_param(4);
+ return EF->LLVMFuzzerCustomMutator(Data, Size, MaxSize,
+ Rand.Rand<unsigned int>());
+}
+
+size_t MutationDispatcher::Mutate_CustomCrossOver(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ if (Size == 0)
+ return 0;
+ if (!CrossOverWith) return 0;
+ const Unit &Other = *CrossOverWith;
+ if (Other.empty())
+ return 0;
+ CustomCrossOverInPlaceHere.resize(MaxSize);
+ auto &U = CustomCrossOverInPlaceHere;
+
+ if (EF->__msan_unpoison) {
+ EF->__msan_unpoison(Data, Size);
+ EF->__msan_unpoison(Other.data(), Other.size());
+ EF->__msan_unpoison(U.data(), U.size());
+ }
+ if (EF->__msan_unpoison_param)
+ EF->__msan_unpoison_param(7);
+ size_t NewSize = EF->LLVMFuzzerCustomCrossOver(
+ Data, Size, Other.data(), Other.size(), U.data(), U.size(),
+ Rand.Rand<unsigned int>());
+
+ if (!NewSize)
+ return 0;
+ assert(NewSize <= MaxSize && "CustomCrossOver returned overisized unit");
+ memcpy(Data, U.data(), NewSize);
+ return NewSize;
+}
+
+size_t MutationDispatcher::Mutate_ShuffleBytes(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ if (Size > MaxSize || Size == 0) return 0;
+ size_t ShuffleAmount =
+ Rand(std::min(Size, (size_t)8)) + 1; // [1,8] and <= Size.
+ size_t ShuffleStart = Rand(Size - ShuffleAmount);
+ assert(ShuffleStart + ShuffleAmount <= Size);
+ std::shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount, Rand);
+ return Size;
+}
+
+size_t MutationDispatcher::Mutate_EraseBytes(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ if (Size <= 1) return 0;
+ size_t N = Rand(Size / 2) + 1;
+ assert(N < Size);
+ size_t Idx = Rand(Size - N + 1);
+ // Erase Data[Idx:Idx+N].
+ memmove(Data + Idx, Data + Idx + N, Size - Idx - N);
+ // Printf("Erase: %zd %zd => %zd; Idx %zd\n", N, Size, Size - N, Idx);
+ return Size - N;
}
-void FromTORC8(size_t Idx, uint64_t *A, uint64_t *B) {
- const auto &X = TPC.TORC8.Get(Idx);
- *A = X.A;
- *B = X.B;
+size_t MutationDispatcher::Mutate_InsertByte(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ if (Size >= MaxSize) return 0;
+ size_t Idx = Rand(Size + 1);
+ // Insert new value at Data[Idx].
+ memmove(Data + Idx + 1, Data + Idx, Size - Idx);
+ Data[Idx] = RandCh(Rand);
+ return Size + 1;
}
-void FromTORCW(size_t Idx, const uint8_t **DataA, size_t *SizeA,
- const uint8_t **DataB, size_t *SizeB) {
- const auto &X = TPC.TORCW.Get(Idx);
- *DataA = X.A.data();
- *SizeA = X.A.size();
- *DataB = X.B.data();
- *SizeB = X.B.size();
+size_t MutationDispatcher::Mutate_InsertRepeatedBytes(uint8_t *Data,
+ size_t Size,
+ size_t MaxSize) {
+ const size_t kMinBytesToInsert = 3;
+ if (Size + kMinBytesToInsert >= MaxSize) return 0;
+ size_t MaxBytesToInsert = std::min(MaxSize - Size, (size_t)128);
+ size_t N = Rand(MaxBytesToInsert - kMinBytesToInsert + 1) + kMinBytesToInsert;
+ assert(Size + N <= MaxSize && N);
+ size_t Idx = Rand(Size + 1);
+ // Insert new values at Data[Idx].
+ memmove(Data + Idx + N, Data + Idx, Size - Idx);
+ // Give preference to 0x00 and 0xff.
+ uint8_t Byte = static_cast<uint8_t>(
+ Rand.RandBool() ? Rand(256) : (Rand.RandBool() ? 0 : 255));
+ for (size_t i = 0; i < N; i++)
+ Data[Idx + i] = Byte;
+ return Size + N;
}
-void FromMMT(size_t Idx, const uint8_t **Data, size_t *Size) {
- const auto &W = TPC.MMT.Get(Idx);
- *Data = W.data();
- *Size = W.size();
+size_t MutationDispatcher::Mutate_ChangeByte(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ if (Size > MaxSize) return 0;
+ size_t Idx = Rand(Size);
+ Data[Idx] = RandCh(Rand);
+ return Size;
}
-void PrintASCII(const Word &W, const char *PrintAfter) {
- fuzzer::PrintASCII(W.data(), W.size(), PrintAfter);
+size_t MutationDispatcher::Mutate_ChangeBit(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ if (Size > MaxSize) return 0;
+ size_t Idx = Rand(Size);
+ Data[Idx] ^= 1 << Rand(8);
+ return Size;
}
-} // namespace
+size_t MutationDispatcher::Mutate_AddWordFromManualDictionary(uint8_t *Data,
+ size_t Size,
+ size_t MaxSize) {
+ return AddWordFromDictionary(ManualDictionary, Data, Size, MaxSize);
+}
+
+size_t MutationDispatcher::ApplyDictionaryEntry(uint8_t *Data, size_t Size,
+ size_t MaxSize,
+ DictionaryEntry &DE) {
+ const Word &W = DE.GetW();
+ bool UsePositionHint = DE.HasPositionHint() &&
+ DE.GetPositionHint() + W.size() < Size &&
+ Rand.RandBool();
+ if (Rand.RandBool()) { // Insert W.
+ if (Size + W.size() > MaxSize) return 0;
+ size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size + 1);
+ memmove(Data + Idx + W.size(), Data + Idx, Size - Idx);
+ memcpy(Data + Idx, W.data(), W.size());
+ Size += W.size();
+ } else { // Overwrite some bytes with W.
+ if (W.size() > Size) return 0;
+ size_t Idx =
+ UsePositionHint ? DE.GetPositionHint() : Rand(Size + 1 - W.size());
+ memcpy(Data + Idx, W.data(), W.size());
+ }
+ return Size;
+}
+
+// Somewhere in the past we have observed a comparison instructions
+// with arguments Arg1 Arg2. This function tries to guess a dictionary
+// entry that will satisfy that comparison.
+// It first tries to find one of the arguments (possibly swapped) in the
+// input and if it succeeds it creates a DE with a position hint.
+// Otherwise it creates a DE with one of the arguments w/o a position hint.
+DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP(
+ const void *Arg1, const void *Arg2,
+ const void *Arg1Mutation, const void *Arg2Mutation,
+ size_t ArgSize, const uint8_t *Data,
+ size_t Size) {
+ bool HandleFirst = Rand.RandBool();
+ const void *ExistingBytes, *DesiredBytes;
+ Word W;
+ const uint8_t *End = Data + Size;
+ for (int Arg = 0; Arg < 2; Arg++) {
+ ExistingBytes = HandleFirst ? Arg1 : Arg2;
+ DesiredBytes = HandleFirst ? Arg2Mutation : Arg1Mutation;
+ HandleFirst = !HandleFirst;
+ W.Set(reinterpret_cast<const uint8_t*>(DesiredBytes), ArgSize);
+ const size_t kMaxNumPositions = 8;
+ size_t Positions[kMaxNumPositions];
+ size_t NumPositions = 0;
+ for (const uint8_t *Cur = Data;
+ Cur < End && NumPositions < kMaxNumPositions; Cur++) {
+ Cur =
+ (const uint8_t *)SearchMemory(Cur, End - Cur, ExistingBytes, ArgSize);
+ if (!Cur) break;
+ Positions[NumPositions++] = Cur - Data;
+ }
+ if (!NumPositions) continue;
+ return DictionaryEntry(W, Positions[Rand(NumPositions)]);
+ }
+ DictionaryEntry DE(W);
+ return DE;
+}
+
+
+template <class T>
+DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP(
+ T Arg1, T Arg2, const uint8_t *Data, size_t Size) {
+ if (Rand.RandBool()) Arg1 = Bswap(Arg1);
+ if (Rand.RandBool()) Arg2 = Bswap(Arg2);
+ T Arg1Mutation = static_cast<T>(Arg1 + Rand(-1, 1));
+ T Arg2Mutation = static_cast<T>(Arg2 + Rand(-1, 1));
+ return MakeDictionaryEntryFromCMP(&Arg1, &Arg2, &Arg1Mutation, &Arg2Mutation,
+ sizeof(Arg1), Data, Size);
+}
-void ConfigureMutagen(unsigned int Seed, const FuzzingOptions &Options,
- LLVMMutagenConfiguration *OutConfig) {
- memset(OutConfig, 0, sizeof(*OutConfig));
- OutConfig->Seed = Seed;
- OutConfig->UseCmp = Options.UseCmp;
- OutConfig->FromTORC4 = FromTORC4;
- OutConfig->FromTORC8 = FromTORC8;
- OutConfig->FromTORCW = FromTORCW;
- OutConfig->UseMemmem = Options.UseMemmem;
- OutConfig->FromMMT = FromMMT;
- OutConfig->CustomMutator = EF->LLVMFuzzerCustomMutator;
- OutConfig->CustomCrossOver = EF->LLVMFuzzerCustomCrossOver;
- OutConfig->MSanUnpoison = EF->__msan_unpoison;
- OutConfig->MSanUnpoisonParam = EF->__msan_unpoison_param;
+DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP(
+ const Word &Arg1, const Word &Arg2, const uint8_t *Data, size_t Size) {
+ return MakeDictionaryEntryFromCMP(Arg1.data(), Arg2.data(), Arg1.data(),
+ Arg2.data(), Arg1.size(), Data, Size);
}
-void PrintRecommendedDictionary(MutationDispatcher &MD) {
- auto RecommendedDictionary = MD.RecommendDictionary();
- if (RecommendedDictionary.empty())
- return;
+size_t MutationDispatcher::Mutate_AddWordFromTORC(
+ uint8_t *Data, size_t Size, size_t MaxSize) {
+ Word W;
+ DictionaryEntry DE;
+ switch (Rand(4)) {
+ case 0: {
+ auto X = TPC.TORC8.Get(Rand.Rand<size_t>());
+ DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size);
+ } break;
+ case 1: {
+ auto X = TPC.TORC4.Get(Rand.Rand<size_t>());
+ if ((X.A >> 16) == 0 && (X.B >> 16) == 0 && Rand.RandBool())
+ DE = MakeDictionaryEntryFromCMP((uint16_t)X.A, (uint16_t)X.B, Data, Size);
+ else
+ DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size);
+ } break;
+ case 2: {
+ auto X = TPC.TORCW.Get(Rand.Rand<size_t>());
+ DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size);
+ } break;
+ case 3: if (Options.UseMemmem) {
+ auto X = TPC.MMT.Get(Rand.Rand<size_t>());
+ DE = DictionaryEntry(X);
+ } break;
+ default:
+ assert(0);
+ }
+ if (!DE.GetW().size()) return 0;
+ Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE);
+ if (!Size) return 0;
+ DictionaryEntry &DERef =
+ CmpDictionaryEntriesDeque[CmpDictionaryEntriesDequeIdx++ %
+ kCmpDictionaryEntriesDequeSize];
+ DERef = DE;
+ CurrentDictionaryEntrySequence.push_back(&DERef);
+ return Size;
+}
+
+size_t MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary(
+ uint8_t *Data, size_t Size, size_t MaxSize) {
+ return AddWordFromDictionary(PersistentAutoDictionary, Data, Size, MaxSize);
+}
+
+size_t MutationDispatcher::AddWordFromDictionary(Dictionary &D, uint8_t *Data,
+ size_t Size, size_t MaxSize) {
+ if (Size > MaxSize) return 0;
+ if (D.empty()) return 0;
+ DictionaryEntry &DE = D[Rand(D.size())];
+ Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE);
+ if (!Size) return 0;
+ DE.IncUseCount();
+ CurrentDictionaryEntrySequence.push_back(&DE);
+ return Size;
+}
+
+// Overwrites part of To[0,ToSize) with a part of From[0,FromSize).
+// Returns ToSize.
+size_t MutationDispatcher::CopyPartOf(const uint8_t *From, size_t FromSize,
+ uint8_t *To, size_t ToSize) {
+ // Copy From[FromBeg, FromBeg + CopySize) into To[ToBeg, ToBeg + CopySize).
+ size_t ToBeg = Rand(ToSize);
+ size_t CopySize = Rand(ToSize - ToBeg) + 1;
+ assert(ToBeg + CopySize <= ToSize);
+ CopySize = std::min(CopySize, FromSize);
+ size_t FromBeg = Rand(FromSize - CopySize + 1);
+ assert(FromBeg + CopySize <= FromSize);
+ memmove(To + ToBeg, From + FromBeg, CopySize);
+ return ToSize;
+}
+
+// Inserts part of From[0,ToSize) into To.
+// Returns new size of To on success or 0 on failure.
+size_t MutationDispatcher::InsertPartOf(const uint8_t *From, size_t FromSize,
+ uint8_t *To, size_t ToSize,
+ size_t MaxToSize) {
+ if (ToSize >= MaxToSize) return 0;
+ size_t AvailableSpace = MaxToSize - ToSize;
+ size_t MaxCopySize = std::min(AvailableSpace, FromSize);
+ size_t CopySize = Rand(MaxCopySize) + 1;
+ size_t FromBeg = Rand(FromSize - CopySize + 1);
+ assert(FromBeg + CopySize <= FromSize);
+ size_t ToInsertPos = Rand(ToSize + 1);
+ assert(ToInsertPos + CopySize <= MaxToSize);
+ size_t TailSize = ToSize - ToInsertPos;
+ if (To == From) {
+ MutateInPlaceHere.resize(MaxToSize);
+ memcpy(MutateInPlaceHere.data(), From + FromBeg, CopySize);
+ memmove(To + ToInsertPos + CopySize, To + ToInsertPos, TailSize);
+ memmove(To + ToInsertPos, MutateInPlaceHere.data(), CopySize);
+ } else {
+ memmove(To + ToInsertPos + CopySize, To + ToInsertPos, TailSize);
+ memmove(To + ToInsertPos, From + FromBeg, CopySize);
+ }
+ return ToSize + CopySize;
+}
+
+size_t MutationDispatcher::Mutate_CopyPart(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ if (Size > MaxSize || Size == 0) return 0;
+ // If Size == MaxSize, `InsertPartOf(...)` will
+ // fail so there's no point using it in this case.
+ if (Size == MaxSize || Rand.RandBool())
+ return CopyPartOf(Data, Size, Data, Size);
+ else
+ return InsertPartOf(Data, Size, Data, Size, MaxSize);
+}
+
+size_t MutationDispatcher::Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ if (Size > MaxSize) return 0;
+ size_t B = Rand(Size);
+ while (B < Size && !isdigit(Data[B])) B++;
+ if (B == Size) return 0;
+ size_t E = B;
+ while (E < Size && isdigit(Data[E])) E++;
+ assert(B < E);
+ // now we have digits in [B, E).
+ // strtol and friends don't accept non-zero-teminated data, parse it manually.
+ uint64_t Val = Data[B] - '0';
+ for (size_t i = B + 1; i < E; i++)
+ Val = Val * 10 + Data[i] - '0';
+
+ // Mutate the integer value.
+ switch(Rand(5)) {
+ case 0: Val++; break;
+ case 1: Val--; break;
+ case 2: Val /= 2; break;
+ case 3: Val *= 2; break;
+ case 4: Val = Rand(Val * Val); break;
+ default: assert(0);
+ }
+ // Just replace the bytes with the new ones, don't bother moving bytes.
+ for (size_t i = B; i < E; i++) {
+ size_t Idx = E + B - i - 1;
+ assert(Idx >= B && Idx < E);
+ Data[Idx] = (Val % 10) + '0';
+ Val /= 10;
+ }
+ return Size;
+}
+
+template<class T>
+size_t ChangeBinaryInteger(uint8_t *Data, size_t Size, Random &Rand) {
+ if (Size < sizeof(T)) return 0;
+ size_t Off = Rand(Size - sizeof(T) + 1);
+ assert(Off + sizeof(T) <= Size);
+ T Val;
+ if (Off < 64 && !Rand(4)) {
+ Val = static_cast<T>(Size);
+ if (Rand.RandBool())
+ Val = Bswap(Val);
+ } else {
+ memcpy(&Val, Data + Off, sizeof(Val));
+ T Add = static_cast<T>(Rand(21));
+ Add -= 10;
+ if (Rand.RandBool())
+ Val = Bswap(T(Bswap(Val) + Add)); // Add assuming
diff erent endiannes.
+ else
+ Val = Val + Add; // Add assuming current endiannes.
+ if (Add == 0 || Rand.RandBool()) // Maybe negate.
+ Val = -Val;
+ }
+ memcpy(Data + Off, &Val, sizeof(Val));
+ return Size;
+}
+
+size_t MutationDispatcher::Mutate_ChangeBinaryInteger(uint8_t *Data,
+ size_t Size,
+ size_t MaxSize) {
+ if (Size > MaxSize) return 0;
+ switch (Rand(4)) {
+ case 3: return ChangeBinaryInteger<uint64_t>(Data, Size, Rand);
+ case 2: return ChangeBinaryInteger<uint32_t>(Data, Size, Rand);
+ case 1: return ChangeBinaryInteger<uint16_t>(Data, Size, Rand);
+ case 0: return ChangeBinaryInteger<uint8_t>(Data, Size, Rand);
+ default: assert(0);
+ }
+ return 0;
+}
+
+size_t MutationDispatcher::Mutate_CrossOver(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ if (Size > MaxSize) return 0;
+ if (Size == 0) return 0;
+ if (!CrossOverWith) return 0;
+ const Unit &O = *CrossOverWith;
+ if (O.empty()) return 0;
+ size_t NewSize = 0;
+ switch(Rand(3)) {
+ case 0:
+ MutateInPlaceHere.resize(MaxSize);
+ NewSize = CrossOver(Data, Size, O.data(), O.size(),
+ MutateInPlaceHere.data(), MaxSize);
+ memcpy(Data, MutateInPlaceHere.data(), NewSize);
+ break;
+ case 1:
+ NewSize = InsertPartOf(O.data(), O.size(), Data, Size, MaxSize);
+ if (!NewSize)
+ NewSize = CopyPartOf(O.data(), O.size(), Data, Size);
+ break;
+ case 2:
+ NewSize = CopyPartOf(O.data(), O.size(), Data, Size);
+ break;
+ default: assert(0);
+ }
+ assert(NewSize > 0 && "CrossOver returned empty unit");
+ assert(NewSize <= MaxSize && "CrossOver returned overisized unit");
+ return NewSize;
+}
+
+void MutationDispatcher::StartMutationSequence() {
+ CurrentMutatorSequence.clear();
+ CurrentDictionaryEntrySequence.clear();
+}
+
+// Copy successful dictionary entries to PersistentAutoDictionary.
+void MutationDispatcher::RecordSuccessfulMutationSequence() {
+ for (auto DE : CurrentDictionaryEntrySequence) {
+ // PersistentAutoDictionary.AddWithSuccessCountOne(DE);
+ DE->IncSuccessCount();
+ assert(DE->GetW().size());
+ // Linear search is fine here as this happens seldom.
+ if (!PersistentAutoDictionary.ContainsWord(DE->GetW()))
+ PersistentAutoDictionary.push_back(*DE);
+ }
+}
+
+void MutationDispatcher::PrintRecommendedDictionary() {
+ Vector<DictionaryEntry> V;
+ for (auto &DE : PersistentAutoDictionary)
+ if (!ManualDictionary.ContainsWord(DE.GetW()))
+ V.push_back(DE);
+ if (V.empty()) return;
Printf("###### Recommended dictionary. ######\n");
- for (auto &DE : RecommendedDictionary) {
+ for (auto &DE: V) {
assert(DE.GetW().size());
Printf("\"");
PrintASCII(DE.GetW(), "\"");
@@ -80,12 +500,97 @@ void PrintRecommendedDictionary(MutationDispatcher &MD) {
Printf("###### End of recommended dictionary. ######\n");
}
-void PrintMutationSequence(MutationDispatcher &MD, bool Verbose) {
- const auto &MS = MD.MutationSequence();
- const auto &DS = MD.DictionaryEntrySequence();
- Printf("MS: %zd %s", MS.size(), MS.GetString(Verbose).c_str());
- if (!DS.empty())
- Printf(" DE: %s", DS.GetString(Verbose).c_str());
+void MutationDispatcher::PrintMutationSequence(bool Verbose) {
+ Printf("MS: %zd ", CurrentMutatorSequence.size());
+ size_t EntriesToPrint =
+ Verbose ? CurrentMutatorSequence.size()
+ : std::min(kMaxMutationsToPrint, CurrentMutatorSequence.size());
+ for (size_t i = 0; i < EntriesToPrint; i++)
+ Printf("%s-", CurrentMutatorSequence[i].Name);
+ if (!CurrentDictionaryEntrySequence.empty()) {
+ Printf(" DE: ");
+ EntriesToPrint = Verbose ? CurrentDictionaryEntrySequence.size()
+ : std::min(kMaxMutationsToPrint,
+ CurrentDictionaryEntrySequence.size());
+ for (size_t i = 0; i < EntriesToPrint; i++) {
+ Printf("\"");
+ PrintASCII(CurrentDictionaryEntrySequence[i]->GetW(), "\"-");
+ }
+ }
+}
+
+std::string MutationDispatcher::MutationSequence() {
+ std::string MS;
+ for (auto M : CurrentMutatorSequence) {
+ MS += M.Name;
+ MS += "-";
+ }
+ return MS;
+}
+
+size_t MutationDispatcher::Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {
+ return MutateImpl(Data, Size, MaxSize, Mutators);
+}
+
+size_t MutationDispatcher::DefaultMutate(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ return MutateImpl(Data, Size, MaxSize, DefaultMutators);
+}
+
+// Mutates Data in place, returns new size.
+size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size,
+ size_t MaxSize,
+ Vector<Mutator> &Mutators) {
+ assert(MaxSize > 0);
+ // Some mutations may fail (e.g. can't insert more bytes if Size == MaxSize),
+ // in which case they will return 0.
+ // Try several times before returning un-mutated data.
+ for (int Iter = 0; Iter < 100; Iter++) {
+ auto M = Mutators[Rand(Mutators.size())];
+ size_t NewSize = (this->*(M.Fn))(Data, Size, MaxSize);
+ if (NewSize && NewSize <= MaxSize) {
+ if (Options.OnlyASCII)
+ ToASCII(Data, NewSize);
+ CurrentMutatorSequence.push_back(M);
+ return NewSize;
+ }
+ }
+ *Data = ' ';
+ return 1; // Fallback, should not happen frequently.
+}
+
+// Mask represents the set of Data bytes that are worth mutating.
+size_t MutationDispatcher::MutateWithMask(uint8_t *Data, size_t Size,
+ size_t MaxSize,
+ const Vector<uint8_t> &Mask) {
+ size_t MaskedSize = std::min(Size, Mask.size());
+ // * Copy the worthy bytes into a temporary array T
+ // * Mutate T
+ // * Copy T back.
+ // This is totally unoptimized.
+ auto &T = MutateWithMaskTemp;
+ if (T.size() < Size)
+ T.resize(Size);
+ size_t OneBits = 0;
+ for (size_t I = 0; I < MaskedSize; I++)
+ if (Mask[I])
+ T[OneBits++] = Data[I];
+
+ if (!OneBits) return 0;
+ assert(!T.empty());
+ size_t NewSize = Mutate(T.data(), OneBits, OneBits);
+ assert(NewSize <= OneBits);
+ (void)NewSize;
+ // Even if NewSize < OneBits we still use all OneBits bytes.
+ for (size_t I = 0, J = 0; I < MaskedSize; I++)
+ if (Mask[I])
+ Data[I] = T[J++];
+ return Size;
+}
+
+void MutationDispatcher::AddWordToManualDictionary(const Word &W) {
+ ManualDictionary.push_back(
+ {W, std::numeric_limits<size_t>::max()});
}
} // namespace fuzzer
diff --git a/compiler-rt/lib/fuzzer/FuzzerMutate.h b/compiler-rt/lib/fuzzer/FuzzerMutate.h
index 85e284ef571c1..fd37191156d3f 100644
--- a/compiler-rt/lib/fuzzer/FuzzerMutate.h
+++ b/compiler-rt/lib/fuzzer/FuzzerMutate.h
@@ -11,23 +11,145 @@
#ifndef LLVM_FUZZER_MUTATE_H
#define LLVM_FUZZER_MUTATE_H
+#include "FuzzerDefs.h"
+#include "FuzzerDictionary.h"
#include "FuzzerOptions.h"
-#include "mutagen/Mutagen.h"
-#include "mutagen/MutagenDispatcher.h"
+#include "FuzzerRandom.h"
namespace fuzzer {
-namespace {
-using mutagen::MutationDispatcher;
+class MutationDispatcher {
+public:
+ MutationDispatcher(Random &Rand, const FuzzingOptions &Options);
+ ~MutationDispatcher() {}
+ /// Indicate that we are about to start a new sequence of mutations.
+ void StartMutationSequence();
+ /// Print the current sequence of mutations. Only prints the full sequence
+ /// when Verbose is true.
+ void PrintMutationSequence(bool Verbose = true);
+ /// Return the current sequence of mutations.
+ std::string MutationSequence();
+ /// Indicate that the current sequence of mutations was successful.
+ void RecordSuccessfulMutationSequence();
+ /// Mutates data by invoking user-provided mutator.
+ size_t Mutate_Custom(uint8_t *Data, size_t Size, size_t MaxSize);
+ /// Mutates data by invoking user-provided crossover.
+ size_t Mutate_CustomCrossOver(uint8_t *Data, size_t Size, size_t MaxSize);
+ /// Mutates data by shuffling bytes.
+ size_t Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize);
+ /// Mutates data by erasing bytes.
+ size_t Mutate_EraseBytes(uint8_t *Data, size_t Size, size_t MaxSize);
+ /// Mutates data by inserting a byte.
+ size_t Mutate_InsertByte(uint8_t *Data, size_t Size, size_t MaxSize);
+ /// Mutates data by inserting several repeated bytes.
+ size_t Mutate_InsertRepeatedBytes(uint8_t *Data, size_t Size, size_t MaxSize);
+ /// Mutates data by changing one byte.
+ size_t Mutate_ChangeByte(uint8_t *Data, size_t Size, size_t MaxSize);
+ /// Mutates data by changing one bit.
+ size_t Mutate_ChangeBit(uint8_t *Data, size_t Size, size_t MaxSize);
+ /// Mutates data by copying/inserting a part of data into a
diff erent place.
+ size_t Mutate_CopyPart(uint8_t *Data, size_t Size, size_t MaxSize);
-} // namespace
+ /// Mutates data by adding a word from the manual dictionary.
+ size_t Mutate_AddWordFromManualDictionary(uint8_t *Data, size_t Size,
+ size_t MaxSize);
-void ConfigureMutagen(unsigned int Seed, const FuzzingOptions &Options,
- LLVMMutagenConfiguration *OutConfig);
+ /// Mutates data by adding a word from the TORC.
+ size_t Mutate_AddWordFromTORC(uint8_t *Data, size_t Size, size_t MaxSize);
-void PrintRecommendedDictionary(MutationDispatcher &MD);
+ /// Mutates data by adding a word from the persistent automatic dictionary.
+ size_t Mutate_AddWordFromPersistentAutoDictionary(uint8_t *Data, size_t Size,
+ size_t MaxSize);
-void PrintMutationSequence(MutationDispatcher &MD, bool Verbose = true);
+ /// Tries to find an ASCII integer in Data, changes it to another ASCII int.
+ size_t Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size, size_t MaxSize);
+ /// Change a 1-, 2-, 4-, or 8-byte integer in interesting ways.
+ size_t Mutate_ChangeBinaryInteger(uint8_t *Data, size_t Size, size_t MaxSize);
+
+ /// CrossOver Data with CrossOverWith.
+ size_t Mutate_CrossOver(uint8_t *Data, size_t Size, size_t MaxSize);
+
+ /// Applies one of the configured mutations.
+ /// Returns the new size of data which could be up to MaxSize.
+ size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize);
+
+ /// Applies one of the configured mutations to the bytes of Data
+ /// that have '1' in Mask.
+ /// Mask.size() should be >= Size.
+ size_t MutateWithMask(uint8_t *Data, size_t Size, size_t MaxSize,
+ const Vector<uint8_t> &Mask);
+
+ /// Applies one of the default mutations. Provided as a service
+ /// to mutation authors.
+ size_t DefaultMutate(uint8_t *Data, size_t Size, size_t MaxSize);
+
+ /// Creates a cross-over of two pieces of Data, returns its size.
+ size_t CrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2,
+ size_t Size2, uint8_t *Out, size_t MaxOutSize);
+
+ void AddWordToManualDictionary(const Word &W);
+
+ void PrintRecommendedDictionary();
+
+ void SetCrossOverWith(const Unit *U) { CrossOverWith = U; }
+
+ Random &GetRand() { return Rand; }
+
+ private:
+ struct Mutator {
+ size_t (MutationDispatcher::*Fn)(uint8_t *Data, size_t Size, size_t Max);
+ const char *Name;
+ };
+
+ size_t AddWordFromDictionary(Dictionary &D, uint8_t *Data, size_t Size,
+ size_t MaxSize);
+ size_t MutateImpl(uint8_t *Data, size_t Size, size_t MaxSize,
+ Vector<Mutator> &Mutators);
+
+ size_t InsertPartOf(const uint8_t *From, size_t FromSize, uint8_t *To,
+ size_t ToSize, size_t MaxToSize);
+ size_t CopyPartOf(const uint8_t *From, size_t FromSize, uint8_t *To,
+ size_t ToSize);
+ size_t ApplyDictionaryEntry(uint8_t *Data, size_t Size, size_t MaxSize,
+ DictionaryEntry &DE);
+
+ template <class T>
+ DictionaryEntry MakeDictionaryEntryFromCMP(T Arg1, T Arg2,
+ const uint8_t *Data, size_t Size);
+ DictionaryEntry MakeDictionaryEntryFromCMP(const Word &Arg1, const Word &Arg2,
+ const uint8_t *Data, size_t Size);
+ DictionaryEntry MakeDictionaryEntryFromCMP(const void *Arg1, const void *Arg2,
+ const void *Arg1Mutation,
+ const void *Arg2Mutation,
+ size_t ArgSize,
+ const uint8_t *Data, size_t Size);
+
+ Random &Rand;
+ const FuzzingOptions Options;
+
+ // Dictionary provided by the user via -dict=DICT_FILE.
+ Dictionary ManualDictionary;
+ // Persistent dictionary modified by the fuzzer, consists of
+ // entries that led to successful discoveries in the past mutations.
+ Dictionary PersistentAutoDictionary;
+
+ Vector<DictionaryEntry *> CurrentDictionaryEntrySequence;
+
+ static const size_t kCmpDictionaryEntriesDequeSize = 16;
+ DictionaryEntry CmpDictionaryEntriesDeque[kCmpDictionaryEntriesDequeSize];
+ size_t CmpDictionaryEntriesDequeIdx = 0;
+
+ const Unit *CrossOverWith = nullptr;
+ Vector<uint8_t> MutateInPlaceHere;
+ Vector<uint8_t> MutateWithMaskTemp;
+ // CustomCrossOver needs its own buffer as a custom implementation may call
+ // LLVMFuzzerMutate, which in turn may resize MutateInPlaceHere.
+ Vector<uint8_t> CustomCrossOverInPlaceHere;
+
+ Vector<Mutator> Mutators;
+ Vector<Mutator> DefaultMutators;
+ Vector<Mutator> CurrentMutatorSequence;
+};
} // namespace fuzzer
diff --git a/compiler-rt/lib/fuzzer/FuzzerRandom.h b/compiler-rt/lib/fuzzer/FuzzerRandom.h
index 8256853a65bb5..ad6c07eb5ef56 100644
--- a/compiler-rt/lib/fuzzer/FuzzerRandom.h
+++ b/compiler-rt/lib/fuzzer/FuzzerRandom.h
@@ -11,7 +11,6 @@
#ifndef LLVM_FUZZER_RANDOM_H
#define LLVM_FUZZER_RANDOM_H
-#include <cassert>
#include <random>
namespace fuzzer {
diff --git a/compiler-rt/lib/fuzzer/FuzzerTracePC.cpp b/compiler-rt/lib/fuzzer/FuzzerTracePC.cpp
index b613aef7b59f5..d808b9b00fa35 100644
--- a/compiler-rt/lib/fuzzer/FuzzerTracePC.cpp
+++ b/compiler-rt/lib/fuzzer/FuzzerTracePC.cpp
@@ -16,6 +16,7 @@
#include "FuzzerBuiltinsMsvc.h"
#include "FuzzerCorpus.h"
#include "FuzzerDefs.h"
+#include "FuzzerDictionary.h"
#include "FuzzerExtFunctions.h"
#include "FuzzerIO.h"
#include "FuzzerPlatform.h"
diff --git a/compiler-rt/lib/fuzzer/FuzzerTracePC.h b/compiler-rt/lib/fuzzer/FuzzerTracePC.h
index 921a13f082ae3..a93732972f7d7 100644
--- a/compiler-rt/lib/fuzzer/FuzzerTracePC.h
+++ b/compiler-rt/lib/fuzzer/FuzzerTracePC.h
@@ -12,7 +12,7 @@
#define LLVM_FUZZER_TRACE_PC
#include "FuzzerDefs.h"
-#include "FuzzerUtil.h"
+#include "FuzzerDictionary.h"
#include "FuzzerValueBitMap.h"
#include <set>
@@ -40,7 +40,7 @@ struct TableOfRecentCompares {
Table[Idx].B = Arg2;
}
- const Pair &Get(size_t I) { return Table[I % kSize]; }
+ Pair Get(size_t I) { return Table[I % kSize]; }
Pair Table[kSize];
};
diff --git a/compiler-rt/lib/fuzzer/FuzzerUtil.h b/compiler-rt/lib/fuzzer/FuzzerUtil.h
index 285f56be8a767..a188a7be32a53 100644
--- a/compiler-rt/lib/fuzzer/FuzzerUtil.h
+++ b/compiler-rt/lib/fuzzer/FuzzerUtil.h
@@ -47,15 +47,6 @@ void PrintMemoryProfile();
unsigned NumberOfCpuCores();
-// Parses one dictionary entry.
-// If successful, write the enty to Unit and returns true,
-// otherwise returns false.
-bool ParseOneDictionaryEntry(const std::string &Str, Unit *U);
-
-// Parses the dictionary file, fills Units, returns true iff all lines
-// were parsed successfully.
-bool ParseDictionaryFile(const std::string &Text, Vector<Unit> *Units);
-
// Platform specific functions.
void SetSignalHandler(const FuzzingOptions& Options);
@@ -72,6 +63,9 @@ bool ExecuteCommand(const Command &Cmd, std::string *CmdOutput);
FILE *OpenProcessPipe(const char *Command, const char *Mode);
int CloseProcessPipe(FILE *F);
+const void *SearchMemory(const void *haystack, size_t haystacklen,
+ const void *needle, size_t needlelen);
+
std::string CloneArgsWithoutX(const Vector<std::string> &Args,
const char *X1, const char *X2);
diff --git a/compiler-rt/lib/fuzzer/FuzzerUtilFuchsia.cpp b/compiler-rt/lib/fuzzer/FuzzerUtilFuchsia.cpp
index e83baa62886c0..5034b4a28d3f5 100644
--- a/compiler-rt/lib/fuzzer/FuzzerUtilFuchsia.cpp
+++ b/compiler-rt/lib/fuzzer/FuzzerUtilFuchsia.cpp
@@ -528,6 +528,11 @@ bool ExecuteCommand(const Command &BaseCmd, std::string *CmdOutput) {
return Ret == 0;
}
+const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
+ size_t PattLen) {
+ return memmem(Data, DataLen, Patt, PattLen);
+}
+
// In fuchsia, accessing /dev/null is not supported. There's nothing
// similar to a file that discards everything that is written to it.
// The way of doing something similar in fuchsia is by using
diff --git a/compiler-rt/lib/fuzzer/FuzzerUtilPosix.cpp b/compiler-rt/lib/fuzzer/FuzzerUtilPosix.cpp
index 5f0aa0190dd66..0446d732a9ec8 100644
--- a/compiler-rt/lib/fuzzer/FuzzerUtilPosix.cpp
+++ b/compiler-rt/lib/fuzzer/FuzzerUtilPosix.cpp
@@ -170,6 +170,11 @@ int CloseProcessPipe(FILE *F) {
return pclose(F);
}
+const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
+ size_t PattLen) {
+ return memmem(Data, DataLen, Patt, PattLen);
+}
+
std::string DisassembleCmd(const std::string &FileName) {
return "objdump -d " + FileName;
}
diff --git a/compiler-rt/lib/fuzzer/FuzzerUtilWindows.cpp b/compiler-rt/lib/fuzzer/FuzzerUtilWindows.cpp
index 5deb5998fccb4..1a54bb569eca4 100644
--- a/compiler-rt/lib/fuzzer/FuzzerUtilWindows.cpp
+++ b/compiler-rt/lib/fuzzer/FuzzerUtilWindows.cpp
@@ -182,6 +182,27 @@ bool ExecuteCommand(const Command &Cmd, std::string *CmdOutput) {
return _pclose(Pipe) == 0;
}
+const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
+ size_t PattLen) {
+ // TODO: make this implementation more efficient.
+ const char *Cdata = (const char *)Data;
+ const char *Cpatt = (const char *)Patt;
+
+ if (!Data || !Patt || DataLen == 0 || PattLen == 0 || DataLen < PattLen)
+ return NULL;
+
+ if (PattLen == 1)
+ return memchr(Data, *Cpatt, DataLen);
+
+ const char *End = Cdata + DataLen - PattLen + 1;
+
+ for (const char *It = Cdata; It < End; ++It)
+ if (It[0] == Cpatt[0] && memcmp(It, Cpatt, PattLen) == 0)
+ return It;
+
+ return NULL;
+}
+
std::string DisassembleCmd(const std::string &FileName) {
Vector<std::string> command_vector;
command_vector.push_back("dumpbin /summary > nul");
diff --git a/compiler-rt/lib/fuzzer/build.sh b/compiler-rt/lib/fuzzer/build.sh
index 822b606041278..504e54e3a819e 100755
--- a/compiler-rt/lib/fuzzer/build.sh
+++ b/compiler-rt/lib/fuzzer/build.sh
@@ -1,11 +1,11 @@
#!/bin/sh
LIBFUZZER_SRC_DIR=$(dirname $0)
-LIBMUTAGEN_SRC_DIR=$LIBFUZZER_SRC_DIR/mutagen
CXX="${CXX:-clang}"
-for f in $LIBFUZZER_SRC_DIR/*.cpp $LIBMUTAGEN_SRC_DIR/*.cpp; do
- $CXX -g -O2 -fno-omit-frame-pointer -std=c++11 $f -c -I$LIBFUZZER_SRC_DIR &
+for f in $LIBFUZZER_SRC_DIR/*.cpp; do
+ $CXX -g -O2 -fno-omit-frame-pointer -std=c++11 $f -c &
done
wait
rm -f libFuzzer.a
-ar ru libFuzzer.a Fuzzer*.o Mutagen*.o
-rm -f Fuzzer*.o Mutagen*.o
+ar ru libFuzzer.a Fuzzer*.o
+rm -f Fuzzer*.o
+
diff --git a/compiler-rt/lib/fuzzer/mutagen/CMakeLists.txt b/compiler-rt/lib/fuzzer/mutagen/CMakeLists.txt
deleted file mode 100644
index 1a8175ce6e6ec..0000000000000
--- a/compiler-rt/lib/fuzzer/mutagen/CMakeLists.txt
+++ /dev/null
@@ -1,59 +0,0 @@
-set(MUTAGEN_SOURCES
- Mutagen.cpp
- MutagenCrossOver.cpp
- MutagenDispatcher.cpp
- MutagenUtilPosix.cpp
- MutagenUtilWindows.cpp)
-
-set(MUTAGEN_HEADERS
- Mutagen.h
- MutagenDictionary.h
- MutagenDispatcher.h
- MutagenUtil.h)
-
-# Expose the files in this library to libFuzzer for optimized, direct inclusion.
-set(LIBFUZZER_MUTAGEN_SOURCES ${MUTAGEN_SOURCES} PARENT_SCOPE)
-set(LIBFUZZER_MUTAGEN_HEADERS ${MUTAGEN_HEADERS} PARENT_SCOPE)
-
-# Reuse the following variables from libFuzzer:
-# FUZZER_SUPPORTED_ARCH
-# FUZZER_SUPPORTED_OS
-# LIBFUZZER_CFLAGS
-# LIBFUZZER_DEPS
-include_directories(..)
-
-add_compiler_rt_component(mutagen)
-
-add_compiler_rt_object_libraries(RTmutagen
- OS ${FUZZER_SUPPORTED_OS}
- ARCHS ${FUZZER_SUPPORTED_ARCH}
- SOURCES ${MUTAGEN_SOURCES}
- ADDITIONAL_HEADERS ${MUTAGEN_HEADERS}
- CFLAGS ${LIBFUZZER_CFLAGS}
- DEPS ${LIBFUZZER_DEPS})
-
-add_compiler_rt_runtime(clang_rt.mutagen
- STATIC
- OS ${FUZZER_SUPPORTED_OS}
- ARCHS ${FUZZER_SUPPORTED_ARCH}
- OBJECT_LIBS RTmutagen
- CFLAGS ${LIBFUZZER_CFLAGS}
- PARENT_TARGET mutagen)
-
-if(OS_NAME MATCHES "Linux|Fuchsia" AND
- COMPILER_RT_LIBCXX_PATH AND
- COMPILER_RT_LIBCXXABI_PATH)
- foreach(arch ${FUZZER_SUPPORTED_ARCH})
- get_target_flags_for_arch(${arch} TARGET_CFLAGS)
- set(LIBCXX_${arch}_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/libcxx_mutagen_${arch})
- add_custom_libcxx(libcxx_mutagen_${arch} ${LIBCXX_${arch}_PREFIX}
- CFLAGS ${TARGET_CFLAGS}
- CMAKE_ARGS -DCMAKE_CXX_COMPILER_WORKS=ON
- -DCMAKE_POSITION_INDEPENDENT_CODE=ON
- -DLIBCXXABI_ENABLE_EXCEPTIONS=OFF
- -DLIBCXX_ABI_NAMESPACE=__Fuzzer)
- target_compile_options(RTmutagen.${arch} PRIVATE -isystem ${LIBCXX_${arch}_PREFIX}/include/c++/v1)
- add_dependencies(RTmutagen.${arch} libcxx_mutagen_${arch}-build)
- partially_link_libcxx(mutagen ${LIBCXX_${arch}_PREFIX} ${arch})
- endforeach()
-endif()
diff --git a/compiler-rt/lib/fuzzer/mutagen/Mutagen.cpp b/compiler-rt/lib/fuzzer/mutagen/Mutagen.cpp
deleted file mode 100644
index 8d5858191afeb..0000000000000
--- a/compiler-rt/lib/fuzzer/mutagen/Mutagen.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-//===- Mutagen.cpp - Interface header for the mutagen -----------*- C++ -* ===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-// Define the interface between libMutagen and its consumers.
-//===----------------------------------------------------------------------===//
-
-#include "Mutagen.h"
-#include "FuzzerDefs.h"
-#include "MutagenDispatcher.h"
-#include <algorithm>
-#include <cstdio>
-#include <string>
-
-namespace mutagen {
-namespace {
-
-MutationDispatcher *MD = nullptr;
-
-} // namespace
-
-MutationDispatcher *GetMutationDispatcherForTest() { return MD; }
-
-} // namespace mutagen
-
-using fuzzer::Unit;
-using mutagen::MD;
-using mutagen::MutationDispatcher;
-using mutagen::Word;
-
-extern "C" {
-
-ATTRIBUTE_INTERFACE void
-LLVMMutagenConfigure(const LLVMMutagenConfiguration *Config) {
- if (MD)
- delete MD;
- MD = new MutationDispatcher(Config);
-}
-
-ATTRIBUTE_INTERFACE void LLVMMutagenResetSequence() {
- MD->StartMutationSequence();
-}
-
-ATTRIBUTE_INTERFACE void LLVMMutagenSetCrossOverWith(const uint8_t *Data,
- size_t Size) {
- static Unit CrossOverWith;
- Unit U(Data, Data + Size);
- CrossOverWith = std::move(U);
- MD->SetCrossOverWith(&CrossOverWith);
-}
-
-ATTRIBUTE_INTERFACE size_t LLVMMutagenMutate(uint8_t *Data, size_t Size,
- size_t Max) {
- return MD->Mutate(Data, Size, Max);
-}
-
-ATTRIBUTE_INTERFACE size_t LLVMMutagenDefaultMutate(uint8_t *Data, size_t Size,
- size_t Max) {
- return MD->DefaultMutate(Data, Size, Max);
-}
-
-ATTRIBUTE_INTERFACE void LLVMMutagenRecordSequence() {
- MD->RecordSuccessfulMutationSequence();
-}
-
-ATTRIBUTE_INTERFACE size_t LLVMMutagenGetMutationSequence(int Verbose,
- char *Out, size_t Max,
- size_t *OutNumItems) {
- const auto &Seq = MD->MutationSequence();
- if (OutNumItems)
- *OutNumItems = Seq.size();
- return snprintf(Out, Max, "%s", Seq.GetString(Verbose).c_str());
-}
-
-ATTRIBUTE_INTERFACE void LLVMMutagenAddWordToDictionary(const uint8_t *Data,
- size_t Size) {
- MD->AddWordToManualDictionary(Word(Data, std::min(Size, Word::GetMaxSize())));
-}
-
-ATTRIBUTE_INTERFACE size_t LLVMMutagenGetDictionaryEntrySequence(
- int Verbose, char *Out, size_t Max, size_t *OutNumItems) {
- const auto &Seq = MD->DictionaryEntrySequence();
- if (OutNumItems)
- *OutNumItems = Seq.size();
- return snprintf(Out, Max, "%s", Seq.GetString(Verbose).c_str());
-}
-
-ATTRIBUTE_INTERFACE size_t LLVMMutagenRecommendDictionary() {
- return MD->RecommendDictionary().size();
-}
-
-ATTRIBUTE_INTERFACE const char *
-LLVMMutagenRecommendDictionaryEntry(size_t *OutUseCount) {
- return MD->RecommendDictionaryEntry(OutUseCount);
-}
-
-} // extern "C"
diff --git a/compiler-rt/lib/fuzzer/mutagen/Mutagen.h b/compiler-rt/lib/fuzzer/mutagen/Mutagen.h
deleted file mode 100644
index 757ee3e07d2cd..0000000000000
--- a/compiler-rt/lib/fuzzer/mutagen/Mutagen.h
+++ /dev/null
@@ -1,119 +0,0 @@
-//===- Mutagen.h - Interface header for the mutagen -------------*- C++ -* ===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-// Define the interface between libMutagen and its consumers.
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_FUZZER_MUTAGEN_H
-#define LLVM_FUZZER_MUTAGEN_H
-
-#include "FuzzerPlatform.h"
-#include <stddef.h>
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif // __cplusplus
-
-#define MAX_WORD_SIZE 64
-
-typedef struct {
- // PRNG seed.
- unsigned int Seed;
-
- // If non-zero, use CMP traces to guide mutations. Ignored if any of
- // |FromTORC4|, |FromTORC8|, or |FromTORCW| are null.
- int UseCmp;
- void (*FromTORC4)(size_t Idx, uint32_t *Arg1, uint32_t *Arg2);
- void (*FromTORC8)(size_t Idx, uint64_t *Arg1, uint64_t *Arg2);
- void (*FromTORCW)(size_t Idx, const uint8_t **Data1, size_t *Size1,
- const uint8_t **Data2, size_t *Size2);
-
- // If non-zero, use hints from intercepting memmem, strstr, etc. Ignored if
- // |UseCmp| is zero or if |FromMMT| is null.
- int UseMemmem;
- void (*FromMMT)(size_t Idx, const uint8_t **Data, size_t *Size);
-
- // If non-zero, generate only ASCII (isprint+isspace) inputs.
- int OnlyASCII;
-
- // Optional user-provided custom mutator.
- size_t (*CustomMutator)(uint8_t *Data, size_t Size, size_t MaxSize,
- unsigned int Seed);
-
- // Optional user-provided custom cross-over function.
- size_t (*CustomCrossOver)(const uint8_t *Data1, size_t Size1,
- const uint8_t *Data2, size_t Size2, uint8_t *Out,
- size_t MaxOutSize, unsigned int Seed);
-
- // Optional MemorySanitizer callbacks.
- void (*MSanUnpoison)(const volatile void *, size_t size);
- void (*MSanUnpoisonParam)(size_t n);
-} LLVMMutagenConfiguration;
-
-// Re-seeds the PRNG and sets mutator-related options.
-ATTRIBUTE_INTERFACE void
-LLVMMutagenConfigure(const LLVMMutagenConfiguration *config);
-
-// Writes the mutation sequence to |Out|, and returns the number of
-// characters it wrote, or would have written given a large enough buffer,
-// excluding the null terminator. Thus, a return value of |Max| or greater
-// indicates the sequence was truncated (like snprintf). May truncate the
-// sequence unless |Verbose| is non-zero. Sets |OutNumItems| to the number of
-// items in the untruncated sequence.
-ATTRIBUTE_INTERFACE size_t LLVMMutagenGetMutationSequence(int Verbose,
- char *Out, size_t Max,
- size_t *OutNumItems);
-
-// Writes the dictionary entry sequence to |Out|, and returns the number of
-// characters it wrote, or would have written given a large enough buffer,
-// excluding a null terminator. Thus, a return value of |Max| or greater
-// indicates the sequence was truncated (like snprintf). May truncate the
-// sequence unless |Verbose| is non-zero. Sets |OutNumItems| to the number of
-// items in the untruncated sequence.
-ATTRIBUTE_INTERFACE size_t LLVMMutagenGetDictionaryEntrySequence(
- int Verbose, char *Out, size_t Max, size_t *OutNumItems);
-
-// Instructs the library to record the current mutation sequence as successful
-// at increasing coverage.
-ATTRIBUTE_INTERFACE void LLVMMutagenRecordSequence();
-
-// Clears the mutation and dictionary entry sequences.
-ATTRIBUTE_INTERFACE void LLVMMutagenResetSequence();
-
-// Adds data used by various mutators to produce new inputs.
-ATTRIBUTE_INTERFACE void LLVMMutagenSetCrossOverWith(const uint8_t *Data,
- size_t Size);
-ATTRIBUTE_INTERFACE void LLVMMutagenAddWordToDictionary(const uint8_t *Word,
- size_t Size);
-
-// Mutates the contents of |Data| and returns the new size.
-ATTRIBUTE_INTERFACE size_t LLVMMutagenMutate(uint8_t *Data, size_t Size,
- size_t Max);
-
-// Like |LLVMMutagenMutate|, but never selects the custom mutators and is
-// therefore suitable to be called from them.
-ATTRIBUTE_INTERFACE size_t LLVMMutagenDefaultMutate(uint8_t *Data, size_t Size,
- size_t Max);
-
-// Creates a recommended dictionary and returns its number of entries. The
-// entries can be retrieved by subsequent calls to
-// |LLVMMutagenRecommendDictionaryEntry|.
-ATTRIBUTE_INTERFACE size_t LLVMMutagenRecommendDictionary();
-
-// Returns the ASCII representation of the next recommended dictionary entry,
-// or null if no entries remain (or |LLVMMutagenRecommendDictionary| wasn't
-// called). If non-null, the return pointer is valid until the next call to this
-// method, and if provided, |OutUseCount| is set to the entry's use count.
-ATTRIBUTE_INTERFACE const char *
-LLVMMutagenRecommendDictionaryEntry(size_t *OutUseCount);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif // __cplusplus
-
-#endif // LLVM_FUZZER_MUTAGEN_H
diff --git a/compiler-rt/lib/fuzzer/mutagen/MutagenDictionary.h b/compiler-rt/lib/fuzzer/mutagen/MutagenDictionary.h
deleted file mode 100644
index a665cabc316e7..0000000000000
--- a/compiler-rt/lib/fuzzer/mutagen/MutagenDictionary.h
+++ /dev/null
@@ -1,85 +0,0 @@
-//===- MutagenDictionary.h - Internal header for the mutagen ----*- C++ -* ===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-// mutagen::Dictionary
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_FUZZER_MUTAGEN_DICTIONARY_H
-#define LLVM_FUZZER_MUTAGEN_DICTIONARY_H
-
-#include "FuzzerDefs.h"
-#include <algorithm>
-#include <cassert>
-#include <cstddef>
-#include <cstdint>
-#include <limits>
-
-namespace mutagen {
-namespace {
-
-using fuzzer::Word;
-
-} // namespace
-
-class DictionaryEntry {
-public:
- DictionaryEntry() {}
- DictionaryEntry(Word W) : W(W) {}
- DictionaryEntry(Word W, size_t PositionHint)
- : W(W), PositionHint(PositionHint) {}
- const Word &GetW() const { return W; }
-
- bool HasPositionHint() const {
- return PositionHint != std::numeric_limits<size_t>::max();
- }
- size_t GetPositionHint() const {
- assert(HasPositionHint());
- return PositionHint;
- }
- void IncUseCount() { UseCount++; }
- void IncSuccessCount() { SuccessCount++; }
- size_t GetUseCount() const { return UseCount; }
- size_t GetSuccessCount() const { return SuccessCount; }
-
-private:
- Word W;
- size_t PositionHint = std::numeric_limits<size_t>::max();
- size_t UseCount = 0;
- size_t SuccessCount = 0;
-};
-
-class Dictionary {
-public:
- static const size_t kMaxDictSize = 1 << 14;
-
- bool ContainsWord(const Word &W) const {
- return std::any_of(begin(), end(), [&](const DictionaryEntry &DE) {
- return DE.GetW() == W;
- });
- }
- const DictionaryEntry *begin() const { return &DE[0]; }
- const DictionaryEntry *end() const { return begin() + Size; }
- DictionaryEntry &operator[](size_t Idx) {
- assert(Idx < Size);
- return DE[Idx];
- }
- void push_back(DictionaryEntry DE) {
- if (Size < kMaxDictSize)
- this->DE[Size++] = DE;
- }
- void clear() { Size = 0; }
- bool empty() const { return Size == 0; }
- size_t size() const { return Size; }
-
-private:
- DictionaryEntry DE[kMaxDictSize];
- size_t Size = 0;
-};
-
-} // namespace mutagen
-
-#endif // LLVM_FUZZER_MUTAGEN_DICTIONARY_H
diff --git a/compiler-rt/lib/fuzzer/mutagen/MutagenDispatcher.cpp b/compiler-rt/lib/fuzzer/mutagen/MutagenDispatcher.cpp
deleted file mode 100644
index 32b5694cc6862..0000000000000
--- a/compiler-rt/lib/fuzzer/mutagen/MutagenDispatcher.cpp
+++ /dev/null
@@ -1,659 +0,0 @@
-//===- MutagenDispatcher.cpp - Mutate a test input ------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-// Mutate a test input.
-//===----------------------------------------------------------------------===//
-
-#include "MutagenDispatcher.h"
-#include "FuzzerBuiltins.h"
-#include "FuzzerBuiltinsMsvc.h"
-#include "FuzzerPlatform.h"
-#include "MutagenUtil.h"
-#include <iomanip>
-#include <sstream>
-
-namespace mutagen {
-namespace {
-
-using fuzzer::Bswap;
-
-std::string ToASCII(const uint8_t *Data, size_t Size) {
- std::ostringstream OSS;
- for (size_t i = 0; i < Size; i++) {
- uint16_t Byte = Data[i];
- if (Byte == '\\')
- OSS << "\\\\";
- else if (Byte == '"')
- OSS << "\\\"";
- else if (Byte >= 32 && Byte < 127)
- OSS << static_cast<char>(Byte);
- else
- OSS << "\\x" << std::hex << std::setw(2) << std::setfill('0') << Byte
- << std::dec;
- }
- return OSS.str();
-}
-
-std::string ToASCII(const Word &W) { return ToASCII(W.data(), W.size()); }
-
-} // namespace
-
-void MutationDispatcher::SetConfig(const LLVMMutagenConfiguration *C) {
- memcpy(&Config, C, sizeof(Config));
- if (!Config.FromTORC4 || !Config.FromTORC8 || !Config.FromTORCW)
- Config.UseCmp = 0;
- if (!Config.FromMMT)
- Config.UseMemmem = 0;
-}
-
-MutationDispatcher::MutationDispatcher(const LLVMMutagenConfiguration *config)
- : Rand(config->Seed) {
- SetConfig(config);
- DefaultMutators.insert(
- DefaultMutators.begin(),
- {
- {&MutationDispatcher::Mutate_EraseBytes, "EraseBytes"},
- {&MutationDispatcher::Mutate_InsertByte, "InsertByte"},
- {&MutationDispatcher::Mutate_InsertRepeatedBytes,
- "InsertRepeatedBytes"},
- {&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"},
- {&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"},
- {&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"},
- {&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"},
- {&MutationDispatcher::Mutate_ChangeBinaryInteger, "ChangeBinInt"},
- {&MutationDispatcher::Mutate_CopyPart, "CopyPart"},
- {&MutationDispatcher::Mutate_CrossOver, "CrossOver"},
- {&MutationDispatcher::Mutate_AddWordFromManualDictionary,
- "ManualDict"},
- {&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary,
- "PersAutoDict"},
- });
- if (Config.UseCmp)
- DefaultMutators.push_back(
- {&MutationDispatcher::Mutate_AddWordFromTORC, "CMP"});
-
- if (Config.CustomMutator)
- Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom"});
- else
- Mutators = DefaultMutators;
-
- if (Config.CustomCrossOver)
- Mutators.push_back(
- {&MutationDispatcher::Mutate_CustomCrossOver, "CustomCrossOver"});
-}
-
-static char RandCh(Random &Rand) {
- if (Rand.RandBool())
- return static_cast<char>(Rand(256));
- const char Special[] = "!*'();:@&=+$,/?%#[]012Az-`~.\xff\x00";
- return Special[Rand(sizeof(Special) - 1)];
-}
-
-size_t MutationDispatcher::Mutate_Custom(uint8_t *Data, size_t Size,
- size_t MaxSize) {
- if (Config.MSanUnpoison)
- Config.MSanUnpoison(Data, Size);
- if (Config.MSanUnpoisonParam)
- Config.MSanUnpoisonParam(4);
- return Config.CustomMutator(Data, Size, MaxSize, Rand.Rand<unsigned int>());
-}
-
-size_t MutationDispatcher::Mutate_CustomCrossOver(uint8_t *Data, size_t Size,
- size_t MaxSize) {
- if (Size == 0)
- return 0;
- if (!CrossOverWith)
- return 0;
- const Unit &Other = *CrossOverWith;
- if (Other.empty())
- return 0;
- CustomCrossOverInPlaceHere.resize(MaxSize);
- auto &U = CustomCrossOverInPlaceHere;
-
- if (Config.MSanUnpoison) {
- Config.MSanUnpoison(Data, Size);
- Config.MSanUnpoison(Other.data(), Other.size());
- Config.MSanUnpoison(U.data(), U.size());
- }
- if (Config.MSanUnpoisonParam)
- Config.MSanUnpoisonParam(7);
- size_t NewSize =
- Config.CustomCrossOver(Data, Size, Other.data(), Other.size(), U.data(),
- U.size(), Rand.Rand<unsigned int>());
-
- if (!NewSize)
- return 0;
- assert(NewSize <= MaxSize && "CustomCrossOver returned overisized unit");
- memcpy(Data, U.data(), NewSize);
- return NewSize;
-}
-
-size_t MutationDispatcher::Mutate_ShuffleBytes(uint8_t *Data, size_t Size,
- size_t MaxSize) {
- if (Size > MaxSize || Size == 0)
- return 0;
- size_t ShuffleAmount =
- Rand(std::min(Size, (size_t)8)) + 1; // [1,8] and <= Size.
- size_t ShuffleStart = Rand(Size - ShuffleAmount);
- assert(ShuffleStart + ShuffleAmount <= Size);
- std::shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount, Rand);
- return Size;
-}
-
-size_t MutationDispatcher::Mutate_EraseBytes(uint8_t *Data, size_t Size,
- size_t MaxSize) {
- if (Size <= 1)
- return 0;
- size_t N = Rand(Size / 2) + 1;
- assert(N < Size);
- size_t Idx = Rand(Size - N + 1);
- // Erase Data[Idx:Idx+N].
- memmove(Data + Idx, Data + Idx + N, Size - Idx - N);
- // Printf("Erase: %zd %zd => %zd; Idx %zd\n", N, Size, Size - N, Idx);
- return Size - N;
-}
-
-size_t MutationDispatcher::Mutate_InsertByte(uint8_t *Data, size_t Size,
- size_t MaxSize) {
- if (Size >= MaxSize)
- return 0;
- size_t Idx = Rand(Size + 1);
- // Insert new value at Data[Idx].
- memmove(Data + Idx + 1, Data + Idx, Size - Idx);
- Data[Idx] = RandCh(Rand);
- return Size + 1;
-}
-
-size_t MutationDispatcher::Mutate_InsertRepeatedBytes(uint8_t *Data,
- size_t Size,
- size_t MaxSize) {
- const size_t kMinBytesToInsert = 3;
- if (Size + kMinBytesToInsert >= MaxSize)
- return 0;
- size_t MaxBytesToInsert = std::min(MaxSize - Size, (size_t)128);
- size_t N = Rand(MaxBytesToInsert - kMinBytesToInsert + 1) + kMinBytesToInsert;
- assert(Size + N <= MaxSize && N);
- size_t Idx = Rand(Size + 1);
- // Insert new values at Data[Idx].
- memmove(Data + Idx + N, Data + Idx, Size - Idx);
- // Give preference to 0x00 and 0xff.
- uint8_t Byte = static_cast<uint8_t>(
- Rand.RandBool() ? Rand(256) : (Rand.RandBool() ? 0 : 255));
- for (size_t i = 0; i < N; i++)
- Data[Idx + i] = Byte;
- return Size + N;
-}
-
-size_t MutationDispatcher::Mutate_ChangeByte(uint8_t *Data, size_t Size,
- size_t MaxSize) {
- if (Size > MaxSize)
- return 0;
- size_t Idx = Rand(Size);
- Data[Idx] = RandCh(Rand);
- return Size;
-}
-
-size_t MutationDispatcher::Mutate_ChangeBit(uint8_t *Data, size_t Size,
- size_t MaxSize) {
- if (Size > MaxSize)
- return 0;
- size_t Idx = Rand(Size);
- Data[Idx] ^= 1 << Rand(8);
- return Size;
-}
-
-size_t MutationDispatcher::Mutate_AddWordFromManualDictionary(uint8_t *Data,
- size_t Size,
- size_t MaxSize) {
- return AddWordFromDictionary(ManualDictionary, Data, Size, MaxSize);
-}
-
-size_t MutationDispatcher::ApplyDictionaryEntry(uint8_t *Data, size_t Size,
- size_t MaxSize,
- DictionaryEntry &DE) {
- const Word &W = DE.GetW();
- bool UsePositionHint = DE.HasPositionHint() &&
- DE.GetPositionHint() + W.size() < Size &&
- Rand.RandBool();
- if (Rand.RandBool()) { // Insert W.
- if (Size + W.size() > MaxSize)
- return 0;
- size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size + 1);
- memmove(Data + Idx + W.size(), Data + Idx, Size - Idx);
- memcpy(Data + Idx, W.data(), W.size());
- Size += W.size();
- } else { // Overwrite some bytes with W.
- if (W.size() > Size)
- return 0;
- size_t Idx =
- UsePositionHint ? DE.GetPositionHint() : Rand(Size + 1 - W.size());
- memcpy(Data + Idx, W.data(), W.size());
- }
- return Size;
-}
-
-// Somewhere in the past we have observed a comparison instructions
-// with arguments Arg1 Arg2. This function tries to guess a dictionary
-// entry that will satisfy that comparison.
-// It first tries to find one of the arguments (possibly swapped) in the
-// input and if it succeeds it creates a DE with a position hint.
-// Otherwise it creates a DE with one of the arguments w/o a position hint.
-DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP(
- const void *Arg1, const void *Arg2, const void *Arg1Mutation,
- const void *Arg2Mutation, size_t ArgSize, const uint8_t *Data,
- size_t Size) {
- bool HandleFirst = Rand.RandBool();
- const void *ExistingBytes, *DesiredBytes;
- Word W;
- const uint8_t *End = Data + Size;
- for (int Arg = 0; Arg < 2; Arg++) {
- ExistingBytes = HandleFirst ? Arg1 : Arg2;
- DesiredBytes = HandleFirst ? Arg2Mutation : Arg1Mutation;
- HandleFirst = !HandleFirst;
- W.Set(reinterpret_cast<const uint8_t *>(DesiredBytes), ArgSize);
- const size_t kMaxNumPositions = 8;
- size_t Positions[kMaxNumPositions];
- size_t NumPositions = 0;
- for (const uint8_t *Cur = Data;
- Cur < End && NumPositions < kMaxNumPositions; Cur++) {
- Cur =
- (const uint8_t *)SearchMemory(Cur, End - Cur, ExistingBytes, ArgSize);
- if (!Cur)
- break;
- Positions[NumPositions++] = Cur - Data;
- }
- if (!NumPositions)
- continue;
- return DictionaryEntry(W, Positions[Rand(NumPositions)]);
- }
- DictionaryEntry DE(W);
- return DE;
-}
-
-template <class T>
-DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP(
- T Arg1, T Arg2, const uint8_t *Data, size_t Size) {
- if (Rand.RandBool())
- Arg1 = Bswap(Arg1);
- if (Rand.RandBool())
- Arg2 = Bswap(Arg2);
- T Arg1Mutation = static_cast<T>(Arg1 + Rand(-1, 1));
- T Arg2Mutation = static_cast<T>(Arg2 + Rand(-1, 1));
- return MakeDictionaryEntryFromCMP(&Arg1, &Arg2, &Arg1Mutation, &Arg2Mutation,
- sizeof(Arg1), Data, Size);
-}
-
-size_t MutationDispatcher::Mutate_AddWordFromTORC(uint8_t *Data, size_t Size,
- size_t MaxSize) {
- Word W;
- DictionaryEntry DE;
- switch (Rand(4)) {
- case 0: {
- uint64_t A, B;
- Config.FromTORC8(Rand.Rand<size_t>(), &A, &B);
- DE = MakeDictionaryEntryFromCMP(A, B, Data, Size);
- } break;
- case 1: {
- uint32_t A, B;
- Config.FromTORC4(Rand.Rand<size_t>(), &A, &B);
- if ((A >> 16) == 0 && (B >> 16) == 0 && Rand.RandBool())
- DE = MakeDictionaryEntryFromCMP((uint16_t)A, (uint16_t)B, Data, Size);
- else
- DE = MakeDictionaryEntryFromCMP(A, B, Data, Size);
- } break;
- case 2: {
- const uint8_t *DataA, *DataB;
- size_t SizeA, SizeB;
- Config.FromTORCW(Rand.Rand<size_t>(), &DataA, &SizeA, &DataB, &SizeB);
- DE = MakeDictionaryEntryFromCMP(DataA, DataB, DataA, DataB, SizeA, Data,
- Size);
- } break;
- case 3:
- if (Config.UseMemmem) {
- const uint8_t *DataW;
- size_t SizeW;
- Config.FromMMT(Rand.Rand<size_t>(), &DataW, &SizeW);
- DE = DictionaryEntry(Word(DataW, SizeW));
- }
- break;
- default:
- assert(0);
- }
- if (!DE.GetW().size())
- return 0;
- Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE);
- if (!Size)
- return 0;
- DictionaryEntry &DERef =
- CmpDictionaryEntriesDeque[CmpDictionaryEntriesDequeIdx++ %
- kCmpDictionaryEntriesDequeSize];
- DERef = DE;
- CurrentDictionaryEntrySequence.push_back(&DERef);
- return Size;
-}
-
-size_t MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary(
- uint8_t *Data, size_t Size, size_t MaxSize) {
- return AddWordFromDictionary(PersistentAutoDictionary, Data, Size, MaxSize);
-}
-
-size_t MutationDispatcher::AddWordFromDictionary(Dictionary &D, uint8_t *Data,
- size_t Size, size_t MaxSize) {
- if (Size > MaxSize)
- return 0;
- if (D.empty())
- return 0;
- DictionaryEntry &DE = D[Rand(D.size())];
- Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE);
- if (!Size)
- return 0;
- DE.IncUseCount();
- CurrentDictionaryEntrySequence.push_back(&DE);
- return Size;
-}
-
-// Overwrites part of To[0,ToSize) with a part of From[0,FromSize).
-// Returns ToSize.
-size_t MutationDispatcher::CopyPartOf(const uint8_t *From, size_t FromSize,
- uint8_t *To, size_t ToSize) {
- // Copy From[FromBeg, FromBeg + CopySize) into To[ToBeg, ToBeg + CopySize).
- size_t ToBeg = Rand(ToSize);
- size_t CopySize = Rand(ToSize - ToBeg) + 1;
- assert(ToBeg + CopySize <= ToSize);
- CopySize = std::min(CopySize, FromSize);
- size_t FromBeg = Rand(FromSize - CopySize + 1);
- assert(FromBeg + CopySize <= FromSize);
- memmove(To + ToBeg, From + FromBeg, CopySize);
- return ToSize;
-}
-
-// Inserts part of From[0,ToSize) into To.
-// Returns new size of To on success or 0 on failure.
-size_t MutationDispatcher::InsertPartOf(const uint8_t *From, size_t FromSize,
- uint8_t *To, size_t ToSize,
- size_t MaxToSize) {
- if (ToSize >= MaxToSize)
- return 0;
- size_t AvailableSpace = MaxToSize - ToSize;
- size_t MaxCopySize = std::min(AvailableSpace, FromSize);
- size_t CopySize = Rand(MaxCopySize) + 1;
- size_t FromBeg = Rand(FromSize - CopySize + 1);
- assert(FromBeg + CopySize <= FromSize);
- size_t ToInsertPos = Rand(ToSize + 1);
- assert(ToInsertPos + CopySize <= MaxToSize);
- size_t TailSize = ToSize - ToInsertPos;
- if (To == From) {
- MutateInPlaceHere.resize(MaxToSize);
- memcpy(MutateInPlaceHere.data(), From + FromBeg, CopySize);
- memmove(To + ToInsertPos + CopySize, To + ToInsertPos, TailSize);
- memmove(To + ToInsertPos, MutateInPlaceHere.data(), CopySize);
- } else {
- memmove(To + ToInsertPos + CopySize, To + ToInsertPos, TailSize);
- memmove(To + ToInsertPos, From + FromBeg, CopySize);
- }
- return ToSize + CopySize;
-}
-
-size_t MutationDispatcher::Mutate_CopyPart(uint8_t *Data, size_t Size,
- size_t MaxSize) {
- if (Size > MaxSize || Size == 0)
- return 0;
- // If Size == MaxSize, `InsertPartOf(...)` will
- // fail so there's no point using it in this case.
- if (Size == MaxSize || Rand.RandBool())
- return CopyPartOf(Data, Size, Data, Size);
- else
- return InsertPartOf(Data, Size, Data, Size, MaxSize);
-}
-
-size_t MutationDispatcher::Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size,
- size_t MaxSize) {
- if (Size > MaxSize)
- return 0;
- size_t B = Rand(Size);
- while (B < Size && !isdigit(Data[B]))
- B++;
- if (B == Size)
- return 0;
- size_t E = B;
- while (E < Size && isdigit(Data[E]))
- E++;
- assert(B < E);
- // now we have digits in [B, E).
- // strtol and friends don't accept non-zero-teminated data, parse it manually.
- uint64_t Val = Data[B] - '0';
- for (size_t i = B + 1; i < E; i++)
- Val = Val * 10 + Data[i] - '0';
-
- // Mutate the integer value.
- switch (Rand(5)) {
- case 0:
- Val++;
- break;
- case 1:
- Val--;
- break;
- case 2:
- Val /= 2;
- break;
- case 3:
- Val *= 2;
- break;
- case 4:
- Val = Rand(Val * Val);
- break;
- default:
- assert(0);
- }
- // Just replace the bytes with the new ones, don't bother moving bytes.
- for (size_t i = B; i < E; i++) {
- size_t Idx = E + B - i - 1;
- assert(Idx >= B && Idx < E);
- Data[Idx] = (Val % 10) + '0';
- Val /= 10;
- }
- return Size;
-}
-
-template <class T>
-size_t ChangeBinaryInteger(uint8_t *Data, size_t Size, Random &Rand) {
- if (Size < sizeof(T))
- return 0;
- size_t Off = Rand(Size - sizeof(T) + 1);
- assert(Off + sizeof(T) <= Size);
- T Val;
- if (Off < 64 && !Rand(4)) {
- Val = static_cast<T>(Size);
- if (Rand.RandBool())
- Val = Bswap(Val);
- } else {
- memcpy(&Val, Data + Off, sizeof(Val));
- T Add = static_cast<T>(Rand(21));
- Add -= 10;
- if (Rand.RandBool())
- Val = Bswap(T(Bswap(Val) + Add)); // Add assuming
diff erent endiannes.
- else
- Val = Val + Add; // Add assuming current endiannes.
- if (Add == 0 || Rand.RandBool()) // Maybe negate.
- Val = -Val;
- }
- memcpy(Data + Off, &Val, sizeof(Val));
- return Size;
-}
-
-size_t MutationDispatcher::Mutate_ChangeBinaryInteger(uint8_t *Data,
- size_t Size,
- size_t MaxSize) {
- if (Size > MaxSize)
- return 0;
- switch (Rand(4)) {
- case 3:
- return ChangeBinaryInteger<uint64_t>(Data, Size, Rand);
- case 2:
- return ChangeBinaryInteger<uint32_t>(Data, Size, Rand);
- case 1:
- return ChangeBinaryInteger<uint16_t>(Data, Size, Rand);
- case 0:
- return ChangeBinaryInteger<uint8_t>(Data, Size, Rand);
- default:
- assert(0);
- }
- return 0;
-}
-
-size_t MutationDispatcher::Mutate_CrossOver(uint8_t *Data, size_t Size,
- size_t MaxSize) {
- if (Size > MaxSize)
- return 0;
- if (Size == 0)
- return 0;
- if (!CrossOverWith)
- return 0;
- const Unit &O = *CrossOverWith;
- if (O.empty())
- return 0;
- size_t NewSize = 0;
- switch (Rand(3)) {
- case 0:
- MutateInPlaceHere.resize(MaxSize);
- NewSize = CrossOver(Data, Size, O.data(), O.size(),
- MutateInPlaceHere.data(), MaxSize);
- memcpy(Data, MutateInPlaceHere.data(), NewSize);
- break;
- case 1:
- NewSize = InsertPartOf(O.data(), O.size(), Data, Size, MaxSize);
- if (!NewSize)
- NewSize = CopyPartOf(O.data(), O.size(), Data, Size);
- break;
- case 2:
- NewSize = CopyPartOf(O.data(), O.size(), Data, Size);
- break;
- default:
- assert(0);
- }
- assert(NewSize > 0 && "CrossOver returned empty unit");
- assert(NewSize <= MaxSize && "CrossOver returned overisized unit");
- return NewSize;
-}
-
-void MutationDispatcher::StartMutationSequence() {
- CurrentMutatorSequence.clear();
- CurrentDictionaryEntrySequence.clear();
-}
-
-// Copy successful dictionary entries to PersistentAutoDictionary.
-void MutationDispatcher::RecordSuccessfulMutationSequence() {
- for (auto *DE : CurrentDictionaryEntrySequence) {
- // PersistentAutoDictionary.AddWithSuccessCountOne(DE);
- DE->IncSuccessCount();
- assert(DE->GetW().size());
- // Linear search is fine here as this happens seldom.
- if (!PersistentAutoDictionary.ContainsWord(DE->GetW()))
- PersistentAutoDictionary.push_back(*DE);
- }
-}
-
-const Dictionary &MutationDispatcher::RecommendDictionary() {
- RecommendedDictionary.clear();
- for (auto &DE : PersistentAutoDictionary)
- if (!ManualDictionary.ContainsWord(DE.GetW()))
- RecommendedDictionary.push_back(DE);
- NextRecommendedDictionaryEntry = 0;
- return RecommendedDictionary;
-}
-
-const char *MutationDispatcher::RecommendDictionaryEntry(size_t *UseCount) {
- if (NextRecommendedDictionaryEntry >= RecommendedDictionary.size())
- return nullptr;
- auto &DE = RecommendedDictionary[NextRecommendedDictionaryEntry++];
- assert(DE.GetW().size());
- DictionaryEntryWord = ToASCII(DE.GetW());
- if (UseCount)
- *UseCount = DE.GetUseCount();
- return DictionaryEntryWord.c_str();
-}
-
-const Sequence<MutationDispatcher::Mutator> &
-MutationDispatcher::MutationSequence() {
- CurrentMutatorSequence.SetString([](Mutator M) { return M.Name; });
- return CurrentMutatorSequence;
-}
-
-const Sequence<DictionaryEntry *> &
-MutationDispatcher::DictionaryEntrySequence() {
- CurrentDictionaryEntrySequence.SetString([](DictionaryEntry *DE) {
- return std::string("\"") + ToASCII(DE->GetW()) + std::string("\"");
- });
- return CurrentDictionaryEntrySequence;
-}
-
-size_t MutationDispatcher::Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {
- return MutateImpl(Data, Size, MaxSize, Mutators);
-}
-
-size_t MutationDispatcher::DefaultMutate(uint8_t *Data, size_t Size,
- size_t MaxSize) {
- return MutateImpl(Data, Size, MaxSize, DefaultMutators);
-}
-
-// Mutates Data in place, returns new size.
-size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size,
- size_t MaxSize,
- Vector<Mutator> &Mutators) {
- assert(MaxSize > 0);
- // Some mutations may fail (e.g. can't insert more bytes if Size == MaxSize),
- // in which case they will return 0.
- // Try several times before returning un-mutated data.
- for (int Iter = 0; Iter < 100; Iter++) {
- auto M = Mutators[Rand(Mutators.size())];
- size_t NewSize = (this->*(M.Fn))(Data, Size, MaxSize);
- if (NewSize && NewSize <= MaxSize) {
- if (Config.OnlyASCII)
- ToASCII(Data, NewSize);
- CurrentMutatorSequence.push_back(M);
- return NewSize;
- }
- }
- *Data = ' ';
- return 1; // Fallback, should not happen frequently.
-}
-
-// Mask represents the set of Data bytes that are worth mutating.
-size_t MutationDispatcher::MutateWithMask(uint8_t *Data, size_t Size,
- size_t MaxSize,
- const Vector<uint8_t> &Mask) {
- size_t MaskedSize = std::min(Size, Mask.size());
- // * Copy the worthy bytes into a temporary array T
- // * Mutate T
- // * Copy T back.
- // This is totally unoptimized.
- auto &T = MutateWithMaskTemp;
- if (T.size() < Size)
- T.resize(Size);
- size_t OneBits = 0;
- for (size_t I = 0; I < MaskedSize; I++)
- if (Mask[I])
- T[OneBits++] = Data[I];
-
- if (!OneBits)
- return 0;
- assert(!T.empty());
- size_t NewSize = Mutate(T.data(), OneBits, OneBits);
- assert(NewSize <= OneBits);
- (void)NewSize;
- // Even if NewSize < OneBits we still use all OneBits bytes.
- for (size_t I = 0, J = 0; I < MaskedSize; I++)
- if (Mask[I])
- Data[I] = T[J++];
- return Size;
-}
-
-void MutationDispatcher::AddWordToManualDictionary(const Word &W) {
- ManualDictionary.push_back({W, std::numeric_limits<size_t>::max()});
-}
-
-} // namespace mutagen
diff --git a/compiler-rt/lib/fuzzer/mutagen/MutagenDispatcher.h b/compiler-rt/lib/fuzzer/mutagen/MutagenDispatcher.h
deleted file mode 100644
index c5c43d5c346fe..0000000000000
--- a/compiler-rt/lib/fuzzer/mutagen/MutagenDispatcher.h
+++ /dev/null
@@ -1,190 +0,0 @@
-//===- MutagenDispatcher.h - Internal header for the mutagen ----*- C++ -* ===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-// mutagen::MutationDispatcher
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_FUZZER_MUTAGEN_DISPATCHER_H
-#define LLVM_FUZZER_MUTAGEN_DISPATCHER_H
-
-#include "FuzzerRandom.h"
-#include "Mutagen.h"
-#include "MutagenDictionary.h"
-#include "MutagenSequence.h"
-#include <cstddef>
-#include <cstdint>
-#include <string>
-
-namespace mutagen {
-namespace {
-
-using fuzzer::Random;
-using fuzzer::Unit;
-using fuzzer::Vector;
-using fuzzer::Word;
-
-} // namespace
-
-class MutationDispatcher final {
-public:
- struct Mutator {
- size_t (MutationDispatcher::*Fn)(uint8_t *Data, size_t Size, size_t Max);
- const char *Name;
- };
-
- explicit MutationDispatcher(const LLVMMutagenConfiguration *Config);
- ~MutationDispatcher() = default;
-
- /// Indicate that we are about to start a new sequence of mutations.
- void StartMutationSequence();
- /// Returns the current sequence of mutations. May truncate the sequence
- /// unless Verbose is true. Sets |OutSize| to the length of the untrancated
- /// sequence, if provided.
- const Sequence<Mutator> &MutationSequence();
- /// Returns the current sequence of dictionary entries. May truncate the
- /// sequence unless Verbose is true. Sets |OutSize| to the length of the
- /// untrancated sequence, if provided.
- const Sequence<DictionaryEntry *> &DictionaryEntrySequence();
- /// Indicate that the current sequence of mutations was successful.
- void RecordSuccessfulMutationSequence();
- /// Mutates data by invoking user-provided mutator.
- size_t Mutate_Custom(uint8_t *Data, size_t Size, size_t MaxSize);
- /// Mutates data by invoking user-provided crossover.
- size_t Mutate_CustomCrossOver(uint8_t *Data, size_t Size, size_t MaxSize);
- /// Mutates data by shuffling bytes.
- size_t Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize);
- /// Mutates data by erasing bytes.
- size_t Mutate_EraseBytes(uint8_t *Data, size_t Size, size_t MaxSize);
- /// Mutates data by inserting a byte.
- size_t Mutate_InsertByte(uint8_t *Data, size_t Size, size_t MaxSize);
- /// Mutates data by inserting several repeated bytes.
- size_t Mutate_InsertRepeatedBytes(uint8_t *Data, size_t Size, size_t MaxSize);
- /// Mutates data by changing one byte.
- size_t Mutate_ChangeByte(uint8_t *Data, size_t Size, size_t MaxSize);
- /// Mutates data by changing one bit.
- size_t Mutate_ChangeBit(uint8_t *Data, size_t Size, size_t MaxSize);
- /// Mutates data by copying/inserting a part of data into a
diff erent place.
- size_t Mutate_CopyPart(uint8_t *Data, size_t Size, size_t MaxSize);
-
- /// Mutates data by adding a word from the manual dictionary.
- size_t Mutate_AddWordFromManualDictionary(uint8_t *Data, size_t Size,
- size_t MaxSize);
-
- /// Mutates data by adding a word from the TORC.
- size_t Mutate_AddWordFromTORC(uint8_t *Data, size_t Size, size_t MaxSize);
-
- /// Mutates data by adding a word from the persistent automatic dictionary.
- size_t Mutate_AddWordFromPersistentAutoDictionary(uint8_t *Data, size_t Size,
- size_t MaxSize);
-
- /// Tries to find an ASCII integer in Data, changes it to another ASCII int.
- size_t Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size, size_t MaxSize);
- /// Change a 1-, 2-, 4-, or 8-byte integer in interesting ways.
- size_t Mutate_ChangeBinaryInteger(uint8_t *Data, size_t Size, size_t MaxSize);
-
- /// CrossOver Data with CrossOverWith.
- size_t Mutate_CrossOver(uint8_t *Data, size_t Size, size_t MaxSize);
-
- size_t AddWordFromDictionary(Dictionary &D, uint8_t *Data, size_t Size,
- size_t MaxSize);
- size_t MutateImpl(uint8_t *Data, size_t Size, size_t MaxSize,
- Vector<Mutator> &Mutators);
-
- size_t InsertPartOf(const uint8_t *From, size_t FromSize, uint8_t *To,
- size_t ToSize, size_t MaxToSize);
- size_t CopyPartOf(const uint8_t *From, size_t FromSize, uint8_t *To,
- size_t ToSize);
- size_t ApplyDictionaryEntry(uint8_t *Data, size_t Size, size_t MaxSize,
- DictionaryEntry &DE);
-
- template <class T>
- DictionaryEntry MakeDictionaryEntryFromCMP(T Arg1, T Arg2,
- const uint8_t *Data, size_t Size);
- DictionaryEntry MakeDictionaryEntryFromCMP(const Word &Arg1, const Word &Arg2,
- const uint8_t *Data, size_t Size);
- DictionaryEntry MakeDictionaryEntryFromCMP(const void *Arg1, const void *Arg2,
- const void *Arg1Mutation,
- const void *Arg2Mutation,
- size_t ArgSize,
- const uint8_t *Data, size_t Size);
-
- /// Applies one of the configured mutations.
- /// Returns the new size of data which could be up to MaxSize.
- size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize);
-
- /// Applies one of the configured mutations to the bytes of Data
- /// that have '1' in Mask.
- /// Mask.size() should be >= Size.
- size_t MutateWithMask(uint8_t *Data, size_t Size, size_t MaxSize,
- const Vector<uint8_t> &Mask);
-
- /// Applies one of the default mutations. Provided as a service
- /// to mutation authors.
- size_t DefaultMutate(uint8_t *Data, size_t Size, size_t MaxSize);
-
- /// Creates a cross-over of two pieces of Data, returns its size.
- size_t CrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2,
- size_t Size2, uint8_t *Out, size_t MaxOutSize);
-
- void AddWordToManualDictionary(const Word &W);
-
- // Creates a recommended dictionary and returns its number of entries. The
- // entries can be retrieved by subsequent calls to
- // |LLVMMutagenRecommendDictionaryEntry|.
- const Dictionary &RecommendDictionary();
-
- // Returns the ASCII representation of the next recommended dictionary entry,
- // and sets |OutUseCount| to its use count. The return pointer is valid until
- // the next call to this method.
- const char *RecommendDictionaryEntry(size_t *OutUseCount);
-
- void SetCrossOverWith(const Unit *U) { CrossOverWith = U; }
-
- Random &GetRand() { return Rand; }
-
-private:
- // Imports and validates the disptacher's configuration.
- void SetConfig(const LLVMMutagenConfiguration *Config);
-
- Random Rand;
- LLVMMutagenConfiguration Config;
-
- // Dictionary provided by the user via -dict=DICT_FILE.
- Dictionary ManualDictionary;
- // Persistent dictionary modified by the fuzzer, consists of
- // entries that led to successful discoveries in the past mutations.
- Dictionary PersistentAutoDictionary;
- // Recommended dictionary buolt by |RecommendDictionary|.
- Dictionary RecommendedDictionary;
- size_t NextRecommendedDictionaryEntry = 0;
- std::string DictionaryEntryWord;
-
- Sequence<DictionaryEntry *> CurrentDictionaryEntrySequence;
-
- static const size_t kCmpDictionaryEntriesDequeSize = 16;
- DictionaryEntry CmpDictionaryEntriesDeque[kCmpDictionaryEntriesDequeSize];
- size_t CmpDictionaryEntriesDequeIdx = 0;
-
- const Unit *CrossOverWith = nullptr;
- Vector<uint8_t> MutateInPlaceHere;
- Vector<uint8_t> MutateWithMaskTemp;
- // CustomCrossOver needs its own buffer as a custom implementation may call
- // LLVMFuzzerMutate, which in turn may resize MutateInPlaceHere.
- Vector<uint8_t> CustomCrossOverInPlaceHere;
-
- Vector<Mutator> Mutators;
- Vector<Mutator> DefaultMutators;
- Sequence<Mutator> CurrentMutatorSequence;
-};
-
-// Returns a pointer to the MutationDispatcher is use by MutagenInterface.
-// This should only be used for testing.
-MutationDispatcher *GetMutationDispatcherForTest();
-
-} // namespace mutagen
-
-#endif // LLVM_FUZZER_MUTAGEN_DISPATCHER_H
diff --git a/compiler-rt/lib/fuzzer/mutagen/MutagenSequence.h b/compiler-rt/lib/fuzzer/mutagen/MutagenSequence.h
deleted file mode 100644
index fd0ab2cb5f0f9..0000000000000
--- a/compiler-rt/lib/fuzzer/mutagen/MutagenSequence.h
+++ /dev/null
@@ -1,101 +0,0 @@
-//===- MutagenSequence.h - Internal header for the mutagen ------*- C++ -* ===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-// mutagen::Sequence
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_FUZZER_MUTAGEN_SEQUENCE_H
-#define LLVM_FUZZER_MUTAGEN_SEQUENCE_H
-
-#include "FuzzerDefs.h"
-#include <sstream>
-#include <string>
-
-namespace mutagen {
-namespace {
-
-using fuzzer::Vector;
-
-} // namespace
-
-// The Sequence type bundles together a list of items, a string representation,
-// and a position in that string suitable for truncating it when overly long,
-// e.g. after the tenth item.
-template <typename T> class Sequence {
-public:
- constexpr static size_t kMaxBriefItems = 10;
-
- void clear() {
- Items.clear();
- Size = 0;
- Str.clear();
- Brief = 0;
- }
-
- bool empty() const { return Size == 0; }
-
- size_t size() const { return Size; }
-
- void push_back(T t) { Items.push_back(t); }
-
- typename Vector<T>::const_iterator begin() const { return Items.begin(); }
- typename Vector<T>::iterator begin() { return Items.begin(); }
-
- typename Vector<T>::const_iterator end() const { return Items.end(); }
- typename Vector<T>::iterator end() { return Items.end(); }
-
- std::string GetString(bool Verbose = true) const {
- return Verbose ? Str : Str.substr(0, Brief);
- }
-
- // Constructs the string representation of the sequence, using a callback that
- // converts items to strings.
- template <typename ItemCallback>
- // std::string ItemCallback(T Item);
- void SetString(ItemCallback ConvertToASCII) {
- // No change since last call.
- if (Size == Items.size())
- return;
- Size = Items.size();
- std::ostringstream OSS;
- size_t i = 0;
- for (; i < Size && i < kMaxBriefItems; i++)
- OSS << ConvertToASCII(Items[i]) << "-";
- Brief = static_cast<size_t>(OSS.tellp());
- for (; i < Size; i++)
- OSS << ConvertToASCII(Items[i]) << "-";
- Str = OSS.str();
- }
-
-private:
- Vector<T> Items;
- size_t Size = 0;
- std::string Str;
- size_t Brief = 0;
-};
-
-template <typename T>
-typename Vector<T>::const_iterator begin(const Sequence<T> &S) {
- return S.begin();
-}
-
-template <typename T> typename Vector<T>::iterator begin(Sequence<T> &S) {
- return S.begin();
-}
-
-template <typename T>
-typename Vector<T>::const_iterator end(const Sequence<T> &S) {
- return S.end();
-}
-
-template <typename T> typename Vector<T>::iterator end(Sequence<T> &S) {
- return S.end();
-}
-
-} // namespace mutagen
-
-#endif // LLVM_FUZZER_MUTAGEN_SEQUENCE_H
diff --git a/compiler-rt/lib/fuzzer/mutagen/MutagenUtil.h b/compiler-rt/lib/fuzzer/mutagen/MutagenUtil.h
deleted file mode 100644
index cf3b78b9655af..0000000000000
--- a/compiler-rt/lib/fuzzer/mutagen/MutagenUtil.h
+++ /dev/null
@@ -1,24 +0,0 @@
-//===- MutagenUtil.h - Internal header for the mutagen Utils ----*- C++ -* ===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-// Util functions.
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_FUZZER_MUTAGEN_UTIL_H
-#define LLVM_FUZZER_MUTAGEN_UTIL_H
-
-#include <cstddef>
-#include <cstdint>
-
-namespace mutagen {
-
-const void *SearchMemory(const void *haystack, size_t haystacklen,
- const void *needle, size_t needlelen);
-
-} // namespace mutagen
-
-#endif // LLVM_FUZZER_MUTAGEN_UTIL_H
diff --git a/compiler-rt/lib/fuzzer/mutagen/MutagenUtilPosix.cpp b/compiler-rt/lib/fuzzer/mutagen/MutagenUtilPosix.cpp
deleted file mode 100644
index c157c6190c5d7..0000000000000
--- a/compiler-rt/lib/fuzzer/mutagen/MutagenUtilPosix.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-//===- MutagenUtilPosix.cpp - Misc utils for Posix. -----------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-// Misc utils implementation using Posix API.
-//===----------------------------------------------------------------------===//
-#include "FuzzerPlatform.h"
-#if (LIBFUZZER_POSIX || LIBFUZZER_FUCHSIA)
-#include <cstring>
-
-namespace mutagen {
-
-const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
- size_t PattLen) {
- return memmem(Data, DataLen, Patt, PattLen);
-}
-
-} // namespace mutagen
-
-#endif // (LIBFUZZER_POSIX || LIBFUZZER_FUCHSIA)
diff --git a/compiler-rt/lib/fuzzer/mutagen/MutagenUtilWindows.cpp b/compiler-rt/lib/fuzzer/mutagen/MutagenUtilWindows.cpp
deleted file mode 100644
index 93b86556b1393..0000000000000
--- a/compiler-rt/lib/fuzzer/mutagen/MutagenUtilWindows.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-//===- MutagenUtilWindows.cpp - Misc utils for Windows. -------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-// Misc utils implementation for Windows.
-//===----------------------------------------------------------------------===//
-#include "FuzzerPlatform.h"
-#if LIBFUZZER_WINDOWS
-#include <cstddef>
-#include <cstdio>
-#include <cstring>
-
-namespace mutagen {
-
-const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
- size_t PattLen) {
- // TODO: make this implementation more efficient.
- const char *Cdata = (const char *)Data;
- const char *Cpatt = (const char *)Patt;
-
- if (!Data || !Patt || DataLen == 0 || PattLen == 0 || DataLen < PattLen)
- return NULL;
-
- if (PattLen == 1)
- return memchr(Data, *Cpatt, DataLen);
-
- const char *End = Cdata + DataLen - PattLen + 1;
-
- for (const char *It = Cdata; It < End; ++It)
- if (It[0] == Cpatt[0] && memcmp(It, Cpatt, PattLen) == 0)
- return It;
-
- return NULL;
-}
-
-} // namespace mutagen
-
-#endif // LIBFUZZER_WINDOWS
diff --git a/compiler-rt/lib/fuzzer/mutagen/build.sh b/compiler-rt/lib/fuzzer/mutagen/build.sh
deleted file mode 100755
index 19c22b8fc5562..0000000000000
--- a/compiler-rt/lib/fuzzer/mutagen/build.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/sh
-LIBMUTAGEN_SRC_DIR=$(dirname $0)
-LIBFUZZER_SRC_DIR=$LIBMUTAGEN_SRC_DIR/..
-CXX="${CXX:-clang}"
-for f in $LIBMUTAGEN_SRC_DIR/*.cpp; do
- $CXX -g -O2 -fno-omit-frame-pointer -std=c++11 $f -c -I$LIBFUZZER_SRC_DIR &
-done
-wait
-rm -f libMutagen.a
-ar ru libMutagen.a Mutagen*.o
-rm -f Mutagen*.o
-
diff --git a/compiler-rt/lib/fuzzer/tests/CMakeLists.txt b/compiler-rt/lib/fuzzer/tests/CMakeLists.txt
index 974efc3c5b630..5b3e906419546 100644
--- a/compiler-rt/lib/fuzzer/tests/CMakeLists.txt
+++ b/compiler-rt/lib/fuzzer/tests/CMakeLists.txt
@@ -17,9 +17,6 @@ set_target_properties(FuzzerUnitTests PROPERTIES FOLDER "Compiler-RT Tests")
add_custom_target(FuzzedDataProviderUnitTests)
set_target_properties(FuzzedDataProviderUnitTests PROPERTIES FOLDER "Compiler-RT Tests")
-add_custom_target(MutagenUnitTests)
-set_target_properties(MutagenUnitTests PROPERTIES FOLDER "Compiler-RT Tests")
-
set(LIBFUZZER_UNITTEST_LINK_FLAGS ${COMPILER_RT_UNITTEST_LINK_FLAGS})
list(APPEND LIBFUZZER_UNITTEST_LINK_FLAGS --driver-mode=g++)
@@ -49,35 +46,23 @@ if(COMPILER_RT_DEFAULT_TARGET_ARCH IN_LIST FUZZER_SUPPORTED_ARCH)
set(arch ${COMPILER_RT_DEFAULT_TARGET_ARCH})
set(LIBFUZZER_TEST_RUNTIME RTFuzzerTest.${arch})
- set(LIBMUTAGEN_TEST_RUNTIME RTMutagenTest.${arch})
if(APPLE)
set(LIBFUZZER_TEST_RUNTIME_OBJECTS
$<TARGET_OBJECTS:RTfuzzer.osx>)
- set(LIBMUTAGEN_TEST_RUNTIME_OBJECTS
- $<TARGET_OBJECTS:RTmutagen.osx>)
else()
set(LIBFUZZER_TEST_RUNTIME_OBJECTS
$<TARGET_OBJECTS:RTfuzzer.${arch}>)
- set(LIBMUTAGEN_TEST_RUNTIME_OBJECTS
- $<TARGET_OBJECTS:RTmutagen.${arch}>)
endif()
add_library(${LIBFUZZER_TEST_RUNTIME} STATIC
- ${LIBFUZZER_TEST_RUNTIME_OBJECTS}
- ${LIBMUTAGEN_TEST_RUNTIME_OBJECTS})
+ ${LIBFUZZER_TEST_RUNTIME_OBJECTS})
set_target_properties(${LIBFUZZER_TEST_RUNTIME} PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
FOLDER "Compiler-RT Runtime tests")
- add_library(${LIBMUTAGEN_TEST_RUNTIME} STATIC
- ${LIBMUTAGEN_TEST_RUNTIME_OBJECTS})
- set_target_properties(${LIBMUTAGEN_TEST_RUNTIME} PROPERTIES
- ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
- FOLDER "Compiler-RT Runtime tests")
-
if(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND
COMPILER_RT_LIBCXX_PATH AND
COMPILER_RT_LIBCXXABI_PATH)
- file(GLOB libfuzzer_headers ../*.h ../mutagen/*.h)
+ file(GLOB libfuzzer_headers ../*.h)
set(LIBFUZZER_TEST_RUNTIME_DEPS libcxx_fuzzer_${arch}-build ${libfuzzer_headers})
set(LIBFUZZER_TEST_RUNTIME_CFLAGS -isystem ${LIBCXX_${arch}_PREFIX}/include/c++/v1)
set(LIBFUZZER_TEST_RUNTIME_LINK_FLAGS ${LIBCXX_${arch}_PREFIX}/lib/libc++.a)
@@ -88,7 +73,7 @@ if(COMPILER_RT_DEFAULT_TARGET_ARCH IN_LIST FUZZER_SUPPORTED_ARCH)
FuzzerUnitTests "Fuzzer-${arch}-Test" ${arch}
SOURCES FuzzerUnittest.cpp ${COMPILER_RT_GTEST_SOURCE}
RUNTIME ${LIBFUZZER_TEST_RUNTIME}
- DEPS gtest ${LIBFUZZER_TEST_RUNTIME_DEPS}
+ DEPS gtest ${LIBFUZZER_TEST_RUNTIME_DEPS}
CFLAGS ${LIBFUZZER_UNITTEST_CFLAGS} ${LIBFUZZER_TEST_RUNTIME_CFLAGS}
LINK_FLAGS ${LIBFUZZER_UNITTEST_LINK_FLAGS} ${LIBFUZZER_TEST_RUNTIME_LINK_FLAGS})
set_target_properties(FuzzerUnitTests PROPERTIES
@@ -103,15 +88,4 @@ if(COMPILER_RT_DEFAULT_TARGET_ARCH IN_LIST FUZZER_SUPPORTED_ARCH)
LINK_FLAGS ${LIBFUZZER_UNITTEST_LINK_FLAGS} ${LIBFUZZER_TEST_RUNTIME_LINK_FLAGS})
set_target_properties(FuzzedDataProviderUnitTests PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
-
- set(MutagenTestObjects)
- generate_compiler_rt_tests(MutagenTestObjects
- MutagenUnitTests "Mutagen-${arch}-Test" ${arch}
- SOURCES MutagenUnittest.cpp ${COMPILER_RT_GTEST_SOURCE}
- RUNTIME ${LIBFUZZER_TEST_RUNTIME}
- DEPS gtest ${LIBFUZZER_TEST_RUNTIME_DEPS} ${LIBMUTAGEN_TEST_RUNTIME_DEPS}
- CFLAGS ${LIBFUZZER_UNITTEST_CFLAGS} ${LIBFUZZER_TEST_RUNTIME_CFLAGS}
- LINK_FLAGS ${LIBFUZZER_UNITTEST_LINK_FLAGS} ${LIBFUZZER_TEST_RUNTIME_LINK_FLAGS})
- set_target_properties(MutagenUnitTests PROPERTIES
- RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
endif()
diff --git a/compiler-rt/lib/fuzzer/tests/FuzzerUnittest.cpp b/compiler-rt/lib/fuzzer/tests/FuzzerUnittest.cpp
index 277fa5e6183f8..974a01ff4ab6e 100644
--- a/compiler-rt/lib/fuzzer/tests/FuzzerUnittest.cpp
+++ b/compiler-rt/lib/fuzzer/tests/FuzzerUnittest.cpp
@@ -10,6 +10,7 @@
#define GTEST_NO_LLVM_SUPPORT 1
#include "FuzzerCorpus.h"
+#include "FuzzerDictionary.h"
#include "FuzzerInternal.h"
#include "FuzzerMerge.h"
#include "FuzzerMutate.h"
@@ -43,6 +44,65 @@ TEST(Fuzzer, Basename) {
#endif
}
+TEST(Fuzzer, CrossOver) {
+ std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
+ fuzzer::EF = t.get();
+ Random Rand(0);
+ std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
+ Unit A({0, 1, 2}), B({5, 6, 7});
+ Unit C;
+ Unit Expected[] = {
+ { 0 },
+ { 0, 1 },
+ { 0, 5 },
+ { 0, 1, 2 },
+ { 0, 1, 5 },
+ { 0, 5, 1 },
+ { 0, 5, 6 },
+ { 0, 1, 2, 5 },
+ { 0, 1, 5, 2 },
+ { 0, 1, 5, 6 },
+ { 0, 5, 1, 2 },
+ { 0, 5, 1, 6 },
+ { 0, 5, 6, 1 },
+ { 0, 5, 6, 7 },
+ { 0, 1, 2, 5, 6 },
+ { 0, 1, 5, 2, 6 },
+ { 0, 1, 5, 6, 2 },
+ { 0, 1, 5, 6, 7 },
+ { 0, 5, 1, 2, 6 },
+ { 0, 5, 1, 6, 2 },
+ { 0, 5, 1, 6, 7 },
+ { 0, 5, 6, 1, 2 },
+ { 0, 5, 6, 1, 7 },
+ { 0, 5, 6, 7, 1 },
+ { 0, 1, 2, 5, 6, 7 },
+ { 0, 1, 5, 2, 6, 7 },
+ { 0, 1, 5, 6, 2, 7 },
+ { 0, 1, 5, 6, 7, 2 },
+ { 0, 5, 1, 2, 6, 7 },
+ { 0, 5, 1, 6, 2, 7 },
+ { 0, 5, 1, 6, 7, 2 },
+ { 0, 5, 6, 1, 2, 7 },
+ { 0, 5, 6, 1, 7, 2 },
+ { 0, 5, 6, 7, 1, 2 }
+ };
+ for (size_t Len = 1; Len < 8; Len++) {
+ Set<Unit> FoundUnits, ExpectedUnitsWitThisLength;
+ for (int Iter = 0; Iter < 3000; Iter++) {
+ C.resize(Len);
+ size_t NewSize = MD->CrossOver(A.data(), A.size(), B.data(), B.size(),
+ C.data(), C.size());
+ C.resize(NewSize);
+ FoundUnits.insert(C);
+ }
+ for (const Unit &U : Expected)
+ if (U.size() <= Len)
+ ExpectedUnitsWitThisLength.insert(U);
+ EXPECT_EQ(ExpectedUnitsWitThisLength, FoundUnits);
+ }
+}
+
TEST(Fuzzer, Hash) {
uint8_t A[] = {'a', 'b', 'c'};
fuzzer::Unit U(A, A + sizeof(A));
@@ -51,6 +111,423 @@ TEST(Fuzzer, Hash) {
EXPECT_EQ("81fe8bfe87576c3ecb22426f8e57847382917acf", fuzzer::Hash(U));
}
+typedef size_t (MutationDispatcher::*Mutator)(uint8_t *Data, size_t Size,
+ size_t MaxSize);
+
+void TestEraseBytes(Mutator M, int NumIter) {
+ std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
+ fuzzer::EF = t.get();
+ uint8_t REM0[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+ uint8_t REM1[8] = {0x00, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+ uint8_t REM2[8] = {0x00, 0x11, 0x33, 0x44, 0x55, 0x66, 0x77};
+ uint8_t REM3[8] = {0x00, 0x11, 0x22, 0x44, 0x55, 0x66, 0x77};
+ uint8_t REM4[8] = {0x00, 0x11, 0x22, 0x33, 0x55, 0x66, 0x77};
+ uint8_t REM5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x66, 0x77};
+ uint8_t REM6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x77};
+ uint8_t REM7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+
+ uint8_t REM8[6] = {0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+ uint8_t REM9[6] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55};
+ uint8_t REM10[6] = {0x00, 0x11, 0x22, 0x55, 0x66, 0x77};
+
+ uint8_t REM11[5] = {0x33, 0x44, 0x55, 0x66, 0x77};
+ uint8_t REM12[5] = {0x00, 0x11, 0x22, 0x33, 0x44};
+ uint8_t REM13[5] = {0x00, 0x44, 0x55, 0x66, 0x77};
+
+
+ Random Rand(0);
+ std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
+ int FoundMask = 0;
+ for (int i = 0; i < NumIter; i++) {
+ uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+ size_t NewSize = (*MD.*M)(T, sizeof(T), sizeof(T));
+ if (NewSize == 7 && !memcmp(REM0, T, 7)) FoundMask |= 1 << 0;
+ if (NewSize == 7 && !memcmp(REM1, T, 7)) FoundMask |= 1 << 1;
+ if (NewSize == 7 && !memcmp(REM2, T, 7)) FoundMask |= 1 << 2;
+ if (NewSize == 7 && !memcmp(REM3, T, 7)) FoundMask |= 1 << 3;
+ if (NewSize == 7 && !memcmp(REM4, T, 7)) FoundMask |= 1 << 4;
+ if (NewSize == 7 && !memcmp(REM5, T, 7)) FoundMask |= 1 << 5;
+ if (NewSize == 7 && !memcmp(REM6, T, 7)) FoundMask |= 1 << 6;
+ if (NewSize == 7 && !memcmp(REM7, T, 7)) FoundMask |= 1 << 7;
+
+ if (NewSize == 6 && !memcmp(REM8, T, 6)) FoundMask |= 1 << 8;
+ if (NewSize == 6 && !memcmp(REM9, T, 6)) FoundMask |= 1 << 9;
+ if (NewSize == 6 && !memcmp(REM10, T, 6)) FoundMask |= 1 << 10;
+
+ if (NewSize == 5 && !memcmp(REM11, T, 5)) FoundMask |= 1 << 11;
+ if (NewSize == 5 && !memcmp(REM12, T, 5)) FoundMask |= 1 << 12;
+ if (NewSize == 5 && !memcmp(REM13, T, 5)) FoundMask |= 1 << 13;
+ }
+ EXPECT_EQ(FoundMask, (1 << 14) - 1);
+}
+
+TEST(FuzzerMutate, EraseBytes1) {
+ TestEraseBytes(&MutationDispatcher::Mutate_EraseBytes, 200);
+}
+TEST(FuzzerMutate, EraseBytes2) {
+ TestEraseBytes(&MutationDispatcher::Mutate, 2000);
+}
+
+void TestInsertByte(Mutator M, int NumIter) {
+ std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
+ fuzzer::EF = t.get();
+ Random Rand(0);
+ std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
+ int FoundMask = 0;
+ uint8_t INS0[8] = {0xF1, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+ uint8_t INS1[8] = {0x00, 0xF2, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+ uint8_t INS2[8] = {0x00, 0x11, 0xF3, 0x22, 0x33, 0x44, 0x55, 0x66};
+ uint8_t INS3[8] = {0x00, 0x11, 0x22, 0xF4, 0x33, 0x44, 0x55, 0x66};
+ uint8_t INS4[8] = {0x00, 0x11, 0x22, 0x33, 0xF5, 0x44, 0x55, 0x66};
+ uint8_t INS5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0xF6, 0x55, 0x66};
+ uint8_t INS6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0xF7, 0x66};
+ uint8_t INS7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xF8};
+ for (int i = 0; i < NumIter; i++) {
+ uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+ size_t NewSize = (*MD.*M)(T, 7, 8);
+ if (NewSize == 8 && !memcmp(INS0, T, 8)) FoundMask |= 1 << 0;
+ if (NewSize == 8 && !memcmp(INS1, T, 8)) FoundMask |= 1 << 1;
+ if (NewSize == 8 && !memcmp(INS2, T, 8)) FoundMask |= 1 << 2;
+ if (NewSize == 8 && !memcmp(INS3, T, 8)) FoundMask |= 1 << 3;
+ if (NewSize == 8 && !memcmp(INS4, T, 8)) FoundMask |= 1 << 4;
+ if (NewSize == 8 && !memcmp(INS5, T, 8)) FoundMask |= 1 << 5;
+ if (NewSize == 8 && !memcmp(INS6, T, 8)) FoundMask |= 1 << 6;
+ if (NewSize == 8 && !memcmp(INS7, T, 8)) FoundMask |= 1 << 7;
+ }
+ EXPECT_EQ(FoundMask, 255);
+}
+
+TEST(FuzzerMutate, InsertByte1) {
+ TestInsertByte(&MutationDispatcher::Mutate_InsertByte, 1 << 15);
+}
+TEST(FuzzerMutate, InsertByte2) {
+ TestInsertByte(&MutationDispatcher::Mutate, 1 << 17);
+}
+
+void TestInsertRepeatedBytes(Mutator M, int NumIter) {
+ std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
+ fuzzer::EF = t.get();
+ Random Rand(0);
+ std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
+ int FoundMask = 0;
+ uint8_t INS0[7] = {0x00, 0x11, 0x22, 0x33, 'a', 'a', 'a'};
+ uint8_t INS1[7] = {0x00, 0x11, 0x22, 'a', 'a', 'a', 0x33};
+ uint8_t INS2[7] = {0x00, 0x11, 'a', 'a', 'a', 0x22, 0x33};
+ uint8_t INS3[7] = {0x00, 'a', 'a', 'a', 0x11, 0x22, 0x33};
+ uint8_t INS4[7] = {'a', 'a', 'a', 0x00, 0x11, 0x22, 0x33};
+
+ uint8_t INS5[8] = {0x00, 0x11, 0x22, 0x33, 'b', 'b', 'b', 'b'};
+ uint8_t INS6[8] = {0x00, 0x11, 0x22, 'b', 'b', 'b', 'b', 0x33};
+ uint8_t INS7[8] = {0x00, 0x11, 'b', 'b', 'b', 'b', 0x22, 0x33};
+ uint8_t INS8[8] = {0x00, 'b', 'b', 'b', 'b', 0x11, 0x22, 0x33};
+ uint8_t INS9[8] = {'b', 'b', 'b', 'b', 0x00, 0x11, 0x22, 0x33};
+
+ for (int i = 0; i < NumIter; i++) {
+ uint8_t T[8] = {0x00, 0x11, 0x22, 0x33};
+ size_t NewSize = (*MD.*M)(T, 4, 8);
+ if (NewSize == 7 && !memcmp(INS0, T, 7)) FoundMask |= 1 << 0;
+ if (NewSize == 7 && !memcmp(INS1, T, 7)) FoundMask |= 1 << 1;
+ if (NewSize == 7 && !memcmp(INS2, T, 7)) FoundMask |= 1 << 2;
+ if (NewSize == 7 && !memcmp(INS3, T, 7)) FoundMask |= 1 << 3;
+ if (NewSize == 7 && !memcmp(INS4, T, 7)) FoundMask |= 1 << 4;
+
+ if (NewSize == 8 && !memcmp(INS5, T, 8)) FoundMask |= 1 << 5;
+ if (NewSize == 8 && !memcmp(INS6, T, 8)) FoundMask |= 1 << 6;
+ if (NewSize == 8 && !memcmp(INS7, T, 8)) FoundMask |= 1 << 7;
+ if (NewSize == 8 && !memcmp(INS8, T, 8)) FoundMask |= 1 << 8;
+ if (NewSize == 8 && !memcmp(INS9, T, 8)) FoundMask |= 1 << 9;
+
+ }
+ EXPECT_EQ(FoundMask, (1 << 10) - 1);
+}
+
+TEST(FuzzerMutate, InsertRepeatedBytes1) {
+ TestInsertRepeatedBytes(&MutationDispatcher::Mutate_InsertRepeatedBytes, 10000);
+}
+TEST(FuzzerMutate, InsertRepeatedBytes2) {
+ TestInsertRepeatedBytes(&MutationDispatcher::Mutate, 300000);
+}
+
+void TestChangeByte(Mutator M, int NumIter) {
+ std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
+ fuzzer::EF = t.get();
+ Random Rand(0);
+ std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
+ int FoundMask = 0;
+ uint8_t CH0[8] = {0xF0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+ uint8_t CH1[8] = {0x00, 0xF1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+ uint8_t CH2[8] = {0x00, 0x11, 0xF2, 0x33, 0x44, 0x55, 0x66, 0x77};
+ uint8_t CH3[8] = {0x00, 0x11, 0x22, 0xF3, 0x44, 0x55, 0x66, 0x77};
+ uint8_t CH4[8] = {0x00, 0x11, 0x22, 0x33, 0xF4, 0x55, 0x66, 0x77};
+ uint8_t CH5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0xF5, 0x66, 0x77};
+ uint8_t CH6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0xF5, 0x77};
+ uint8_t CH7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xF7};
+ for (int i = 0; i < NumIter; i++) {
+ uint8_t T[9] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+ size_t NewSize = (*MD.*M)(T, 8, 9);
+ if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0;
+ if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1;
+ if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2;
+ if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3;
+ if (NewSize == 8 && !memcmp(CH4, T, 8)) FoundMask |= 1 << 4;
+ if (NewSize == 8 && !memcmp(CH5, T, 8)) FoundMask |= 1 << 5;
+ if (NewSize == 8 && !memcmp(CH6, T, 8)) FoundMask |= 1 << 6;
+ if (NewSize == 8 && !memcmp(CH7, T, 8)) FoundMask |= 1 << 7;
+ }
+ EXPECT_EQ(FoundMask, 255);
+}
+
+TEST(FuzzerMutate, ChangeByte1) {
+ TestChangeByte(&MutationDispatcher::Mutate_ChangeByte, 1 << 15);
+}
+TEST(FuzzerMutate, ChangeByte2) {
+ TestChangeByte(&MutationDispatcher::Mutate, 1 << 17);
+}
+
+void TestChangeBit(Mutator M, int NumIter) {
+ std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
+ fuzzer::EF = t.get();
+ Random Rand(0);
+ std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
+ int FoundMask = 0;
+ uint8_t CH0[8] = {0x01, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+ uint8_t CH1[8] = {0x00, 0x13, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+ uint8_t CH2[8] = {0x00, 0x11, 0x02, 0x33, 0x44, 0x55, 0x66, 0x77};
+ uint8_t CH3[8] = {0x00, 0x11, 0x22, 0x37, 0x44, 0x55, 0x66, 0x77};
+ uint8_t CH4[8] = {0x00, 0x11, 0x22, 0x33, 0x54, 0x55, 0x66, 0x77};
+ uint8_t CH5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x54, 0x66, 0x77};
+ uint8_t CH6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x76, 0x77};
+ uint8_t CH7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xF7};
+ for (int i = 0; i < NumIter; i++) {
+ uint8_t T[9] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+ size_t NewSize = (*MD.*M)(T, 8, 9);
+ if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0;
+ if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1;
+ if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2;
+ if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3;
+ if (NewSize == 8 && !memcmp(CH4, T, 8)) FoundMask |= 1 << 4;
+ if (NewSize == 8 && !memcmp(CH5, T, 8)) FoundMask |= 1 << 5;
+ if (NewSize == 8 && !memcmp(CH6, T, 8)) FoundMask |= 1 << 6;
+ if (NewSize == 8 && !memcmp(CH7, T, 8)) FoundMask |= 1 << 7;
+ }
+ EXPECT_EQ(FoundMask, 255);
+}
+
+TEST(FuzzerMutate, ChangeBit1) {
+ TestChangeBit(&MutationDispatcher::Mutate_ChangeBit, 1 << 16);
+}
+TEST(FuzzerMutate, ChangeBit2) {
+ TestChangeBit(&MutationDispatcher::Mutate, 1 << 18);
+}
+
+void TestShuffleBytes(Mutator M, int NumIter) {
+ std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
+ fuzzer::EF = t.get();
+ Random Rand(0);
+ std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
+ int FoundMask = 0;
+ uint8_t CH0[7] = {0x00, 0x22, 0x11, 0x33, 0x44, 0x55, 0x66};
+ uint8_t CH1[7] = {0x11, 0x00, 0x33, 0x22, 0x44, 0x55, 0x66};
+ uint8_t CH2[7] = {0x00, 0x33, 0x11, 0x22, 0x44, 0x55, 0x66};
+ uint8_t CH3[7] = {0x00, 0x11, 0x22, 0x44, 0x55, 0x66, 0x33};
+ uint8_t CH4[7] = {0x00, 0x11, 0x22, 0x33, 0x55, 0x44, 0x66};
+ for (int i = 0; i < NumIter; i++) {
+ uint8_t T[7] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+ size_t NewSize = (*MD.*M)(T, 7, 7);
+ if (NewSize == 7 && !memcmp(CH0, T, 7)) FoundMask |= 1 << 0;
+ if (NewSize == 7 && !memcmp(CH1, T, 7)) FoundMask |= 1 << 1;
+ if (NewSize == 7 && !memcmp(CH2, T, 7)) FoundMask |= 1 << 2;
+ if (NewSize == 7 && !memcmp(CH3, T, 7)) FoundMask |= 1 << 3;
+ if (NewSize == 7 && !memcmp(CH4, T, 7)) FoundMask |= 1 << 4;
+ }
+ EXPECT_EQ(FoundMask, 31);
+}
+
+TEST(FuzzerMutate, ShuffleBytes1) {
+ TestShuffleBytes(&MutationDispatcher::Mutate_ShuffleBytes, 1 << 17);
+}
+TEST(FuzzerMutate, ShuffleBytes2) {
+ TestShuffleBytes(&MutationDispatcher::Mutate, 1 << 20);
+}
+
+void TestCopyPart(Mutator M, int NumIter) {
+ std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
+ fuzzer::EF = t.get();
+ Random Rand(0);
+ std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
+ int FoundMask = 0;
+ uint8_t CH0[7] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x11};
+ uint8_t CH1[7] = {0x55, 0x66, 0x22, 0x33, 0x44, 0x55, 0x66};
+ uint8_t CH2[7] = {0x00, 0x55, 0x66, 0x33, 0x44, 0x55, 0x66};
+ uint8_t CH3[7] = {0x00, 0x11, 0x22, 0x00, 0x11, 0x22, 0x66};
+ uint8_t CH4[7] = {0x00, 0x11, 0x11, 0x22, 0x33, 0x55, 0x66};
+
+ for (int i = 0; i < NumIter; i++) {
+ uint8_t T[7] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+ size_t NewSize = (*MD.*M)(T, 7, 7);
+ if (NewSize == 7 && !memcmp(CH0, T, 7)) FoundMask |= 1 << 0;
+ if (NewSize == 7 && !memcmp(CH1, T, 7)) FoundMask |= 1 << 1;
+ if (NewSize == 7 && !memcmp(CH2, T, 7)) FoundMask |= 1 << 2;
+ if (NewSize == 7 && !memcmp(CH3, T, 7)) FoundMask |= 1 << 3;
+ if (NewSize == 7 && !memcmp(CH4, T, 7)) FoundMask |= 1 << 4;
+ }
+
+ uint8_t CH5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x11, 0x22};
+ uint8_t CH6[8] = {0x22, 0x33, 0x44, 0x00, 0x11, 0x22, 0x33, 0x44};
+ uint8_t CH7[8] = {0x00, 0x11, 0x22, 0x00, 0x11, 0x22, 0x33, 0x44};
+ uint8_t CH8[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x22, 0x33, 0x44};
+ uint8_t CH9[8] = {0x00, 0x11, 0x22, 0x22, 0x33, 0x44, 0x33, 0x44};
+
+ for (int i = 0; i < NumIter; i++) {
+ uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+ size_t NewSize = (*MD.*M)(T, 5, 8);
+ if (NewSize == 8 && !memcmp(CH5, T, 8)) FoundMask |= 1 << 5;
+ if (NewSize == 8 && !memcmp(CH6, T, 8)) FoundMask |= 1 << 6;
+ if (NewSize == 8 && !memcmp(CH7, T, 8)) FoundMask |= 1 << 7;
+ if (NewSize == 8 && !memcmp(CH8, T, 8)) FoundMask |= 1 << 8;
+ if (NewSize == 8 && !memcmp(CH9, T, 8)) FoundMask |= 1 << 9;
+ }
+
+ EXPECT_EQ(FoundMask, 1023);
+}
+
+TEST(FuzzerMutate, CopyPart1) {
+ TestCopyPart(&MutationDispatcher::Mutate_CopyPart, 1 << 10);
+}
+TEST(FuzzerMutate, CopyPart2) {
+ TestCopyPart(&MutationDispatcher::Mutate, 1 << 13);
+}
+TEST(FuzzerMutate, CopyPartNoInsertAtMaxSize) {
+ // This (non exhaustively) tests if `Mutate_CopyPart` tries to perform an
+ // insert on an input of size `MaxSize`. Performing an insert in this case
+ // will lead to the mutation failing.
+ std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
+ fuzzer::EF = t.get();
+ Random Rand(0);
+ std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
+ uint8_t Data[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x11, 0x22};
+ size_t MaxSize = sizeof(Data);
+ for (int count = 0; count < (1 << 18); ++count) {
+ size_t NewSize = MD->Mutate_CopyPart(Data, MaxSize, MaxSize);
+ ASSERT_EQ(NewSize, MaxSize);
+ }
+}
+
+void TestAddWordFromDictionary(Mutator M, int NumIter) {
+ std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
+ fuzzer::EF = t.get();
+ Random Rand(0);
+ std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
+ uint8_t Word1[4] = {0xAA, 0xBB, 0xCC, 0xDD};
+ uint8_t Word2[3] = {0xFF, 0xEE, 0xEF};
+ MD->AddWordToManualDictionary(Word(Word1, sizeof(Word1)));
+ MD->AddWordToManualDictionary(Word(Word2, sizeof(Word2)));
+ int FoundMask = 0;
+ uint8_t CH0[7] = {0x00, 0x11, 0x22, 0xAA, 0xBB, 0xCC, 0xDD};
+ uint8_t CH1[7] = {0x00, 0x11, 0xAA, 0xBB, 0xCC, 0xDD, 0x22};
+ uint8_t CH2[7] = {0x00, 0xAA, 0xBB, 0xCC, 0xDD, 0x11, 0x22};
+ uint8_t CH3[7] = {0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0x11, 0x22};
+ uint8_t CH4[6] = {0x00, 0x11, 0x22, 0xFF, 0xEE, 0xEF};
+ uint8_t CH5[6] = {0x00, 0x11, 0xFF, 0xEE, 0xEF, 0x22};
+ uint8_t CH6[6] = {0x00, 0xFF, 0xEE, 0xEF, 0x11, 0x22};
+ uint8_t CH7[6] = {0xFF, 0xEE, 0xEF, 0x00, 0x11, 0x22};
+ for (int i = 0; i < NumIter; i++) {
+ uint8_t T[7] = {0x00, 0x11, 0x22};
+ size_t NewSize = (*MD.*M)(T, 3, 7);
+ if (NewSize == 7 && !memcmp(CH0, T, 7)) FoundMask |= 1 << 0;
+ if (NewSize == 7 && !memcmp(CH1, T, 7)) FoundMask |= 1 << 1;
+ if (NewSize == 7 && !memcmp(CH2, T, 7)) FoundMask |= 1 << 2;
+ if (NewSize == 7 && !memcmp(CH3, T, 7)) FoundMask |= 1 << 3;
+ if (NewSize == 6 && !memcmp(CH4, T, 6)) FoundMask |= 1 << 4;
+ if (NewSize == 6 && !memcmp(CH5, T, 6)) FoundMask |= 1 << 5;
+ if (NewSize == 6 && !memcmp(CH6, T, 6)) FoundMask |= 1 << 6;
+ if (NewSize == 6 && !memcmp(CH7, T, 6)) FoundMask |= 1 << 7;
+ }
+ EXPECT_EQ(FoundMask, 255);
+}
+
+TEST(FuzzerMutate, AddWordFromDictionary1) {
+ TestAddWordFromDictionary(
+ &MutationDispatcher::Mutate_AddWordFromManualDictionary, 1 << 15);
+}
+
+TEST(FuzzerMutate, AddWordFromDictionary2) {
+ TestAddWordFromDictionary(&MutationDispatcher::Mutate, 1 << 15);
+}
+
+void TestChangeASCIIInteger(Mutator M, int NumIter) {
+ std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
+ fuzzer::EF = t.get();
+ Random Rand(0);
+ std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
+
+ uint8_t CH0[8] = {'1', '2', '3', '4', '5', '6', '7', '7'};
+ uint8_t CH1[8] = {'1', '2', '3', '4', '5', '6', '7', '9'};
+ uint8_t CH2[8] = {'2', '4', '6', '9', '1', '3', '5', '6'};
+ uint8_t CH3[8] = {'0', '6', '1', '7', '2', '8', '3', '9'};
+ int FoundMask = 0;
+ for (int i = 0; i < NumIter; i++) {
+ uint8_t T[8] = {'1', '2', '3', '4', '5', '6', '7', '8'};
+ size_t NewSize = (*MD.*M)(T, 8, 8);
+ /**/ if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0;
+ else if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1;
+ else if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2;
+ else if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3;
+ else if (NewSize == 8) FoundMask |= 1 << 4;
+ }
+ EXPECT_EQ(FoundMask, 31);
+}
+
+TEST(FuzzerMutate, ChangeASCIIInteger1) {
+ TestChangeASCIIInteger(&MutationDispatcher::Mutate_ChangeASCIIInteger,
+ 1 << 15);
+}
+
+TEST(FuzzerMutate, ChangeASCIIInteger2) {
+ TestChangeASCIIInteger(&MutationDispatcher::Mutate, 1 << 15);
+}
+
+void TestChangeBinaryInteger(Mutator M, int NumIter) {
+ std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
+ fuzzer::EF = t.get();
+ Random Rand(0);
+ std::unique_ptr<MutationDispatcher> MD(new MutationDispatcher(Rand, {}));
+
+ uint8_t CH0[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x79};
+ uint8_t CH1[8] = {0x00, 0x11, 0x22, 0x31, 0x44, 0x55, 0x66, 0x77};
+ uint8_t CH2[8] = {0xff, 0x10, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+ uint8_t CH3[8] = {0x00, 0x11, 0x2a, 0x33, 0x44, 0x55, 0x66, 0x77};
+ uint8_t CH4[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x4f, 0x66, 0x77};
+ uint8_t CH5[8] = {0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88};
+ uint8_t CH6[8] = {0x00, 0x11, 0x22, 0x00, 0x00, 0x00, 0x08, 0x77}; // Size
+ uint8_t CH7[8] = {0x00, 0x08, 0x00, 0x33, 0x44, 0x55, 0x66, 0x77}; // Sw(Size)
+
+ int FoundMask = 0;
+ for (int i = 0; i < NumIter; i++) {
+ uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+ size_t NewSize = (*MD.*M)(T, 8, 8);
+ /**/ if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0;
+ else if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1;
+ else if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2;
+ else if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3;
+ else if (NewSize == 8 && !memcmp(CH4, T, 8)) FoundMask |= 1 << 4;
+ else if (NewSize == 8 && !memcmp(CH5, T, 8)) FoundMask |= 1 << 5;
+ else if (NewSize == 8 && !memcmp(CH6, T, 8)) FoundMask |= 1 << 6;
+ else if (NewSize == 8 && !memcmp(CH7, T, 8)) FoundMask |= 1 << 7;
+ }
+ EXPECT_EQ(FoundMask, 255);
+}
+
+TEST(FuzzerMutate, ChangeBinaryInteger1) {
+ TestChangeBinaryInteger(&MutationDispatcher::Mutate_ChangeBinaryInteger,
+ 1 << 12);
+}
+
+TEST(FuzzerMutate, ChangeBinaryInteger2) {
+ TestChangeBinaryInteger(&MutationDispatcher::Mutate, 1 << 15);
+}
+
+
TEST(FuzzerDictionary, ParseOneDictionaryEntry) {
Unit U;
EXPECT_FALSE(ParseOneDictionaryEntry("", &U));
diff --git a/compiler-rt/lib/fuzzer/tests/MutagenUnittest.cpp b/compiler-rt/lib/fuzzer/tests/MutagenUnittest.cpp
deleted file mode 100644
index 287eecf5fe2c8..0000000000000
--- a/compiler-rt/lib/fuzzer/tests/MutagenUnittest.cpp
+++ /dev/null
@@ -1,971 +0,0 @@
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-#include "mutagen/Mutagen.h"
-#include "mutagen/MutagenDispatcher.h"
-#include "mutagen/MutagenSequence.h"
-#include "mutagen/MutagenUtil.h"
-#include "gtest/gtest.h"
-#include <chrono>
-
-// This test doesn't set Config.MsanUnpoison*, so ensure MSan isn't present.
-// Avoid using fuzzer::ExternalFunctions, since it may not be linked against
-// the test binary.
-#if defined(__has_feature)
-#if __has_feature(memory_sanitizer)
-#error MemorySanitizer is not supported for the mutagen unit tests.
-#endif // __has_feature(memory_sanitizer)
-#endif // defined(__has_feature)
-
-namespace mutagen {
-namespace {
-
-using fuzzer::Set;
-
-std::unique_ptr<MutationDispatcher> CreateMutationDispatcher() {
- LLVMMutagenConfiguration Config;
- memset(&Config, 0, sizeof(Config));
- return std::unique_ptr<MutationDispatcher>(new MutationDispatcher(&Config));
-}
-
-typedef size_t (MutationDispatcher::*Mutator)(uint8_t *Data, size_t Size,
- size_t MaxSize);
-
-TEST(MutationDispatcher, CrossOver) {
- auto MD = CreateMutationDispatcher();
- Unit A({0, 1, 2}), B({5, 6, 7});
- Unit C;
- Unit Expected[] = {{0},
- {0, 1},
- {0, 5},
- {0, 1, 2},
- {0, 1, 5},
- {0, 5, 1},
- {0, 5, 6},
- {0, 1, 2, 5},
- {0, 1, 5, 2},
- {0, 1, 5, 6},
- {0, 5, 1, 2},
- {0, 5, 1, 6},
- {0, 5, 6, 1},
- {0, 5, 6, 7},
- {0, 1, 2, 5, 6},
- {0, 1, 5, 2, 6},
- {0, 1, 5, 6, 2},
- {0, 1, 5, 6, 7},
- {0, 5, 1, 2, 6},
- {0, 5, 1, 6, 2},
- {0, 5, 1, 6, 7},
- {0, 5, 6, 1, 2},
- {0, 5, 6, 1, 7},
- {0, 5, 6, 7, 1},
- {0, 1, 2, 5, 6, 7},
- {0, 1, 5, 2, 6, 7},
- {0, 1, 5, 6, 2, 7},
- {0, 1, 5, 6, 7, 2},
- {0, 5, 1, 2, 6, 7},
- {0, 5, 1, 6, 2, 7},
- {0, 5, 1, 6, 7, 2},
- {0, 5, 6, 1, 2, 7},
- {0, 5, 6, 1, 7, 2},
- {0, 5, 6, 7, 1, 2}};
- for (size_t Len = 1; Len < 8; Len++) {
- Set<Unit> FoundUnits, ExpectedUnitsWitThisLength;
- for (int Iter = 0; Iter < 3000; Iter++) {
- C.resize(Len);
- size_t NewSize = MD->CrossOver(A.data(), A.size(), B.data(), B.size(),
- C.data(), C.size());
- C.resize(NewSize);
- FoundUnits.insert(C);
- }
- for (const Unit &U : Expected)
- if (U.size() <= Len)
- ExpectedUnitsWitThisLength.insert(U);
- EXPECT_EQ(ExpectedUnitsWitThisLength, FoundUnits);
- }
-}
-
-void TestEraseBytes(Mutator M, int NumIter) {
- uint8_t REM0[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
- uint8_t REM1[8] = {0x00, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
- uint8_t REM2[8] = {0x00, 0x11, 0x33, 0x44, 0x55, 0x66, 0x77};
- uint8_t REM3[8] = {0x00, 0x11, 0x22, 0x44, 0x55, 0x66, 0x77};
- uint8_t REM4[8] = {0x00, 0x11, 0x22, 0x33, 0x55, 0x66, 0x77};
- uint8_t REM5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x66, 0x77};
- uint8_t REM6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x77};
- uint8_t REM7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
-
- uint8_t REM8[6] = {0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
- uint8_t REM9[6] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55};
- uint8_t REM10[6] = {0x00, 0x11, 0x22, 0x55, 0x66, 0x77};
-
- uint8_t REM11[5] = {0x33, 0x44, 0x55, 0x66, 0x77};
- uint8_t REM12[5] = {0x00, 0x11, 0x22, 0x33, 0x44};
- uint8_t REM13[5] = {0x00, 0x44, 0x55, 0x66, 0x77};
-
- auto MD = CreateMutationDispatcher();
- int FoundMask = 0;
- for (int i = 0; i < NumIter; i++) {
- uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
- size_t NewSize = (*MD.*M)(T, sizeof(T), sizeof(T));
- if (NewSize == 7 && !memcmp(REM0, T, 7))
- FoundMask |= 1 << 0;
- if (NewSize == 7 && !memcmp(REM1, T, 7))
- FoundMask |= 1 << 1;
- if (NewSize == 7 && !memcmp(REM2, T, 7))
- FoundMask |= 1 << 2;
- if (NewSize == 7 && !memcmp(REM3, T, 7))
- FoundMask |= 1 << 3;
- if (NewSize == 7 && !memcmp(REM4, T, 7))
- FoundMask |= 1 << 4;
- if (NewSize == 7 && !memcmp(REM5, T, 7))
- FoundMask |= 1 << 5;
- if (NewSize == 7 && !memcmp(REM6, T, 7))
- FoundMask |= 1 << 6;
- if (NewSize == 7 && !memcmp(REM7, T, 7))
- FoundMask |= 1 << 7;
-
- if (NewSize == 6 && !memcmp(REM8, T, 6))
- FoundMask |= 1 << 8;
- if (NewSize == 6 && !memcmp(REM9, T, 6))
- FoundMask |= 1 << 9;
- if (NewSize == 6 && !memcmp(REM10, T, 6))
- FoundMask |= 1 << 10;
-
- if (NewSize == 5 && !memcmp(REM11, T, 5))
- FoundMask |= 1 << 11;
- if (NewSize == 5 && !memcmp(REM12, T, 5))
- FoundMask |= 1 << 12;
- if (NewSize == 5 && !memcmp(REM13, T, 5))
- FoundMask |= 1 << 13;
- }
- EXPECT_EQ(FoundMask, (1 << 14) - 1);
-}
-
-TEST(MutationDispatcher, EraseBytes1) {
- TestEraseBytes(&MutationDispatcher::Mutate_EraseBytes, 200);
-}
-TEST(MutationDispatcher, EraseBytes2) {
- TestEraseBytes(&MutationDispatcher::Mutate, 2000);
-}
-
-void TestInsertByte(Mutator M, int NumIter) {
- auto MD = CreateMutationDispatcher();
- int FoundMask = 0;
- uint8_t INS0[8] = {0xF1, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
- uint8_t INS1[8] = {0x00, 0xF2, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
- uint8_t INS2[8] = {0x00, 0x11, 0xF3, 0x22, 0x33, 0x44, 0x55, 0x66};
- uint8_t INS3[8] = {0x00, 0x11, 0x22, 0xF4, 0x33, 0x44, 0x55, 0x66};
- uint8_t INS4[8] = {0x00, 0x11, 0x22, 0x33, 0xF5, 0x44, 0x55, 0x66};
- uint8_t INS5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0xF6, 0x55, 0x66};
- uint8_t INS6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0xF7, 0x66};
- uint8_t INS7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xF8};
- for (int i = 0; i < NumIter; i++) {
- uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
- size_t NewSize = (*MD.*M)(T, 7, 8);
- if (NewSize == 8 && !memcmp(INS0, T, 8))
- FoundMask |= 1 << 0;
- if (NewSize == 8 && !memcmp(INS1, T, 8))
- FoundMask |= 1 << 1;
- if (NewSize == 8 && !memcmp(INS2, T, 8))
- FoundMask |= 1 << 2;
- if (NewSize == 8 && !memcmp(INS3, T, 8))
- FoundMask |= 1 << 3;
- if (NewSize == 8 && !memcmp(INS4, T, 8))
- FoundMask |= 1 << 4;
- if (NewSize == 8 && !memcmp(INS5, T, 8))
- FoundMask |= 1 << 5;
- if (NewSize == 8 && !memcmp(INS6, T, 8))
- FoundMask |= 1 << 6;
- if (NewSize == 8 && !memcmp(INS7, T, 8))
- FoundMask |= 1 << 7;
- }
- EXPECT_EQ(FoundMask, 255);
-}
-
-TEST(MutationDispatcher, InsertByte1) {
- TestInsertByte(&MutationDispatcher::Mutate_InsertByte, 1 << 15);
-}
-TEST(MutationDispatcher, InsertByte2) {
- TestInsertByte(&MutationDispatcher::Mutate, 1 << 17);
-}
-
-void TestInsertRepeatedBytes(Mutator M, int NumIter) {
- auto MD = CreateMutationDispatcher();
- int FoundMask = 0;
- uint8_t INS0[7] = {0x00, 0x11, 0x22, 0x33, 'a', 'a', 'a'};
- uint8_t INS1[7] = {0x00, 0x11, 0x22, 'a', 'a', 'a', 0x33};
- uint8_t INS2[7] = {0x00, 0x11, 'a', 'a', 'a', 0x22, 0x33};
- uint8_t INS3[7] = {0x00, 'a', 'a', 'a', 0x11, 0x22, 0x33};
- uint8_t INS4[7] = {'a', 'a', 'a', 0x00, 0x11, 0x22, 0x33};
-
- uint8_t INS5[8] = {0x00, 0x11, 0x22, 0x33, 'b', 'b', 'b', 'b'};
- uint8_t INS6[8] = {0x00, 0x11, 0x22, 'b', 'b', 'b', 'b', 0x33};
- uint8_t INS7[8] = {0x00, 0x11, 'b', 'b', 'b', 'b', 0x22, 0x33};
- uint8_t INS8[8] = {0x00, 'b', 'b', 'b', 'b', 0x11, 0x22, 0x33};
- uint8_t INS9[8] = {'b', 'b', 'b', 'b', 0x00, 0x11, 0x22, 0x33};
-
- for (int i = 0; i < NumIter; i++) {
- uint8_t T[8] = {0x00, 0x11, 0x22, 0x33};
- size_t NewSize = (*MD.*M)(T, 4, 8);
- if (NewSize == 7 && !memcmp(INS0, T, 7))
- FoundMask |= 1 << 0;
- if (NewSize == 7 && !memcmp(INS1, T, 7))
- FoundMask |= 1 << 1;
- if (NewSize == 7 && !memcmp(INS2, T, 7))
- FoundMask |= 1 << 2;
- if (NewSize == 7 && !memcmp(INS3, T, 7))
- FoundMask |= 1 << 3;
- if (NewSize == 7 && !memcmp(INS4, T, 7))
- FoundMask |= 1 << 4;
-
- if (NewSize == 8 && !memcmp(INS5, T, 8))
- FoundMask |= 1 << 5;
- if (NewSize == 8 && !memcmp(INS6, T, 8))
- FoundMask |= 1 << 6;
- if (NewSize == 8 && !memcmp(INS7, T, 8))
- FoundMask |= 1 << 7;
- if (NewSize == 8 && !memcmp(INS8, T, 8))
- FoundMask |= 1 << 8;
- if (NewSize == 8 && !memcmp(INS9, T, 8))
- FoundMask |= 1 << 9;
- }
- EXPECT_EQ(FoundMask, (1 << 10) - 1);
-}
-
-TEST(MutationDispatcher, InsertRepeatedBytes1) {
- TestInsertRepeatedBytes(&MutationDispatcher::Mutate_InsertRepeatedBytes,
- 10000);
-}
-TEST(MutationDispatcher, InsertRepeatedBytes2) {
- TestInsertRepeatedBytes(&MutationDispatcher::Mutate, 300000);
-}
-
-void TestChangeByte(Mutator M, int NumIter) {
- auto MD = CreateMutationDispatcher();
- int FoundMask = 0;
- uint8_t CH0[8] = {0xF0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
- uint8_t CH1[8] = {0x00, 0xF1, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
- uint8_t CH2[8] = {0x00, 0x11, 0xF2, 0x33, 0x44, 0x55, 0x66, 0x77};
- uint8_t CH3[8] = {0x00, 0x11, 0x22, 0xF3, 0x44, 0x55, 0x66, 0x77};
- uint8_t CH4[8] = {0x00, 0x11, 0x22, 0x33, 0xF4, 0x55, 0x66, 0x77};
- uint8_t CH5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0xF5, 0x66, 0x77};
- uint8_t CH6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0xF5, 0x77};
- uint8_t CH7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xF7};
- for (int i = 0; i < NumIter; i++) {
- uint8_t T[9] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
- size_t NewSize = (*MD.*M)(T, 8, 9);
- if (NewSize == 8 && !memcmp(CH0, T, 8))
- FoundMask |= 1 << 0;
- if (NewSize == 8 && !memcmp(CH1, T, 8))
- FoundMask |= 1 << 1;
- if (NewSize == 8 && !memcmp(CH2, T, 8))
- FoundMask |= 1 << 2;
- if (NewSize == 8 && !memcmp(CH3, T, 8))
- FoundMask |= 1 << 3;
- if (NewSize == 8 && !memcmp(CH4, T, 8))
- FoundMask |= 1 << 4;
- if (NewSize == 8 && !memcmp(CH5, T, 8))
- FoundMask |= 1 << 5;
- if (NewSize == 8 && !memcmp(CH6, T, 8))
- FoundMask |= 1 << 6;
- if (NewSize == 8 && !memcmp(CH7, T, 8))
- FoundMask |= 1 << 7;
- }
- EXPECT_EQ(FoundMask, 255);
-}
-
-TEST(MutationDispatcher, ChangeByte1) {
- TestChangeByte(&MutationDispatcher::Mutate_ChangeByte, 1 << 15);
-}
-TEST(MutationDispatcher, ChangeByte2) {
- TestChangeByte(&MutationDispatcher::Mutate, 1 << 17);
-}
-
-void TestChangeBit(Mutator M, int NumIter) {
- auto MD = CreateMutationDispatcher();
- int FoundMask = 0;
- uint8_t CH0[8] = {0x01, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
- uint8_t CH1[8] = {0x00, 0x13, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
- uint8_t CH2[8] = {0x00, 0x11, 0x02, 0x33, 0x44, 0x55, 0x66, 0x77};
- uint8_t CH3[8] = {0x00, 0x11, 0x22, 0x37, 0x44, 0x55, 0x66, 0x77};
- uint8_t CH4[8] = {0x00, 0x11, 0x22, 0x33, 0x54, 0x55, 0x66, 0x77};
- uint8_t CH5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x54, 0x66, 0x77};
- uint8_t CH6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x76, 0x77};
- uint8_t CH7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0xF7};
- for (int i = 0; i < NumIter; i++) {
- uint8_t T[9] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
- size_t NewSize = (*MD.*M)(T, 8, 9);
- if (NewSize == 8 && !memcmp(CH0, T, 8))
- FoundMask |= 1 << 0;
- if (NewSize == 8 && !memcmp(CH1, T, 8))
- FoundMask |= 1 << 1;
- if (NewSize == 8 && !memcmp(CH2, T, 8))
- FoundMask |= 1 << 2;
- if (NewSize == 8 && !memcmp(CH3, T, 8))
- FoundMask |= 1 << 3;
- if (NewSize == 8 && !memcmp(CH4, T, 8))
- FoundMask |= 1 << 4;
- if (NewSize == 8 && !memcmp(CH5, T, 8))
- FoundMask |= 1 << 5;
- if (NewSize == 8 && !memcmp(CH6, T, 8))
- FoundMask |= 1 << 6;
- if (NewSize == 8 && !memcmp(CH7, T, 8))
- FoundMask |= 1 << 7;
- }
- EXPECT_EQ(FoundMask, 255);
-}
-
-TEST(MutationDispatcher, ChangeBit1) {
- TestChangeBit(&MutationDispatcher::Mutate_ChangeBit, 1 << 16);
-}
-TEST(MutationDispatcher, ChangeBit2) {
- TestChangeBit(&MutationDispatcher::Mutate, 1 << 18);
-}
-
-void TestShuffleBytes(Mutator M, int NumIter) {
- auto MD = CreateMutationDispatcher();
- int FoundMask = 0;
- uint8_t CH0[7] = {0x00, 0x22, 0x11, 0x33, 0x44, 0x55, 0x66};
- uint8_t CH1[7] = {0x11, 0x00, 0x33, 0x22, 0x44, 0x55, 0x66};
- uint8_t CH2[7] = {0x00, 0x33, 0x11, 0x22, 0x44, 0x55, 0x66};
- uint8_t CH3[7] = {0x00, 0x11, 0x22, 0x44, 0x55, 0x66, 0x33};
- uint8_t CH4[7] = {0x00, 0x11, 0x22, 0x33, 0x55, 0x44, 0x66};
- for (int i = 0; i < NumIter; i++) {
- uint8_t T[7] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
- size_t NewSize = (*MD.*M)(T, 7, 7);
- if (NewSize == 7 && !memcmp(CH0, T, 7))
- FoundMask |= 1 << 0;
- if (NewSize == 7 && !memcmp(CH1, T, 7))
- FoundMask |= 1 << 1;
- if (NewSize == 7 && !memcmp(CH2, T, 7))
- FoundMask |= 1 << 2;
- if (NewSize == 7 && !memcmp(CH3, T, 7))
- FoundMask |= 1 << 3;
- if (NewSize == 7 && !memcmp(CH4, T, 7))
- FoundMask |= 1 << 4;
- }
- EXPECT_EQ(FoundMask, 31);
-}
-
-TEST(MutationDispatcher, ShuffleBytes1) {
- TestShuffleBytes(&MutationDispatcher::Mutate_ShuffleBytes, 1 << 17);
-}
-TEST(MutationDispatcher, ShuffleBytes2) {
- TestShuffleBytes(&MutationDispatcher::Mutate, 1 << 20);
-}
-
-void TestCopyPart(Mutator M, int NumIter) {
- auto MD = CreateMutationDispatcher();
- int FoundMask = 0;
- uint8_t CH0[7] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x11};
- uint8_t CH1[7] = {0x55, 0x66, 0x22, 0x33, 0x44, 0x55, 0x66};
- uint8_t CH2[7] = {0x00, 0x55, 0x66, 0x33, 0x44, 0x55, 0x66};
- uint8_t CH3[7] = {0x00, 0x11, 0x22, 0x00, 0x11, 0x22, 0x66};
- uint8_t CH4[7] = {0x00, 0x11, 0x11, 0x22, 0x33, 0x55, 0x66};
-
- for (int i = 0; i < NumIter; i++) {
- uint8_t T[7] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
- size_t NewSize = (*MD.*M)(T, 7, 7);
- if (NewSize == 7 && !memcmp(CH0, T, 7))
- FoundMask |= 1 << 0;
- if (NewSize == 7 && !memcmp(CH1, T, 7))
- FoundMask |= 1 << 1;
- if (NewSize == 7 && !memcmp(CH2, T, 7))
- FoundMask |= 1 << 2;
- if (NewSize == 7 && !memcmp(CH3, T, 7))
- FoundMask |= 1 << 3;
- if (NewSize == 7 && !memcmp(CH4, T, 7))
- FoundMask |= 1 << 4;
- }
-
- uint8_t CH5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x11, 0x22};
- uint8_t CH6[8] = {0x22, 0x33, 0x44, 0x00, 0x11, 0x22, 0x33, 0x44};
- uint8_t CH7[8] = {0x00, 0x11, 0x22, 0x00, 0x11, 0x22, 0x33, 0x44};
- uint8_t CH8[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x22, 0x33, 0x44};
- uint8_t CH9[8] = {0x00, 0x11, 0x22, 0x22, 0x33, 0x44, 0x33, 0x44};
-
- for (int i = 0; i < NumIter; i++) {
- uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
- size_t NewSize = (*MD.*M)(T, 5, 8);
- if (NewSize == 8 && !memcmp(CH5, T, 8))
- FoundMask |= 1 << 5;
- if (NewSize == 8 && !memcmp(CH6, T, 8))
- FoundMask |= 1 << 6;
- if (NewSize == 8 && !memcmp(CH7, T, 8))
- FoundMask |= 1 << 7;
- if (NewSize == 8 && !memcmp(CH8, T, 8))
- FoundMask |= 1 << 8;
- if (NewSize == 8 && !memcmp(CH9, T, 8))
- FoundMask |= 1 << 9;
- }
-
- EXPECT_EQ(FoundMask, 1023);
-}
-
-TEST(MutationDispatcher, CopyPart1) {
- TestCopyPart(&MutationDispatcher::Mutate_CopyPart, 1 << 10);
-}
-TEST(MutationDispatcher, CopyPart2) {
- TestCopyPart(&MutationDispatcher::Mutate, 1 << 13);
-}
-TEST(MutationDispatcher, CopyPartNoInsertAtMaxSize) {
- // This (non exhaustively) tests if `Mutate_CopyPart` tries to perform an
- // insert on an input of size `MaxSize`. Performing an insert in this case
- // will lead to the mutation failing.
- auto MD = CreateMutationDispatcher();
- uint8_t Data[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x00, 0x11, 0x22};
- size_t MaxSize = sizeof(Data);
- for (int count = 0; count < (1 << 18); ++count) {
- size_t NewSize = MD->Mutate_CopyPart(Data, MaxSize, MaxSize);
- ASSERT_EQ(NewSize, MaxSize);
- }
-}
-
-void TestAddWordFromDictionary(Mutator M, int NumIter) {
- auto MD = CreateMutationDispatcher();
- uint8_t Word1[4] = {0xAA, 0xBB, 0xCC, 0xDD};
- uint8_t Word2[3] = {0xFF, 0xEE, 0xEF};
- MD->AddWordToManualDictionary(Word(Word1, sizeof(Word1)));
- MD->AddWordToManualDictionary(Word(Word2, sizeof(Word2)));
- int FoundMask = 0;
- uint8_t CH0[7] = {0x00, 0x11, 0x22, 0xAA, 0xBB, 0xCC, 0xDD};
- uint8_t CH1[7] = {0x00, 0x11, 0xAA, 0xBB, 0xCC, 0xDD, 0x22};
- uint8_t CH2[7] = {0x00, 0xAA, 0xBB, 0xCC, 0xDD, 0x11, 0x22};
- uint8_t CH3[7] = {0xAA, 0xBB, 0xCC, 0xDD, 0x00, 0x11, 0x22};
- uint8_t CH4[6] = {0x00, 0x11, 0x22, 0xFF, 0xEE, 0xEF};
- uint8_t CH5[6] = {0x00, 0x11, 0xFF, 0xEE, 0xEF, 0x22};
- uint8_t CH6[6] = {0x00, 0xFF, 0xEE, 0xEF, 0x11, 0x22};
- uint8_t CH7[6] = {0xFF, 0xEE, 0xEF, 0x00, 0x11, 0x22};
- for (int i = 0; i < NumIter; i++) {
- uint8_t T[7] = {0x00, 0x11, 0x22};
- size_t NewSize = (*MD.*M)(T, 3, 7);
- if (NewSize == 7 && !memcmp(CH0, T, 7))
- FoundMask |= 1 << 0;
- if (NewSize == 7 && !memcmp(CH1, T, 7))
- FoundMask |= 1 << 1;
- if (NewSize == 7 && !memcmp(CH2, T, 7))
- FoundMask |= 1 << 2;
- if (NewSize == 7 && !memcmp(CH3, T, 7))
- FoundMask |= 1 << 3;
- if (NewSize == 6 && !memcmp(CH4, T, 6))
- FoundMask |= 1 << 4;
- if (NewSize == 6 && !memcmp(CH5, T, 6))
- FoundMask |= 1 << 5;
- if (NewSize == 6 && !memcmp(CH6, T, 6))
- FoundMask |= 1 << 6;
- if (NewSize == 6 && !memcmp(CH7, T, 6))
- FoundMask |= 1 << 7;
- }
- EXPECT_EQ(FoundMask, 255);
-}
-
-TEST(MutationDispatcher, AddWordFromDictionary1) {
- TestAddWordFromDictionary(
- &MutationDispatcher::Mutate_AddWordFromManualDictionary, 1 << 15);
-}
-
-TEST(MutationDispatcher, AddWordFromDictionary2) {
- TestAddWordFromDictionary(&MutationDispatcher::Mutate, 1 << 15);
-}
-
-void TestChangeASCIIInteger(Mutator M, int NumIter) {
- auto MD = CreateMutationDispatcher();
-
- uint8_t CH0[8] = {'1', '2', '3', '4', '5', '6', '7', '7'};
- uint8_t CH1[8] = {'1', '2', '3', '4', '5', '6', '7', '9'};
- uint8_t CH2[8] = {'2', '4', '6', '9', '1', '3', '5', '6'};
- uint8_t CH3[8] = {'0', '6', '1', '7', '2', '8', '3', '9'};
- int FoundMask = 0;
- for (int i = 0; i < NumIter; i++) {
- uint8_t T[8] = {'1', '2', '3', '4', '5', '6', '7', '8'};
- size_t NewSize = (*MD.*M)(T, 8, 8);
- /**/ if (NewSize == 8 && !memcmp(CH0, T, 8))
- FoundMask |= 1 << 0;
- else if (NewSize == 8 && !memcmp(CH1, T, 8))
- FoundMask |= 1 << 1;
- else if (NewSize == 8 && !memcmp(CH2, T, 8))
- FoundMask |= 1 << 2;
- else if (NewSize == 8 && !memcmp(CH3, T, 8))
- FoundMask |= 1 << 3;
- else if (NewSize == 8)
- FoundMask |= 1 << 4;
- }
- EXPECT_EQ(FoundMask, 31);
-}
-
-TEST(MutationDispatcher, ChangeASCIIInteger1) {
- TestChangeASCIIInteger(&MutationDispatcher::Mutate_ChangeASCIIInteger,
- 1 << 15);
-}
-
-TEST(MutationDispatcher, ChangeASCIIInteger2) {
- TestChangeASCIIInteger(&MutationDispatcher::Mutate, 1 << 15);
-}
-
-void TestChangeBinaryInteger(Mutator M, int NumIter) {
- auto MD = CreateMutationDispatcher();
-
- uint8_t CH0[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x79};
- uint8_t CH1[8] = {0x00, 0x11, 0x22, 0x31, 0x44, 0x55, 0x66, 0x77};
- uint8_t CH2[8] = {0xff, 0x10, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
- uint8_t CH3[8] = {0x00, 0x11, 0x2a, 0x33, 0x44, 0x55, 0x66, 0x77};
- uint8_t CH4[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x4f, 0x66, 0x77};
- uint8_t CH5[8] = {0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88};
- uint8_t CH6[8] = {0x00, 0x11, 0x22, 0x00, 0x00, 0x00, 0x08, 0x77}; // Size
- uint8_t CH7[8] = {0x00, 0x08, 0x00, 0x33, 0x44, 0x55, 0x66, 0x77}; // Sw(Size)
-
- int FoundMask = 0;
- for (int i = 0; i < NumIter; i++) {
- uint8_t T[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
- size_t NewSize = (*MD.*M)(T, 8, 8);
- /**/ if (NewSize == 8 && !memcmp(CH0, T, 8))
- FoundMask |= 1 << 0;
- else if (NewSize == 8 && !memcmp(CH1, T, 8))
- FoundMask |= 1 << 1;
- else if (NewSize == 8 && !memcmp(CH2, T, 8))
- FoundMask |= 1 << 2;
- else if (NewSize == 8 && !memcmp(CH3, T, 8))
- FoundMask |= 1 << 3;
- else if (NewSize == 8 && !memcmp(CH4, T, 8))
- FoundMask |= 1 << 4;
- else if (NewSize == 8 && !memcmp(CH5, T, 8))
- FoundMask |= 1 << 5;
- else if (NewSize == 8 && !memcmp(CH6, T, 8))
- FoundMask |= 1 << 6;
- else if (NewSize == 8 && !memcmp(CH7, T, 8))
- FoundMask |= 1 << 7;
- }
- EXPECT_EQ(FoundMask, 255);
-}
-
-TEST(MutationDispatcher, ChangeBinaryInteger1) {
- TestChangeBinaryInteger(&MutationDispatcher::Mutate_ChangeBinaryInteger,
- 1 << 12);
-}
-
-TEST(MutationDispatcher, ChangeBinaryInteger2) {
- TestChangeBinaryInteger(&MutationDispatcher::Mutate, 1 << 15);
-}
-
-// Test fixture for MutagenInterface unit tests.
-static const char *kWord1 = "word1";
-static const char *kWord2 = "word2";
-
-class MutagenInterface : public ::testing::Test {
-protected:
- void SetUp() override {
- Current = this;
- memset(&Config, 0, sizeof(Config));
-
- Config.Seed = 1;
-
- Config.UseCmp = 1;
- Config.FromTORC4 = [](size_t Idx, uint32_t *Arg1, uint32_t *Arg2) {
- ++(Current->FromTORC4Calls);
- *Arg1 = 0x0401;
- *Arg2 = 0x0402;
- };
- Config.FromTORC8 = [](size_t Idx, uint64_t *Arg1, uint64_t *Arg2) {
- ++(Current->FromTORC8Calls);
- *Arg1 = 0x0801;
- *Arg2 = 0x0802;
- };
- Config.FromTORCW = [](size_t Idx, const uint8_t **Data1, size_t *Size1,
- const uint8_t **Data2, size_t *Size2) {
- ++(Current->FromTORCWCalls);
- *Data1 = reinterpret_cast<const uint8_t *>(kWord1);
- *Size1 = strlen(kWord1);
- *Data2 = reinterpret_cast<const uint8_t *>(kWord2);
- *Size2 = strlen(kWord2);
- };
-
- Config.UseMemmem = 0;
- Config.FromMMT = [](size_t Idx, const uint8_t **Data, size_t *Size) {
- ++(Current->FromMMTCalls);
- *Data = reinterpret_cast<const uint8_t *>(kWord1);
- *Size = strlen(kWord1);
- };
-
- Config.OnlyASCII = 0;
-
- Config.CustomMutator = [](uint8_t *Data, size_t Size, size_t MaxSize,
- unsigned int Seed) {
- ++(Current->CustomMutatorCalls);
- return LLVMMutagenDefaultMutate(Data, Size, MaxSize);
- };
-
- Config.CustomCrossOver =
- [](const uint8_t *Data1, size_t Size1, const uint8_t *Data2,
- size_t Size2, uint8_t *Out, size_t MaxOutSize, unsigned int Seed) {
- ++(Current->CustomCrossOverCalls);
- auto *MD = GetMutationDispatcherForTest();
- return MD->CrossOver(Data1, Size1, Data2, Size2, Out, MaxOutSize);
- };
-
- U = Unit({1, 2, 3, 4});
- U.reserve(8);
- }
-
- void TearDown() override {
- Current = nullptr;
- memset(&Config, 0, sizeof(Config));
- LLVMMutagenConfigure(&Config);
- }
-
- LLVMMutagenConfiguration Config;
- Unit U;
-
- size_t FromTORC4Calls = 0;
- size_t FromTORC8Calls = 0;
- size_t FromTORCWCalls = 0;
- size_t FromMMTCalls = 0;
- size_t CustomMutatorCalls = 0;
- size_t CustomCrossOverCalls = 0;
-
-private:
- static MutagenInterface *Current;
-};
-
-MutagenInterface *MutagenInterface::Current = nullptr;
-
-// Unit tests for MutagenInterface.
-
-TEST_F(MutagenInterface, Configure) {
- Config.OnlyASCII = 1;
- LLVMMutagenConfigure(&Config);
- auto *MD = GetMutationDispatcherForTest();
- ASSERT_NE(MD, nullptr);
-
- Random Rand1(Config.Seed);
- Random &Rand2 = MD->GetRand();
- for (size_t i = 0; i < 10; ++i)
- EXPECT_EQ(Rand1(), Rand2());
-
- Config.Seed = static_cast<unsigned>(
- std::chrono::system_clock::now().time_since_epoch().count());
- Config.OnlyASCII = 0;
- LLVMMutagenConfigure(&Config);
- MD = GetMutationDispatcherForTest();
- ASSERT_NE(MD, nullptr);
-
- Random Rand3(Config.Seed);
- Random &Rand4 = MD->GetRand();
- for (size_t i = 0; i < 10; ++i)
- EXPECT_EQ(Rand3(), Rand4());
-}
-
-TEST_F(MutagenInterface, UseTORCs) {
- // If !UseCmp, none of the TORC/MMT callbacks are called, regardless of
- // UseMemmem.
- Config.UseCmp = 0;
- Config.UseMemmem = 1;
- LLVMMutagenConfigure(&Config);
- for (size_t i = 0; i < 200; ++i)
- LLVMMutagenMutate(U.data(), U.size(), U.capacity());
- EXPECT_EQ(FromTORC4Calls, 0U);
- EXPECT_EQ(FromTORC8Calls, 0U);
- EXPECT_EQ(FromTORCWCalls, 0U);
- EXPECT_EQ(FromMMTCalls, 0U);
-
- // If UseCmp, but !UseMemmem, only the TORC callbacks are invoked.
- Config.UseCmp = 1;
- Config.UseMemmem = 0;
- LLVMMutagenConfigure(&Config);
- for (size_t i = 0; i < 200; ++i)
- LLVMMutagenMutate(U.data(), U.size(), U.capacity());
- EXPECT_NE(FromTORC4Calls, 0U);
- EXPECT_NE(FromTORC8Calls, 0U);
- EXPECT_NE(FromTORCWCalls, 0U);
- EXPECT_EQ(FromMMTCalls, 0U);
-
- // If UseCmp and UseMemmem, all the TORC/MMT callbacks are invoked.
- Config.UseCmp = 1;
- Config.UseMemmem = 1;
- LLVMMutagenConfigure(&Config);
- for (size_t i = 0; i < 200; ++i)
- LLVMMutagenMutate(U.data(), U.size(), U.capacity());
- EXPECT_NE(FromTORC4Calls, 0U);
- EXPECT_NE(FromTORC8Calls, 0U);
- EXPECT_NE(FromTORCWCalls, 0U);
- EXPECT_NE(FromMMTCalls, 0U);
-}
-
-TEST_F(MutagenInterface, CustomCallbacks) {
- // DefaultMutate never selects custom callbacks.
- LLVMMutagenConfigure(&Config);
- for (size_t i = 0; i < 200; ++i)
- LLVMMutagenDefaultMutate(U.data(), U.size(), U.capacity());
-
- // Valid.
- auto *MD = GetMutationDispatcherForTest();
- EXPECT_EQ(CustomMutatorCalls, 0U);
- MD->Mutate_Custom(U.data(), U.size(), U.capacity());
- EXPECT_EQ(CustomMutatorCalls, 1U);
-
- // Null cross-over input disables CustomCrossOver.
- LLVMMutagenSetCrossOverWith(nullptr, 0);
- MD->Mutate_CustomCrossOver(U.data(), U.size(), U.capacity());
- EXPECT_EQ(CustomCrossOverCalls, 0U);
-
- // Zero-length cross-over input disables CustomCrossOver.
- Unit CrossOverWith = {4, 3, 2, 1};
- LLVMMutagenSetCrossOverWith(CrossOverWith.data(), 0);
- MD->Mutate_CustomCrossOver(U.data(), U.size(), U.capacity());
- EXPECT_EQ(CustomCrossOverCalls, 0U);
-
- // Valid.
- LLVMMutagenSetCrossOverWith(CrossOverWith.data(), CrossOverWith.size());
- MD->Mutate_CustomCrossOver(U.data(), U.size(), U.capacity());
- EXPECT_EQ(CustomCrossOverCalls, 1U);
-
- // Can mutate without custom callbacks.
- Config.CustomMutator = nullptr;
- Config.CustomCrossOver = nullptr;
- LLVMMutagenConfigure(&Config);
- for (size_t i = 0; i < 200; ++i)
- LLVMMutagenMutate(U.data(), U.size(), U.capacity());
-}
-
-TEST_F(MutagenInterface, MutationSequence) {
- LLVMMutagenConfigure(&Config);
- char Buf[1024];
- size_t NumItems;
-
- Set<std::string> Names = {
- "ShuffleBytes", "EraseBytes", "InsertBytes", "InsertRepeatedBytes",
- "ChangeByte", "ChangeBit", "CopyPart", "ChangeASCIIInt",
- "ChangeBinInt",
- };
- std::string Name;
- std::istringstream ISS;
-
- // Empty sequences
- auto Size = LLVMMutagenGetMutationSequence(true, Buf, sizeof(Buf), &NumItems);
- EXPECT_STREQ(Buf, "");
- EXPECT_EQ(Size, 0U);
- EXPECT_EQ(NumItems, 0U);
-
- while (true) {
- // Can get size without output parameters.
- Size = LLVMMutagenGetMutationSequence(true, nullptr, 0, &NumItems);
- if (NumItems > Sequence<Mutator>::kMaxBriefItems)
- break;
- // !Verbose has no effect for <= 10 items.
- EXPECT_EQ(LLVMMutagenGetMutationSequence(false, nullptr, 0, nullptr), Size);
- EXPECT_GT(LLVMMutagenDefaultMutate(U.data(), U.size(), U.capacity()), 0U);
- }
-
- // All items are valid.
- LLVMMutagenGetMutationSequence(true, Buf, sizeof(Buf), nullptr);
- ISS.str(Buf);
- size_t N = 0;
- while (std::getline(ISS, Name, '-')) {
- EXPECT_GT(Names.count(Name), 0U);
- ++N;
- }
- EXPECT_EQ(N, NumItems);
-
- // !Verbose truncates, but items are still valid.
- EXPECT_LT(LLVMMutagenGetMutationSequence(false, Buf, sizeof(Buf), nullptr),
- Size);
- ISS.str(Buf);
- N = 0;
- while (std::getline(ISS, Name, '-')) {
- EXPECT_GT(Names.count(Name), 0U);
- ++N;
- }
- EXPECT_LT(N, NumItems);
-
- // Truncated sequence is a prefix of its untruncated equivalent.
- std::string Truncated(Buf);
- LLVMMutagenGetMutationSequence(true, Buf, sizeof(Buf), &NumItems);
- Buf[Truncated.size()] = '\0';
- EXPECT_STREQ(Truncated.c_str(), Buf);
-
- // Stops at the end of |Buf|, and null terminates.
- EXPECT_EQ(LLVMMutagenGetMutationSequence(true, Buf, Size - 1, nullptr), Size);
- EXPECT_EQ(strlen(Buf), Size - 2);
-
- // Clear the sequence.
- LLVMMutagenResetSequence();
- EXPECT_EQ(LLVMMutagenGetMutationSequence(true, nullptr, 0, nullptr), 0U);
-}
-
-static uint8_t FromASCIINybble(char C) {
- if ('0' <= C && C <= '9')
- return static_cast<uint8_t>(C - '0');
- if ('A' <= C && C <= 'F')
- return static_cast<uint8_t>(C - 'A' + 10);
- assert('a' <= C && C <= 'f');
- return static_cast<uint8_t>(C - 'a' + 10);
-}
-
-static Word FromASCII(const char *DE) {
- Unit Tmp;
- bool Escape = false;
- size_t Hex = 0;
- uint8_t Nybble = 0;
- for (char C = *DE++; C; C = *DE++) {
- if (Hex == 2) {
- Nybble = FromASCIINybble(C);
- --Hex;
- } else if (Hex == 1) {
- Tmp.push_back(static_cast<uint8_t>(Nybble << 4) | FromASCIINybble(C));
- --Hex;
- } else if (Escape) {
- switch (C) {
- case '\\':
- case '"':
- Tmp.push_back(static_cast<uint8_t>(C));
- break;
- case 'x':
- Hex = 2;
- break;
- default:
- assert(false && "FromASCII failure.");
- }
- Escape = false;
- } else if (C == '\\') {
- Escape = true;
- } else {
- Tmp.push_back(static_cast<uint8_t>(C));
- }
- }
- return Word(Tmp.data(), Tmp.size());
-}
-
-TEST_F(MutagenInterface, Dictionaries) {
- LLVMMutagenConfigure(&Config);
- size_t NumItems;
- char Buf[1024];
- std::istringstream ISS;
- std::string Str;
-
- // Empty sequences
- auto Size =
- LLVMMutagenGetDictionaryEntrySequence(true, Buf, sizeof(Buf), &NumItems);
- EXPECT_STREQ(Buf, "");
- EXPECT_EQ(Size, 0U);
- EXPECT_EQ(NumItems, 0U);
-
- auto *MD = GetMutationDispatcherForTest();
- while (true) {
- // Can get size without output parameters.
- Size = LLVMMutagenGetDictionaryEntrySequence(true, nullptr, 0, &NumItems);
- if (NumItems > Sequence<DictionaryEntry *>::kMaxBriefItems)
- break;
- // !Verbose has no effect for <= 10 items.
- EXPECT_EQ(LLVMMutagenGetDictionaryEntrySequence(false, nullptr, 0, nullptr),
- Size);
- MD->Mutate_AddWordFromTORC(U.data(), U.size(), U.capacity());
- }
-
- // All items are valid.
- LLVMMutagenGetDictionaryEntrySequence(true, Buf, sizeof(Buf), nullptr);
- ISS.str(Buf);
- size_t N = 0;
- while (std::getline(ISS, Str, '-')) {
- ASSERT_FALSE(Str.empty());
- EXPECT_EQ(Str[0], '"');
- EXPECT_EQ(Str[Str.size() - 1], '"');
- ++N;
- }
- EXPECT_EQ(N, NumItems);
-
- // !Verbose truncates, but items are still valid.
- EXPECT_LT(
- LLVMMutagenGetDictionaryEntrySequence(false, Buf, sizeof(Buf), nullptr),
- Size);
- ISS.str(Buf);
- N = 0;
- while (std::getline(ISS, Str, '-')) {
- ASSERT_FALSE(Str.empty());
- EXPECT_EQ(Str[0], '"');
- EXPECT_EQ(Str[Str.size() - 1], '"');
- ++N;
- }
- EXPECT_LT(N, NumItems);
-
- // Truncated sequence is a prefix of its untruncated equivalent.
- std::string Truncated(Buf);
- LLVMMutagenGetDictionaryEntrySequence(true, Buf, sizeof(Buf), &NumItems);
- Buf[Truncated.size()] = '\0';
- EXPECT_STREQ(Truncated.c_str(), Buf);
-
- // Stops at the end of |Buf|, and null terminates.
- EXPECT_EQ(LLVMMutagenGetDictionaryEntrySequence(true, Buf, Size - 1, nullptr),
- Size);
- EXPECT_EQ(strlen(Buf), Size - 2);
-
- // Clear the sequence.
- LLVMMutagenResetSequence();
- EXPECT_EQ(LLVMMutagenGetDictionaryEntrySequence(true, nullptr, 0, nullptr),
- 0U);
-
- // Retuns null if no recommendations.
- size_t UseCount = 0;
- EXPECT_EQ(LLVMMutagenRecommendDictionaryEntry(&UseCount), nullptr);
- EXPECT_EQ(LLVMMutagenRecommendDictionary(), 0U);
- EXPECT_EQ(LLVMMutagenRecommendDictionaryEntry(&UseCount), nullptr);
-
- // Record sequences.
- for (size_t i = 0; i < 5; ++i) {
- for (size_t i = 0; i < 5; ++i) {
- MD->Mutate_AddWordFromTORC(U.data(), U.size(), U.capacity());
- }
- LLVMMutagenRecordSequence();
- }
-
- size_t NumDEs = LLVMMutagenRecommendDictionary();
- EXPECT_NE(NumDEs, 0U);
- for (size_t i = 0; i < NumDEs; ++i) {
- auto *DE = LLVMMutagenRecommendDictionaryEntry(&UseCount);
- EXPECT_NE(DE, nullptr);
- EXPECT_EQ(UseCount, 0U);
- }
-
- // Increment the use counts of entries.
- for (size_t i = 0; i < 100; ++i)
- MD->Mutate_AddWordFromPersistentAutoDictionary(U.data(), U.size(),
- U.capacity());
- NumDEs = LLVMMutagenRecommendDictionary();
- EXPECT_NE(NumDEs, 0U);
- for (size_t i = 0; i < NumDEs; ++i) {
- auto *DE = LLVMMutagenRecommendDictionaryEntry(&UseCount);
- EXPECT_NE(DE, nullptr);
- EXPECT_NE(UseCount, 0U);
- }
-
- // Add the first few words manually to exclude them from recommendations.
- Vector<Word> ManualAdditions;
- NumDEs = LLVMMutagenRecommendDictionary();
- ASSERT_GT(NumDEs, 3U);
- for (size_t i = 0; i < 3; ++i) {
- auto *DE = LLVMMutagenRecommendDictionaryEntry(nullptr);
- auto W = FromASCII(DE);
- LLVMMutagenAddWordToDictionary(W.data(), W.size());
- ManualAdditions.push_back(W);
- }
- N = NumDEs;
-
- // Get the recommended dictionary without the manual additions.
- NumDEs = LLVMMutagenRecommendDictionary();
- EXPECT_EQ(NumDEs, N - 3);
- for (size_t i = 0; i < NumDEs; ++i) {
- auto *DE = LLVMMutagenRecommendDictionaryEntry(nullptr);
- ASSERT_NE(DE, nullptr);
- Word W1(reinterpret_cast<const uint8_t *>(DE), strlen(DE));
- for (const auto &W2 : ManualAdditions)
- EXPECT_FALSE(W1 == W2);
- }
-}
-
-} // namespace
-} // namespace mutagen
-
-int main(int argc, char **argv) {
- testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
-}
diff --git a/compiler-rt/test/fuzzer/CMakeLists.txt b/compiler-rt/test/fuzzer/CMakeLists.txt
index acfcd437f0287..c12a04b6f2702 100644
--- a/compiler-rt/test/fuzzer/CMakeLists.txt
+++ b/compiler-rt/test/fuzzer/CMakeLists.txt
@@ -20,7 +20,6 @@ endif()
if(COMPILER_RT_INCLUDE_TESTS)
list(APPEND LIBFUZZER_TEST_DEPS FuzzerUnitTests)
list(APPEND LIBFUZZER_TEST_DEPS FuzzedDataProviderUnitTests)
- list(APPEND LIBFUZZER_TEST_DEPS MutagenUnitTests)
endif()
add_custom_target(check-fuzzer)
More information about the llvm-commits
mailing list