From 724a54f58b617572bf36ac2c67e4e62313bb5015 Mon Sep 17 00:00:00 2001 From: Marc Date: Thu, 25 Jul 2024 23:27:45 -0400 Subject: [PATCH 01/31] Update for VMF 4.0 --- .../modules/common/mutator/byteMutations.cpp | 18 ++--- .../modules/common/mutator/byteMutations.hpp | 6 +- .../modules/common/mutator/lineMutations.cpp | 26 +++---- .../modules/common/mutator/lineMutations.hpp | 6 +- .../modules/common/mutator/mutationBase.hpp | 2 +- .../modules/common/mutator/radamsaMutator.cpp | 20 +++--- .../modules/common/mutator/radamsaMutator.hpp | 14 ++-- .../src/modules/common/mutator/MyMutator.cpp | 4 +- .../src/modules/common/mutator/MyMutator.hpp | 4 +- dockerfiles/Dockerfile | 70 +++++++++++++++++++ dockerfiles/Dockerfile.kali | 70 +++++++++++++++++++ 11 files changed, 190 insertions(+), 50 deletions(-) create mode 100644 dockerfiles/Dockerfile create mode 100644 dockerfiles/Dockerfile.kali diff --git a/Radamsa/vmf/src/modules/common/mutator/byteMutations.cpp b/Radamsa/vmf/src/modules/common/mutator/byteMutations.cpp index 5310645..885730d 100644 --- a/Radamsa/vmf/src/modules/common/mutator/byteMutations.cpp +++ b/Radamsa/vmf/src/modules/common/mutator/byteMutations.cpp @@ -1,7 +1,7 @@ /* ============================================================================= * Vader Modular Fuzzer * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. - * + * * * Effort sponsored by the U.S. Government under Other Transaction number * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government @@ -50,7 +50,7 @@ #include "byteMutations.hpp" -void vader::radamsa::mutations::ByteMutations::DropByte( +void vmf::radamsa::mutations::ByteMutations::DropByte( StorageEntry* newEntry, const size_t originalSize, const char* originalBuffer, @@ -106,7 +106,7 @@ void vader::radamsa::mutations::ByteMutations::DropByte( } } -void vader::radamsa::mutations::ByteMutations::FlipByte( +void vmf::radamsa::mutations::ByteMutations::FlipByte( StorageEntry* newEntry, const size_t originalSize, const char* originalBuffer, @@ -161,7 +161,7 @@ void vader::radamsa::mutations::ByteMutations::FlipByte( newBuffer[randomIndexToFlip] ^= randomMaskedBit; } -void vader::radamsa::mutations::ByteMutations::InsertByte( +void vmf::radamsa::mutations::ByteMutations::InsertByte( StorageEntry* newEntry, const size_t originalSize, const char* originalBuffer, @@ -217,7 +217,7 @@ void vader::radamsa::mutations::ByteMutations::InsertByte( } } -void vader::radamsa::mutations::ByteMutations::RepeatByte( +void vmf::radamsa::mutations::ByteMutations::RepeatByte( StorageEntry* newEntry, const size_t originalSize, const char* originalBuffer, @@ -281,7 +281,7 @@ void vader::radamsa::mutations::ByteMutations::RepeatByte( } } -void vader::radamsa::mutations::ByteMutations::PermuteByte( +void vmf::radamsa::mutations::ByteMutations::PermuteByte( StorageEntry* newEntry, const size_t originalSize, const char* originalBuffer, @@ -337,7 +337,7 @@ void vader::radamsa::mutations::ByteMutations::PermuteByte( } } -void vader::radamsa::mutations::ByteMutations::IncrementByte( +void vmf::radamsa::mutations::ByteMutations::IncrementByte( StorageEntry* newEntry, const size_t originalSize, const char* originalBuffer, @@ -383,7 +383,7 @@ void vader::radamsa::mutations::ByteMutations::IncrementByte( newBuffer[randomIndexToIncrement] = static_cast((originalBuffer[randomIndexToIncrement] + 0x01u) % std::numeric_limits::max()); } -void vader::radamsa::mutations::ByteMutations::DecrementByte( +void vmf::radamsa::mutations::ByteMutations::DecrementByte( StorageEntry* newEntry, const size_t originalSize, const char* originalBuffer, @@ -429,7 +429,7 @@ void vader::radamsa::mutations::ByteMutations::DecrementByte( newBuffer[randomIndexToDecrement] = static_cast((originalBuffer[randomIndexToDecrement] - 0x01u) % std::numeric_limits::max()); } -void vader::radamsa::mutations::ByteMutations::RandomizeByte( +void vmf::radamsa::mutations::ByteMutations::RandomizeByte( StorageEntry* newEntry, const size_t originalSize, const char* originalBuffer, diff --git a/Radamsa/vmf/src/modules/common/mutator/byteMutations.hpp b/Radamsa/vmf/src/modules/common/mutator/byteMutations.hpp index fd848c9..da2e501 100644 --- a/Radamsa/vmf/src/modules/common/mutator/byteMutations.hpp +++ b/Radamsa/vmf/src/modules/common/mutator/byteMutations.hpp @@ -1,7 +1,7 @@ /* ============================================================================= * Vader Modular Fuzzer * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. - * + * * * Effort sponsored by the U.S. Government under Other Transaction number * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government @@ -36,7 +36,7 @@ #include "mutationBase.hpp" -namespace vader::radamsa::mutations +namespace vmf::radamsa::mutations { /** * @brief This module is draws heavily upon the libAFL mutator.c @@ -65,7 +65,7 @@ namespace vader::radamsa::mutations * customized fuzzers for a specific target while taking advantage of * a lot of features that AFL++ already provides. */ -class ByteMutations: public vader::radamsa::mutations::MutationBase +class ByteMutations: public vmf::radamsa::mutations::MutationBase { public: ByteMutations() = delete; diff --git a/Radamsa/vmf/src/modules/common/mutator/lineMutations.cpp b/Radamsa/vmf/src/modules/common/mutator/lineMutations.cpp index 103dc81..1daa36e 100644 --- a/Radamsa/vmf/src/modules/common/mutator/lineMutations.cpp +++ b/Radamsa/vmf/src/modules/common/mutator/lineMutations.cpp @@ -1,7 +1,7 @@ /* ============================================================================= * Vader Modular Fuzzer * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. - * + * * * Effort sponsored by the U.S. Government under Other Transaction number * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government @@ -55,7 +55,7 @@ #include "lineMutations.hpp" #include "Logging.hpp" -vader::radamsa::mutations::LineMutations::Line vader::radamsa::mutations::LineMutations::GetLineData( +vmf::radamsa::mutations::LineMutations::Line vmf::radamsa::mutations::LineMutations::GetLineData( const char* const buffer, const size_t size, const size_t lineIndex, @@ -118,7 +118,7 @@ vader::radamsa::mutations::LineMutations::Line vader::radamsa::mutations::LineMu return lineData; } -size_t vader::radamsa::mutations::LineMutations::GetNumberOfLinesAfterIndex( +size_t vmf::radamsa::mutations::LineMutations::GetNumberOfLinesAfterIndex( const char* const buffer, const size_t size, const size_t index) @@ -143,7 +143,7 @@ size_t vader::radamsa::mutations::LineMutations::GetNumberOfLinesAfterIndex( return ++numberOfLines; } -bool vader::radamsa::mutations::LineMutations::IsBinarish( +bool vmf::radamsa::mutations::LineMutations::IsBinarish( const char* const buffer, const size_t size) { @@ -174,7 +174,7 @@ bool vader::radamsa::mutations::LineMutations::IsBinarish( return false; } -void vader::radamsa::mutations::LineMutations::DeleteLine( +void vmf::radamsa::mutations::LineMutations::DeleteLine( StorageEntry* newEntry, const size_t originalSize, const char* originalBuffer, @@ -258,7 +258,7 @@ void vader::radamsa::mutations::LineMutations::DeleteLine( } } -void vader::radamsa::mutations::LineMutations::DeleteSequentialLines( +void vmf::radamsa::mutations::LineMutations::DeleteSequentialLines( StorageEntry* newEntry, const size_t originalSize, const char* originalBuffer, @@ -353,7 +353,7 @@ void vader::radamsa::mutations::LineMutations::DeleteSequentialLines( } } -void vader::radamsa::mutations::LineMutations::DuplicateLine( +void vmf::radamsa::mutations::LineMutations::DuplicateLine( StorageEntry* newEntry, const size_t originalSize, const char* originalBuffer, @@ -458,7 +458,7 @@ void vader::radamsa::mutations::LineMutations::DuplicateLine( } } -void vader::radamsa::mutations::LineMutations::CopyLineCloseBy( +void vmf::radamsa::mutations::LineMutations::CopyLineCloseBy( StorageEntry* newEntry, const size_t originalSize, const char* originalBuffer, @@ -555,7 +555,7 @@ void vader::radamsa::mutations::LineMutations::CopyLineCloseBy( } } -void vader::radamsa::mutations::LineMutations::RepeatLine( +void vmf::radamsa::mutations::LineMutations::RepeatLine( StorageEntry* newEntry, const size_t originalSize, const char* originalBuffer, @@ -648,7 +648,7 @@ void vader::radamsa::mutations::LineMutations::RepeatLine( } } -void vader::radamsa::mutations::LineMutations::SwapLine( +void vmf::radamsa::mutations::LineMutations::SwapLine( StorageEntry* newEntry, const size_t originalSize, const char* originalBuffer, @@ -778,7 +778,7 @@ void vader::radamsa::mutations::LineMutations::SwapLine( } } -size_t vader::radamsa::mutations::LineMutations::GetRandomLogValue(const size_t maximumValue) +size_t vmf::radamsa::mutations::LineMutations::GetRandomLogValue(const size_t maximumValue) { constexpr size_t minimumValue{2u}; @@ -788,7 +788,7 @@ size_t vader::radamsa::mutations::LineMutations::GetRandomLogValue(const size_t return GetRandomN_Bit(GetRandomValueWithinBounds(0u, maximumValue - minimumValue) + minimumValue); } -size_t vader::radamsa::mutations::LineMutations::GetRandomN_Bit(const size_t n) +size_t vmf::radamsa::mutations::LineMutations::GetRandomN_Bit(const size_t n) { const size_t highValue{(n - 1u) << 1u}; const size_t randomValue{GetRandomValueWithinBounds(0u, highValue)}; @@ -797,7 +797,7 @@ size_t vader::radamsa::mutations::LineMutations::GetRandomN_Bit(const size_t n) return nBitValue; } -void vader::radamsa::mutations::LineMutations::PermuteLine( +void vmf::radamsa::mutations::LineMutations::PermuteLine( StorageEntry* newEntry, const size_t originalSize, const char* originalBuffer, diff --git a/Radamsa/vmf/src/modules/common/mutator/lineMutations.hpp b/Radamsa/vmf/src/modules/common/mutator/lineMutations.hpp index 7b2f447..4b42c79 100644 --- a/Radamsa/vmf/src/modules/common/mutator/lineMutations.hpp +++ b/Radamsa/vmf/src/modules/common/mutator/lineMutations.hpp @@ -1,7 +1,7 @@ /* ============================================================================= * Vader Modular Fuzzer * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. - * + * * * Effort sponsored by the U.S. Government under Other Transaction number * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government @@ -43,7 +43,7 @@ #include "RuntimeException.hpp" -namespace vader::radamsa::mutations +namespace vmf::radamsa::mutations { /** * @brief This module is draws heavily upon the libAFL mutator.c @@ -72,7 +72,7 @@ namespace vader::radamsa::mutations * customized fuzzers for a specific target while taking advantage of * a lot of features that AFL++ already provides. */ -class LineMutations: public vader::radamsa::mutations::MutationBase +class LineMutations: public vmf::radamsa::mutations::MutationBase { public: struct Line diff --git a/Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp b/Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp index 46bbbb1..dffefa8 100644 --- a/Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp +++ b/Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp @@ -5,7 +5,7 @@ #include #include -namespace vader::radamsa::mutations +namespace vmf::radamsa::mutations { class MutationBase { diff --git a/Radamsa/vmf/src/modules/common/mutator/radamsaMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/radamsaMutator.cpp index 308d656..a2c57cc 100644 --- a/Radamsa/vmf/src/modules/common/mutator/radamsaMutator.cpp +++ b/Radamsa/vmf/src/modules/common/mutator/radamsaMutator.cpp @@ -1,7 +1,7 @@ /* ============================================================================= * Vader Modular Fuzzer * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. - * + * * * Effort sponsored by the U.S. Government under Other Transaction number * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government @@ -52,14 +52,14 @@ #include "ModuleFactory.hpp" #include "radamsaMutator.hpp" -namespace vader +namespace vmf { -REGISTER_MODULE(vader::modules::radamsa::RadamsaMutator); +REGISTER_MODULE(vmf::modules::radamsa::RadamsaMutator); } -vader::Module* vader::modules::radamsa::RadamsaMutator::build(std::string name) { return new RadamsaMutator(name); } +vmf::Module* vmf::modules::radamsa::RadamsaMutator::build(std::string name) { return new RadamsaMutator(name); } -void vader::modules::radamsa::RadamsaMutator::SetAlgorithmType(const AlgorithmType algorithmType) +void vmf::modules::radamsa::RadamsaMutator::SetAlgorithmType(const AlgorithmType algorithmType) { switch(algorithmType) { @@ -91,7 +91,7 @@ void vader::modules::radamsa::RadamsaMutator::SetAlgorithmType(const AlgorithmTy } } -void vader::modules::radamsa::RadamsaMutator::registerStorageNeeds(StorageRegistry& registry) +void vmf::modules::radamsa::RadamsaMutator::registerStorageNeeds(StorageRegistry& registry) { testCaseKey_ = registry.registerKey( "TEST_CASE", @@ -103,7 +103,7 @@ void vader::modules::radamsa::RadamsaMutator::registerStorageNeeds(StorageRegist StorageRegistry::READ_ONLY); } -vader::StorageEntry* vader::modules::radamsa::RadamsaMutator::createTestCase(StorageModule& storage, StorageEntry* baseEntry) +void vmf::modules::radamsa::RadamsaMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) { if (baseEntry == nullptr) throw RuntimeException("RadamsaMutator mutate called with null base entry", RuntimeException::OTHER); @@ -115,7 +115,7 @@ vader::StorageEntry* vader::modules::radamsa::RadamsaMutator::createTestCase(Sto if(size <= 0) throw RuntimeException("RadamsaMutator mutate called with zero sized buffer", RuntimeException::USAGE_ERROR); - StorageEntry* newEntry{storage.createNewEntry()}; + switch(algorithmType_) { @@ -181,10 +181,10 @@ vader::StorageEntry* vader::modules::radamsa::RadamsaMutator::createTestCase(Sto break; } - return newEntry; + } -vader::modules::radamsa::RadamsaMutator::AlgorithmType vader::modules::radamsa::RadamsaMutator::stringToType(std::string type) +vmf::modules::radamsa::RadamsaMutator::AlgorithmType vmf::modules::radamsa::RadamsaMutator::stringToType(std::string type) { if(type.compare("ByteMutations_DropByte") == 0) return AlgorithmType::ByteMutations_DropByte; diff --git a/Radamsa/vmf/src/modules/common/mutator/radamsaMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/radamsaMutator.hpp index df1b58e..fc70fe9 100644 --- a/Radamsa/vmf/src/modules/common/mutator/radamsaMutator.hpp +++ b/Radamsa/vmf/src/modules/common/mutator/radamsaMutator.hpp @@ -1,7 +1,7 @@ /* ============================================================================= * Vader Modular Fuzzer * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. - * + * * * Effort sponsored by the U.S. Government under Other Transaction number * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government @@ -37,7 +37,7 @@ #include "lineMutations.hpp" -namespace vader::modules::radamsa +namespace vmf::modules::radamsa { /** * @brief This module is draws heavily upon the libAFL mutator.c @@ -67,8 +67,8 @@ namespace vader::modules::radamsa * a lot of features that AFL++ already provides. */ class RadamsaMutator: public MutatorModule, - public vader::radamsa::mutations::ByteMutations, - public vader::radamsa::mutations::LineMutations + public vmf::radamsa::mutations::ByteMutations, + public vmf::radamsa::mutations::LineMutations { public: enum class AlgorithmType : uint8_t @@ -94,8 +94,8 @@ class RadamsaMutator: public MutatorModule, virtual ~RadamsaMutator() = default; RadamsaMutator(std::string name) noexcept : MutatorModule{name}, - vader::radamsa::mutations::ByteMutations{RANDOM_NUMBER_GENERATOR_}, - vader::radamsa::mutations::LineMutations{RANDOM_NUMBER_GENERATOR_} + vmf::radamsa::mutations::ByteMutations{RANDOM_NUMBER_GENERATOR_}, + vmf::radamsa::mutations::LineMutations{RANDOM_NUMBER_GENERATOR_} {} @@ -106,7 +106,7 @@ class RadamsaMutator: public MutatorModule, virtual void registerStorageNeeds(StorageRegistry& registry); - virtual StorageEntry* createTestCase(StorageModule& storage, StorageEntry* baseEntry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); static Module* build(std::string name); diff --git a/SamplePackage/vmf/src/modules/common/mutator/MyMutator.cpp b/SamplePackage/vmf/src/modules/common/mutator/MyMutator.cpp index f397e68..61204bd 100644 --- a/SamplePackage/vmf/src/modules/common/mutator/MyMutator.cpp +++ b/SamplePackage/vmf/src/modules/common/mutator/MyMutator.cpp @@ -1,7 +1,7 @@ /* ============================================================================= * Vader Modular Fuzzer (VMF) * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. - * + * * * Effort sponsored by the U.S. Government under Other Transaction number * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government @@ -29,7 +29,7 @@ #include "MyMutator.hpp" #include "Logging.hpp" -using namespace vader; +using namespace vmf; /* This will register the mutator module with the VMF module factory, making diff --git a/SamplePackage/vmf/src/modules/common/mutator/MyMutator.hpp b/SamplePackage/vmf/src/modules/common/mutator/MyMutator.hpp index d68f7d1..b115740 100644 --- a/SamplePackage/vmf/src/modules/common/mutator/MyMutator.hpp +++ b/SamplePackage/vmf/src/modules/common/mutator/MyMutator.hpp @@ -1,7 +1,7 @@ /* ============================================================================= * Vader Modular Fuzzer (VMF) * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. - * + * * * Effort sponsored by the U.S. Government under Other Transaction number * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government @@ -32,7 +32,7 @@ #include "MutatorModule.hpp" #include "StorageEntry.hpp" -using namespace vader; +using namespace vmf; class MyMutator : public MutatorModule { diff --git a/dockerfiles/Dockerfile b/dockerfiles/Dockerfile new file mode 100644 index 0000000..54efa7d --- /dev/null +++ b/dockerfiles/Dockerfile @@ -0,0 +1,70 @@ +FROM kalilinux/kali-last-release AS deps + +RUN apt-get update \ + && DEBIAN_FRONTEND="noninteractive" apt-get install -y --no-install-recommends --fix-missing \ + ca-certificates \ + curl \ + gdb \ + git \ + gnupg \ + lsb-release \ + zip + +RUN apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends --fix-missing \ + graphviz \ + clang-16 \ + clang \ + doxygen \ + libcurl4-openssl-dev \ + llvm-16 \ + llvm-16-dev \ + llvm \ + llvm-dev \ + lld \ + python3-dev \ + python3-pip \ + python3-setuptools \ + build-essential \ + cmake + +ENV LLVM_CONFIG=llvm-config-16 + +FROM deps AS aflpp + +# Clone and build AFL++ +RUN set -ex \ + && cd /usr/local/src \ + && git clone --depth 1 -b v4.10c https://github.com/AFLplusplus/AFLplusplus.git \ + && cd AFLplusplus \ + && make all \ + && make install \ + && set +ex + +FROM aflpp AS vmf + +# Clone, build, install VMF +RUN set -ex \ + && cd /usr/local/src \ + && git clone --depth 1 https://github.com/draperlaboratory/vadermodularfuzzer.git VaderModularFuzzer\ + && cd VaderModularFuzzer \ + && mkdir -p build \ + && cd build \ + && cmake -DCMAKE_INSTALL_PREFIX=/usr/local .. \ + && make -j \ + && make install \ + && set +ex + +# Clone, build, install VMFExperimental +RUN set -ex \ + && cd /usr/local/src/ \ + && git clone --depth 1 https://github.com/crusoe112/VmfExperimental.git VmfExperimental\ + && cd VmfExperimental \ + && mkdir build \ + && cd build \ + && cmake -DVMF_INSTALL=/usr/local .. \ + && ls -la /usr/local/include \ + && make && make install \ + && set +ex + +CMD bash diff --git a/dockerfiles/Dockerfile.kali b/dockerfiles/Dockerfile.kali new file mode 100644 index 0000000..54efa7d --- /dev/null +++ b/dockerfiles/Dockerfile.kali @@ -0,0 +1,70 @@ +FROM kalilinux/kali-last-release AS deps + +RUN apt-get update \ + && DEBIAN_FRONTEND="noninteractive" apt-get install -y --no-install-recommends --fix-missing \ + ca-certificates \ + curl \ + gdb \ + git \ + gnupg \ + lsb-release \ + zip + +RUN apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends --fix-missing \ + graphviz \ + clang-16 \ + clang \ + doxygen \ + libcurl4-openssl-dev \ + llvm-16 \ + llvm-16-dev \ + llvm \ + llvm-dev \ + lld \ + python3-dev \ + python3-pip \ + python3-setuptools \ + build-essential \ + cmake + +ENV LLVM_CONFIG=llvm-config-16 + +FROM deps AS aflpp + +# Clone and build AFL++ +RUN set -ex \ + && cd /usr/local/src \ + && git clone --depth 1 -b v4.10c https://github.com/AFLplusplus/AFLplusplus.git \ + && cd AFLplusplus \ + && make all \ + && make install \ + && set +ex + +FROM aflpp AS vmf + +# Clone, build, install VMF +RUN set -ex \ + && cd /usr/local/src \ + && git clone --depth 1 https://github.com/draperlaboratory/vadermodularfuzzer.git VaderModularFuzzer\ + && cd VaderModularFuzzer \ + && mkdir -p build \ + && cd build \ + && cmake -DCMAKE_INSTALL_PREFIX=/usr/local .. \ + && make -j \ + && make install \ + && set +ex + +# Clone, build, install VMFExperimental +RUN set -ex \ + && cd /usr/local/src/ \ + && git clone --depth 1 https://github.com/crusoe112/VmfExperimental.git VmfExperimental\ + && cd VmfExperimental \ + && mkdir build \ + && cd build \ + && cmake -DVMF_INSTALL=/usr/local .. \ + && ls -la /usr/local/include \ + && make && make install \ + && set +ex + +CMD bash From fc8e7489b9394bb125bc9ffcbb29530256c3130c Mon Sep 17 00:00:00 2001 From: Marc Date: Thu, 25 Jul 2024 23:43:47 -0400 Subject: [PATCH 02/31] Fixed errors for SampleMutator --- SamplePackage/vmf/src/modules/common/mutator/MyMutator.cpp | 5 +---- SamplePackage/vmf/src/modules/common/mutator/MyMutator.hpp | 2 +- dockerfiles/Dockerfile | 1 - dockerfiles/Dockerfile.kali | 1 - 4 files changed, 2 insertions(+), 7 deletions(-) diff --git a/SamplePackage/vmf/src/modules/common/mutator/MyMutator.cpp b/SamplePackage/vmf/src/modules/common/mutator/MyMutator.cpp index 61204bd..022d443 100644 --- a/SamplePackage/vmf/src/modules/common/mutator/MyMutator.cpp +++ b/SamplePackage/vmf/src/modules/common/mutator/MyMutator.cpp @@ -97,7 +97,7 @@ void MyMutator::registerStorageNeeds(StorageRegistry& registry) * @return StorageEntry* * @throws RuntimeException if baseEntry has an empty test case buffer. */ -StorageEntry* MyMutator::createTestCase(StorageModule& storage, StorageEntry* baseEntry) +void MyMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) { int inputSize = baseEntry->getBufferSize(testCaseKey); // char* inputBuffer = baseEntry->getBufferPointer(testCaseKey); @@ -111,9 +111,6 @@ StorageEntry* MyMutator::createTestCase(StorageModule& storage, StorageEntry* ba // This doesn't really do anything useful - this is just an // integration demonstration. LOG_INFO << "Not really mutating here, just pretending"; - StorageEntry* newEntry = storage.createNewEntry(); char* outputBuffer = newEntry->allocateBuffer(testCaseKey, 23); strcpy(outputBuffer, "foobar"); - - return newEntry; } diff --git a/SamplePackage/vmf/src/modules/common/mutator/MyMutator.hpp b/SamplePackage/vmf/src/modules/common/mutator/MyMutator.hpp index b115740..3c99c79 100644 --- a/SamplePackage/vmf/src/modules/common/mutator/MyMutator.hpp +++ b/SamplePackage/vmf/src/modules/common/mutator/MyMutator.hpp @@ -43,7 +43,7 @@ class MyMutator : public MutatorModule MyMutator(std::string name); virtual ~MyMutator(); virtual void registerStorageNeeds(StorageRegistry& registry); - virtual StorageEntry* createTestCase(StorageModule& storage, StorageEntry* baseEntry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); private: int testCaseKey; diff --git a/dockerfiles/Dockerfile b/dockerfiles/Dockerfile index 54efa7d..9a44c45 100644 --- a/dockerfiles/Dockerfile +++ b/dockerfiles/Dockerfile @@ -63,7 +63,6 @@ RUN set -ex \ && mkdir build \ && cd build \ && cmake -DVMF_INSTALL=/usr/local .. \ - && ls -la /usr/local/include \ && make && make install \ && set +ex diff --git a/dockerfiles/Dockerfile.kali b/dockerfiles/Dockerfile.kali index 54efa7d..9a44c45 100644 --- a/dockerfiles/Dockerfile.kali +++ b/dockerfiles/Dockerfile.kali @@ -63,7 +63,6 @@ RUN set -ex \ && mkdir build \ && cd build \ && cmake -DVMF_INSTALL=/usr/local .. \ - && ls -la /usr/local/include \ && make && make install \ && set +ex From 72de386959c6ac7b2098f5d49a48d46145f6ced0 Mon Sep 17 00:00:00 2001 From: Marc Date: Wed, 31 Jul 2024 14:20:23 -0400 Subject: [PATCH 03/31] Break flip byte mutator into it's own class for testing --- Radamsa/vmf/src/modules/CMakeLists.txt | 7 +- .../common/mutator/.byteMutations.hpp.swp | Bin 0 -> 16384 bytes .../common/mutator/RadamsaFlipByteMutator.cpp | 142 ++++++++++++++++++ .../common/mutator/RadamsaFlipByteMutator.hpp | 56 +++++++ 4 files changed, 202 insertions(+), 3 deletions(-) create mode 100644 Radamsa/vmf/src/modules/common/mutator/.byteMutations.hpp.swp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp diff --git a/Radamsa/vmf/src/modules/CMakeLists.txt b/Radamsa/vmf/src/modules/CMakeLists.txt index e951265..a154abb 100644 --- a/Radamsa/vmf/src/modules/CMakeLists.txt +++ b/Radamsa/vmf/src/modules/CMakeLists.txt @@ -29,9 +29,10 @@ # Create Radamsa library add_library(Radamsa SHARED - common/mutator/byteMutations.cpp - common/mutator/radamsaMutator.cpp - common/mutator/lineMutations.cpp +# common/mutator/byteMutations.cpp +# common/mutator/radamsaMutator.cpp +# common/mutator/lineMutations.cpp + common/mutator/RadamsaFlipByteMutator.cpp ) # Build-time dependencies for Radamsa diff --git a/Radamsa/vmf/src/modules/common/mutator/.byteMutations.hpp.swp b/Radamsa/vmf/src/modules/common/mutator/.byteMutations.hpp.swp new file mode 100644 index 0000000000000000000000000000000000000000..b463aec5e70344c939c65bc0133902532d847033 GIT binary patch literal 16384 zcmeHNUu+yl8DB~%6cRwt0^)&wI1o9BeP=s`l8YUDvCpxE?O10!Y51csw>x_`cz0*n zoxSrVO7g-(C3rwo(5HfEB!mP~kq{yhLX{}uk=H(e=o6>{@qk48z(4W(X7}Pd<2I?( zhm!8fKb`kx=G*W4&G%<^Zdy|pR@UfLW!k~@e#d$FLpS}SUurnsiN~BB5h(upPS@S` zyUrb}8;NcwA`Dg3u69GedLi^1yRl4EC?g|+YEyV3OoeSr6So>_FAHQ^b#)l(s2XNQ z7@bsGeIwWSf2E_e(uw0cX<4?H47}ADIP9F9nVw=6j*NYrKKOy{w>lxE{Urk>10@3` z10@3`10@3`10@4*DF#e@pK}8i-&a`uh2ryV`##@Z+|LxBU)=)_>;lU`18{&_?{=J@0Xx7) zfy2Nd;9n0q&Od<{f#-mmz%#)2fg8XzpbvZocog_E4EQPV6F>q2_z3V2@TYe=&M$!{ zffhi(A0BX=9|2zls=!~~;W$44`oJ>q0Px)X-~@OASOOM-S>R*9E7%Nq8F(J}4)AT@ zae#nFfJ4Ab*iiWe@FdUy7J&s|3OEG32)=&~Fz;Vy?s3u3<>FL>p;TRwmkr^pgbK58 zQ%Y|o^5pKs0bSjWNRE?ER9i(NIGg#tOb+T-h#c*>iRX-V-ozOT(Uy(KB>m$Q$)5c$ z@6*-FqoqK_XK@B&{2;wmWXQ z%mG%6 z533nxtw6ao=c?ldB28&TP>u3t!Wo}hEy)k{)N1zl4j*kuWvexnFdSzz?2{K2X+Yi{!2=V?&UDGg5J&MC3~9DbpF2 zlXJD2tKw0HJd)VXb=+s94N1rUe{A}C4YOvYHzG{#|!DO!M%NHZNnGgH&2CTFH* zrkI~N$WjL3fY(=~YbsO^0{6$5oG__yMcQ7Zq;>kk7y6$13kre@WO{))e6PK1HPvmUa znGZXYsdV=SoGBs;3&cuRCxI9UrWaCud>h1faLw`$J-=7;_&E<~|36~!4G zj9kp4ky}Nj8ALBLO@l;3p)?(xJKi>e(5hQx23WvPOidq-cYA;c+Nh4E1Iu*&EeD$% zWE~spti*gPQPKxZh{ODlA}in}qL(t0U4_ZZVnh-T4yha@9oDn7@MF7fI zOOsd@94V-$v4M)5G5N^j*ic(DiwurXHf%0H{O)fbF6eoiQ?1g4wIz-?JF|FFjG7+` zBs`ZhGR?hlSDxPIi&RMGHdZH3R;DI(G8te75xAT>**VhK+a1lC`}=ZOvvwlT@XI34 zfq7H~K3H0z6`znKCn$x_S-C|@Zb#Xu)Uir zMyUM(ZP>~;$eD#cuinAdqfjRj%LAlk`&(w6wCd-q_rv zrSnay(?-3ywX(3iT5r!(Ow=zQ)SGJbVZ*Nh3{SsZQH=7W5>9plU zqg8g1H`x0WmjzhV6G?)q$2Eo}Sl2CRv%afRlPJhVSA-Cc>|nKne^7!I3aCOx&r6@5 z1)LmN$~YQPoDwW>_%QA<5)m?soz-q$ODxSSZ7IQ&Y--;?5!`81A$x##f+PYCZcq%M zll!XR1lZwcL5aP}1-}W?LC4o%U%)qb!qN`xYV{AY+-JqoLa`c~W6OLZz1x)Vvr#Cj zm?lKK@>vdx!o7?An-1fB~R5Wy+aR3w~KkY2f-BHrQuOsn>>%2DvkSR=rcOmh>FR1^vYYmJ1>QO<>( zGx(qofpWEbrePxRzfR|wAA1$yL`eN^J*nu2%y!@BWsgLBp+4) zA(_juOEctB)*FYpk?dHbA!fM&_U7xhJyzJDEI}#B4Z3)0dgjrMNh~=|O-@ZsO@k%V zlko8R+SY;<$z1FWuhmn-Dv6hUe0F%R9>weYm_Y!huEZc^d0gHx1+ zEn6m8*euq!^GN!5DX>ch{%&u5GwvS4>Skt|S4k(WJ_~qH!*O=n#G-VE7VSV<6)mhq zxL{6jI=1v(;95*;eEMA=GuV|as>U0cl;`Fge*gaz-k~4HdpE!T4}RbOJ>K_!2mA(j z2FQRlU<~*V-uwRzyafCjcnZ+KB0#_+z=Oaau^(^?_$DBMIxr861NQ?jU~k}A;A_B_ zfy=--;0W*v_6L3o+yrg_*8v|m3p@<`75e@P_%84?@GamIz!8A=57H z9;N(t-L8@I_hqbWk5P?=_j|7%*y|cyy@uy%gY84<6;B@QzU71L_Fgp*uV?qRfg9LW!4A;9I)6 + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaFlipByteMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaFlipByteMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaFlipByteMutator::build(std::string name) +{ + return new RadamsaFlipByteMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaFlipByteMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaFlipByteMutator::RadamsaFlipByteMutator object + * + * @param name The of the name module + */ +RadamsaFlipByteMutator::RadamsaFlipByteMutator(std::string name) : + MutatorModule(name) +{ + rand.randInit(); +} + +/** + * @brief Destroy the RadamsaFlipByteMutator::RadamsaFlipByteMutator object + * + */ +RadamsaFlipByteMutator::~RadamsaFlipByteMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaFlipByteMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +void RadamsaFlipByteMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + // Consume the original buffer by flipping a byte and appending a null-terminator to the end. + + constexpr size_t minimumSize{1u}; + int originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBuffer(testCaseKey); + + if (originalSize < minimumSize) + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; + + if (minimumSeedIndex > originalSize - 1u) + throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + + if (originalBuffer == nullptr) + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + + // The new buffer size will contain one additional element since we are appending a null-terminator to the end. + + const size_t newBufferSize{originalSize + 1u}; + + // Allocate the new buffer, set it's elements to those of the original buffer, and append a null-terminator to the end. + + char* newBuffer{newEntry->allocateBuffer(testCaseKey, static_cast(newBufferSize))}; + memset(newBuffer, 0u, newBufferSize); + memcpy(newBuffer, originalBuffer, originalSize); + + // Select a random byte to drop from the original buffer. + + const size_t lower{0u}; + const size_t upper{originalSize - 1u}; + const size_t maximumRandomIndexValue{originalSize - minimumSeedIndex}; + const size_t randomIndexToFlip{ + std::clamp( + GetRandomValueWithinBounds( + lower, + maximumRandomIndexValue) + minimumSeedIndex, + lower, + upper)}; + + // Select a random bit to flip from the random byte. + // When computing the random bit shift, + // we add 1 so that a maximum number of 8 bit shift operations can be performed against a char containing the value 0x01. + + const size_t randomBitShift{GetRandomValueWithinBounds(0u, std::numeric_limits::digits + 1u)}; + const char randomMaskedBit{static_cast(0x01u << randomBitShift)}; + + // Flip the random byte by performing an XOR operation with a random masked bit. + newBuffer[randomIndexToFlip] ^= randomMaskedBit; +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp new file mode 100644 index 0000000..4e50c56 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp @@ -0,0 +1,56 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaFlipByteMutator: public MutatorModule +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaFlipByteMutator(); + virtual ~RadamsaFlipByteMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand rand; +}; +} \ No newline at end of file From d6d665c7c0cf8ea51ea38e998ce024297d39f734 Mon Sep 17 00:00:00 2001 From: Marc Date: Wed, 31 Jul 2024 20:20:38 -0400 Subject: [PATCH 04/31] Fixed .hpp constructor defnition --- .../src/modules/common/mutator/RadamsaFlipByteMutator.cpp | 6 +++--- .../src/modules/common/mutator/RadamsaFlipByteMutator.hpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp index e5fdcf2..3661ab2 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp @@ -64,8 +64,7 @@ void RadamsaFlipByteMutator::init(ConfigInterface& config) * * @param name The of the name module */ -RadamsaFlipByteMutator::RadamsaFlipByteMutator(std::string name) : - MutatorModule(name) +RadamsaFlipByteMutator::RadamsaFlipByteMutator(std::string name) : MutatorModule(name) { rand.randInit(); } @@ -95,8 +94,9 @@ void RadamsaFlipByteMutator::mutateTestCase(StorageModule& storage, StorageEntry // Consume the original buffer by flipping a byte and appending a null-terminator to the end. constexpr size_t minimumSize{1u}; + const size_t minimumSeedIndex{0u}; int originalSize = baseEntry->getBufferSize(testCaseKey); - char* originalBuffer = baseEntry->getBuffer(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); if (originalSize < minimumSize) throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp index 4e50c56..af1cf3c 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp @@ -45,7 +45,7 @@ class RadamsaFlipByteMutator: public MutatorModule static Module* build(std::string name); virtual void init(ConfigInterface& config); - RadamsaFlipByteMutator(); + RadamsaFlipByteMutator(std::string name); virtual ~RadamsaFlipByteMutator(); virtual void registerStorageNeeds(StorageRegistry& registry); virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); From 7d929317030563d8363e8fba7e176374e6e39dfe Mon Sep 17 00:00:00 2001 From: Marc Date: Wed, 31 Jul 2024 20:29:43 -0400 Subject: [PATCH 05/31] Import mutationBase --- .../vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp index af1cf3c..33beff4 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp @@ -31,6 +31,7 @@ #include "MutatorModule.hpp" #include "StorageEntry.hpp" #include "RuntimeException.hpp" +#include "mutationBase.hpp" #include "VmfRand.hpp" namespace vmf From 190978e2830af5a5b3bb1c0ebc1c45d7301317ba Mon Sep 17 00:00:00 2001 From: Marc Date: Wed, 31 Jul 2024 20:32:57 -0400 Subject: [PATCH 06/31] Changed MutationBase scope to vmf namespace --- Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp b/Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp index dffefa8..a520580 100644 --- a/Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp +++ b/Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp @@ -5,7 +5,7 @@ #include #include -namespace vmf::radamsa::mutations +namespace vmf { class MutationBase { From 47f3a29fc46a69d518c74b3c464804d39c72458e Mon Sep 17 00:00:00 2001 From: Marc Date: Wed, 31 Jul 2024 20:40:08 -0400 Subject: [PATCH 07/31] Inherit from MutationBase --- .../vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp index 33beff4..4b98924 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp @@ -39,7 +39,7 @@ namespace vmf /** * */ -class RadamsaFlipByteMutator: public MutatorModule +class RadamsaFlipByteMutator: public MutatorModule, public MutationBase { public: From e2829549860ccdc2a557145d965470dbdc65301d Mon Sep 17 00:00:00 2001 From: Marc Date: Wed, 31 Jul 2024 22:05:00 -0400 Subject: [PATCH 08/31] Fixes for MutationBase inheritance --- .../vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp | 2 +- .../vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp index 3661ab2..4c0f085 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp @@ -64,7 +64,7 @@ void RadamsaFlipByteMutator::init(ConfigInterface& config) * * @param name The of the name module */ -RadamsaFlipByteMutator::RadamsaFlipByteMutator(std::string name) : MutatorModule(name) +RadamsaFlipByteMutator::RadamsaFlipByteMutator(std::string name) : MutatorModule(name), MutationBase(rand) { rand.randInit(); } diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp index 4b98924..e3575ad 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp @@ -46,7 +46,7 @@ class RadamsaFlipByteMutator: public MutatorModule, public MutationBase static Module* build(std::string name); virtual void init(ConfigInterface& config); - RadamsaFlipByteMutator(std::string name); + RadamsaFlipByteMutator(std::string name) : MutatorModule(name), MutationBase(rand); virtual ~RadamsaFlipByteMutator(); virtual void registerStorageNeeds(StorageRegistry& registry); virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); From 7071b4beb282ca91d0ee87301fdc9ca90b3b2a63 Mon Sep 17 00:00:00 2001 From: Marc Date: Thu, 1 Aug 2024 11:43:54 -0400 Subject: [PATCH 09/31] Changed mutationBase to be a static class --- .../common/mutator/RadamsaFlipByteMutator.cpp | 15 ++++++------ .../common/mutator/RadamsaFlipByteMutator.hpp | 2 +- .../modules/common/mutator/mutationBase.hpp | 24 ++----------------- 3 files changed, 11 insertions(+), 30 deletions(-) diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp index 4c0f085..a6c9564 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp @@ -64,7 +64,7 @@ void RadamsaFlipByteMutator::init(ConfigInterface& config) * * @param name The of the name module */ -RadamsaFlipByteMutator::RadamsaFlipByteMutator(std::string name) : MutatorModule(name), MutationBase(rand) +RadamsaFlipByteMutator::RadamsaFlipByteMutator(std::string name) : MutatorModule(name) { rand.randInit(); } @@ -124,17 +124,18 @@ void RadamsaFlipByteMutator::mutateTestCase(StorageModule& storage, StorageEntry const size_t maximumRandomIndexValue{originalSize - minimumSeedIndex}; const size_t randomIndexToFlip{ std::clamp( - GetRandomValueWithinBounds( - lower, - maximumRandomIndexValue) + minimumSeedIndex, - lower, - upper)}; + rand->randBetween( + lower, + maximumRandomIndexValue + ) + minimumSeedIndex, + lower, + upper)}; // Select a random bit to flip from the random byte. // When computing the random bit shift, // we add 1 so that a maximum number of 8 bit shift operations can be performed against a char containing the value 0x01. - const size_t randomBitShift{GetRandomValueWithinBounds(0u, std::numeric_limits::digits + 1u)}; + const size_t randomBitShift{rand->randBetween(0u, std::numeric_limits::digits + 1u)}; const char randomMaskedBit{static_cast(0x01u << randomBitShift)}; // Flip the random byte by performing an XOR operation with a random masked bit. diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp index e3575ad..b1cc751 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp @@ -46,7 +46,7 @@ class RadamsaFlipByteMutator: public MutatorModule, public MutationBase static Module* build(std::string name); virtual void init(ConfigInterface& config); - RadamsaFlipByteMutator(std::string name) : MutatorModule(name), MutationBase(rand); + RadamsaFlipByteMutator(std::string name) : MutatorModule(name) virtual ~RadamsaFlipByteMutator(); virtual void registerStorageNeeds(StorageRegistry& registry); virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); diff --git a/Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp b/Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp index a520580..86bcccb 100644 --- a/Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp +++ b/Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp @@ -4,32 +4,15 @@ #include #include #include +#include "VmfRand.hpp" namespace vmf { class MutationBase { public: - MutationBase() = delete; - virtual ~MutationBase() = default; - MutationBase(const MutationBase&) = delete; - MutationBase(MutationBase&&) = delete; - - MutationBase& operator=(const MutationBase&) = delete; - MutationBase& operator=(MutationBase&&) = delete; - -protected: - MutationBase(std::default_random_engine& randomNumberGenerator) : RANDOM_NUMBER_GENERATOR_{randomNumberGenerator} {} - - size_t GetRandomValueWithinBounds(const size_t lower, const size_t upper) noexcept - { - std::uniform_int_distribution distribution(lower, upper); - - return distribution(RANDOM_NUMBER_GENERATOR_); - } - - size_t GetRandomByteRepetitionLength() noexcept + static size_t GetRandomByteRepetitionLength(vmf::VmfRand rand) noexcept { constexpr size_t MINIMUM_UPPER_LIMIT{0x2u}; constexpr size_t MAXIMUM_UPPER_LIMIT{0x20000u}; @@ -49,8 +32,5 @@ class MutationBase return GetRandomValueWithinBounds(0u, randomUpperLimit) + 1u; // We add one to the return value in order to account for the case where the random upper value is zero. } - std::default_random_engine& RANDOM_NUMBER_GENERATOR_; - -private: }; } \ No newline at end of file From 96e986fa36047718d63f758dcaa41b8ea971df87 Mon Sep 17 00:00:00 2001 From: Marc Date: Thu, 1 Aug 2024 11:45:45 -0400 Subject: [PATCH 10/31] Fixed rand calls --- .../vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp index a6c9564..13eb571 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp @@ -124,7 +124,7 @@ void RadamsaFlipByteMutator::mutateTestCase(StorageModule& storage, StorageEntry const size_t maximumRandomIndexValue{originalSize - minimumSeedIndex}; const size_t randomIndexToFlip{ std::clamp( - rand->randBetween( + rand.randBetween( lower, maximumRandomIndexValue ) + minimumSeedIndex, @@ -135,7 +135,7 @@ void RadamsaFlipByteMutator::mutateTestCase(StorageModule& storage, StorageEntry // When computing the random bit shift, // we add 1 so that a maximum number of 8 bit shift operations can be performed against a char containing the value 0x01. - const size_t randomBitShift{rand->randBetween(0u, std::numeric_limits::digits + 1u)}; + const size_t randomBitShift{rand.randBetween(0u, std::numeric_limits::digits + 1u)}; const char randomMaskedBit{static_cast(0x01u << randomBitShift)}; // Flip the random byte by performing an XOR operation with a random masked bit. From baf8500af5681842e49979446a2b4c01b6594013 Mon Sep 17 00:00:00 2001 From: Marc Date: Thu, 1 Aug 2024 11:48:32 -0400 Subject: [PATCH 11/31] Updated mutationBase to use vmf::rand --- Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp b/Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp index 86bcccb..684959a 100644 --- a/Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp +++ b/Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp @@ -17,7 +17,7 @@ class MutationBase constexpr size_t MINIMUM_UPPER_LIMIT{0x2u}; constexpr size_t MAXIMUM_UPPER_LIMIT{0x20000u}; - size_t randomStop{GetRandomValueWithinBounds(0u, MINIMUM_UPPER_LIMIT)}; + size_t randomStop{rand.randBetween(0u, MINIMUM_UPPER_LIMIT)}; size_t randomUpperLimit{MINIMUM_UPPER_LIMIT}; while(randomStop != 0u) @@ -26,10 +26,10 @@ class MutationBase break; randomUpperLimit <<= 1u; - randomStop = GetRandomValueWithinBounds(0u, MINIMUM_UPPER_LIMIT); + randomStop = rand.randBetween(0u, MINIMUM_UPPER_LIMIT); } - return GetRandomValueWithinBounds(0u, randomUpperLimit) + 1u; // We add one to the return value in order to account for the case where the random upper value is zero. + return rand.randBetween(0u, randomUpperLimit) + 1u; // We add one to the return value in order to account for the case where the random upper value is zero. } }; From 3902b7b867aa0d2267aa2013394eb37019e3c177 Mon Sep 17 00:00:00 2001 From: Marc Date: Thu, 1 Aug 2024 11:50:16 -0400 Subject: [PATCH 12/31] Fixed syntax error in flipbytemutator --- .../vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp index b1cc751..9e63948 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp @@ -46,7 +46,7 @@ class RadamsaFlipByteMutator: public MutatorModule, public MutationBase static Module* build(std::string name); virtual void init(ConfigInterface& config); - RadamsaFlipByteMutator(std::string name) : MutatorModule(name) + RadamsaFlipByteMutator(std::string name) : MutatorModule(name); virtual ~RadamsaFlipByteMutator(); virtual void registerStorageNeeds(StorageRegistry& registry); virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); From 021ca81ae02c559607b061b01b0f852523f42d3d Mon Sep 17 00:00:00 2001 From: Marc Date: Thu, 1 Aug 2024 11:51:40 -0400 Subject: [PATCH 13/31] Fixed errors in RadamsaFlipByteMutator.hpp --- .../vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp index 9e63948..4b98924 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp @@ -46,7 +46,7 @@ class RadamsaFlipByteMutator: public MutatorModule, public MutationBase static Module* build(std::string name); virtual void init(ConfigInterface& config); - RadamsaFlipByteMutator(std::string name) : MutatorModule(name); + RadamsaFlipByteMutator(std::string name); virtual ~RadamsaFlipByteMutator(); virtual void registerStorageNeeds(StorageRegistry& registry); virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); From 6acb487bd7f677e039835ea733c05ce5fd2a44bc Mon Sep 17 00:00:00 2001 From: Marc Date: Fri, 2 Aug 2024 18:41:50 -0400 Subject: [PATCH 14/31] Added drop byte mutator --- Radamsa/vmf/src/modules/CMakeLists.txt | 1 + .../common/mutator/RadamsaDropByteMutator.cpp | 144 ++++++++++++++++++ .../common/mutator/RadamsaDropByteMutator.hpp | 57 +++++++ 3 files changed, 202 insertions(+) create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaDropByteMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaDropByteMutator.hpp diff --git a/Radamsa/vmf/src/modules/CMakeLists.txt b/Radamsa/vmf/src/modules/CMakeLists.txt index a154abb..e68b8d8 100644 --- a/Radamsa/vmf/src/modules/CMakeLists.txt +++ b/Radamsa/vmf/src/modules/CMakeLists.txt @@ -32,6 +32,7 @@ add_library(Radamsa SHARED # common/mutator/byteMutations.cpp # common/mutator/radamsaMutator.cpp # common/mutator/lineMutations.cpp + common/mutator/RadamsaDropByteMutator.cpp common/mutator/RadamsaFlipByteMutator.cpp ) diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaDropByteMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaDropByteMutator.cpp new file mode 100644 index 0000000..6125fc8 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaDropByteMutator.cpp @@ -0,0 +1,144 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaDropByteMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaDropByteMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaDropByteMutator::build(std::string name) +{ + return new RadamsaDropByteMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaDropByteMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaDropByteMutator::RadamsaDropByteMutator object + * + * @param name The of the name module + */ +RadamsaDropByteMutator::RadamsaDropByteMutator(std::string name) : MutatorModule(name) +{ + rand.randInit(); +} + +/** + * @brief Destroy the RadamsaDropByteMutator::RadamsaDropByteMutator object + * + */ +RadamsaDropByteMutator::~RadamsaDropByteMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaDropByteMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +void RadamsaDropByteMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + // Consume the original buffer by dropping a byte and appending a null-terminator to the end. + + constexpr size_t minimumSize{1u}; + const size_t minimumSeedIndex{0u}; + int originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); + + if (originalSize < minimumSize) + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; + + if (minimumSeedIndex > originalSize - 1u) + throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + + if (originalBuffer == nullptr) + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + + // The new buffer will contain one less byte, but a null-terminator will be appended to the end; therefore, the sizes will be equal. + + const size_t newBufferSize{originalSize}; + + // Allocate the new buffer and set it's elements to zero. + + char* newBuffer{newEntry->allocateBuffer(testCaseKey, newBufferSize)}; + memset(newBuffer, 0u, newBufferSize); + + // Select a random byte to drop from the original buffer. + + const size_t lower{0u}; + const size_t upper{originalSize - 1u}; + const size_t maximumRandomIndexValue{originalSize - minimumSeedIndex}; + const size_t randomIndexToDrop{ + std::clamp( + rand.randBetween( + lower, + maximumRandomIndexValue) + minimumSeedIndex, + lower, + upper)}; + + // Copy data from the original buffer into the new buffer, but exclude the random byte. + // The last element in the new buffer is skipped since it was implicitly set to zero during allocation. + + for (size_t sourceIndex{0u}, destinationIndex{0u}; sourceIndex < originalSize; ++sourceIndex) + { + if (sourceIndex != randomIndexToDrop) + { + newBuffer[destinationIndex] = originalBuffer[sourceIndex]; + + ++destinationIndex; + } + } +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaDropByteMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaDropByteMutator.hpp new file mode 100644 index 0000000..456a257 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaDropByteMutator.hpp @@ -0,0 +1,57 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "mutationBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaDropByteMutator: public MutatorModule, public MutationBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaDropByteMutator(std::string name); + virtual ~RadamsaDropByteMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand rand; +}; +} \ No newline at end of file From 0d8594d940de7783e9d5cbf186a46acae6f71cda Mon Sep 17 00:00:00 2001 From: Marc Date: Wed, 14 Aug 2024 12:33:51 -0400 Subject: [PATCH 15/31] Added InsertByte Mutator --- Radamsa/vmf/src/modules/CMakeLists.txt | 1 + .../mutator/RadamsaInsertByteMutator.cpp | 148 ++++++++++++++++++ .../mutator/RadamsaInsertByteMutator.hpp | 57 +++++++ 3 files changed, 206 insertions(+) create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaInsertByteMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaInsertByteMutator.hpp diff --git a/Radamsa/vmf/src/modules/CMakeLists.txt b/Radamsa/vmf/src/modules/CMakeLists.txt index e68b8d8..d78b756 100644 --- a/Radamsa/vmf/src/modules/CMakeLists.txt +++ b/Radamsa/vmf/src/modules/CMakeLists.txt @@ -34,6 +34,7 @@ add_library(Radamsa SHARED # common/mutator/lineMutations.cpp common/mutator/RadamsaDropByteMutator.cpp common/mutator/RadamsaFlipByteMutator.cpp + common/mutator/RadamsaInsertByteMutator.cpp ) # Build-time dependencies for Radamsa diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaInsertByteMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaInsertByteMutator.cpp new file mode 100644 index 0000000..837c64b --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaInsertByteMutator.cpp @@ -0,0 +1,148 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaInsertByteMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaInsertByteMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaInsertByteMutator::build(std::string name) +{ + return new RadamsaInsertByteMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaInsertByteMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaInsertByteMutator::RadamsaInsertByteMutator object + * + * @param name The of the name module + */ +RadamsaInsertByteMutator::RadamsaInsertByteMutator(std::string name) : MutatorModule(name) +{ + rand.randInit(); +} + +/** + * @brief Destroy the RadamsaInsertByteMutator::RadamsaInsertByteMutator object + * + */ +RadamsaInsertByteMutator::~RadamsaInsertByteMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaInsertByteMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +void RadamsaInsertByteMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + // Consume the original buffer by inserting a byte and appending a null-terminator to the end. + + constexpr size_t minimumSize{1u}; + const size_t minimumSeedIndex{0u}; + int originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); + + + if (originalSize < minimumSize) + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; + + if (minimumSeedIndex > originalSize - 1u) + throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + + if (originalBuffer == nullptr) + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + + // The new buffer size will contain two additional elements since we are inserting a random byte and appending a null-terminator to the end. + + const size_t newBufferSize{originalSize + 2u}; + + // Allocate the new buffer and set it's elements to zero. + + char* newBuffer{newEntry->allocateBuffer(testCaseKey, static_cast(newBufferSize))}; + memset(newBuffer, 0u, newBufferSize); + + // Select a random index from which the new byte will be inserted. + + const size_t lower{0u}; + const size_t upper{originalSize - 1u}; + const size_t maximumRandomIndexValue{originalSize - minimumSeedIndex}; + const size_t randomInsertionIndex{ + std::clamp( + rand.randBetween( + lower, + maximumRandomIndexValue + ) + minimumSeedIndex, + lower, + upper + ) + }; + + // Copy data from the original buffer into the new buffer, but insert a random byte. + // The last element in the new buffer is skipped since it was implicitly set to zero during allocation. + + for (size_t sourceIndex{0u}, destinationIndex{0u}; sourceIndex < originalSize; ++sourceIndex) + { + newBuffer[destinationIndex] = originalBuffer[sourceIndex]; + + if (sourceIndex == randomInsertionIndex) + newBuffer[++destinationIndex] = static_cast(rand.randBetween(0u, std::numeric_limits::max())); + + ++destinationIndex; + } +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaInsertByteMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaInsertByteMutator.hpp new file mode 100644 index 0000000..c279895 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaInsertByteMutator.hpp @@ -0,0 +1,57 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "mutationBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaInsertByteMutator: public MutatorModule, public MutationBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaInsertByteMutator(std::string name); + virtual ~RadamsaInsertByteMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand rand; +}; +} \ No newline at end of file From 238d7c74936d81befd27eab5b554f4211180e33d Mon Sep 17 00:00:00 2001 From: Marc Date: Wed, 14 Aug 2024 12:49:28 -0400 Subject: [PATCH 16/31] Updated original size type --- .../vmf/src/modules/common/mutator/RadamsaDropByteMutator.cpp | 2 +- .../vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp | 2 +- .../vmf/src/modules/common/mutator/RadamsaInsertByteMutator.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaDropByteMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaDropByteMutator.cpp index 6125fc8..2651460 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaDropByteMutator.cpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaDropByteMutator.cpp @@ -95,7 +95,7 @@ void RadamsaDropByteMutator::mutateTestCase(StorageModule& storage, StorageEntry constexpr size_t minimumSize{1u}; const size_t minimumSeedIndex{0u}; - int originalSize = baseEntry->getBufferSize(testCaseKey); + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); if (originalSize < minimumSize) diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp index 13eb571..d56ba99 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp @@ -95,7 +95,7 @@ void RadamsaFlipByteMutator::mutateTestCase(StorageModule& storage, StorageEntry constexpr size_t minimumSize{1u}; const size_t minimumSeedIndex{0u}; - int originalSize = baseEntry->getBufferSize(testCaseKey); + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); if (originalSize < minimumSize) diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaInsertByteMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaInsertByteMutator.cpp index 837c64b..3596238 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaInsertByteMutator.cpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaInsertByteMutator.cpp @@ -95,7 +95,7 @@ void RadamsaInsertByteMutator::mutateTestCase(StorageModule& storage, StorageEnt constexpr size_t minimumSize{1u}; const size_t minimumSeedIndex{0u}; - int originalSize = baseEntry->getBufferSize(testCaseKey); + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); From 559fa4d7c1ce0a78883c13a2060225d510ad0c85 Mon Sep 17 00:00:00 2001 From: Marc Date: Wed, 14 Aug 2024 13:36:24 -0400 Subject: [PATCH 17/31] Added repeat byte mutator --- Radamsa/vmf/src/modules/CMakeLists.txt | 1 + .../mutator/RadamsaRepeatByteMutator.cpp | 154 ++++++++++++++++++ .../mutator/RadamsaRepeatByteMutator.hpp | 57 +++++++ dockerfiles/Dockerfile | 10 ++ dockerfiles/Dockerfile.kali | 10 ++ 5 files changed, 232 insertions(+) create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteMutator.hpp diff --git a/Radamsa/vmf/src/modules/CMakeLists.txt b/Radamsa/vmf/src/modules/CMakeLists.txt index d78b756..ea8fd54 100644 --- a/Radamsa/vmf/src/modules/CMakeLists.txt +++ b/Radamsa/vmf/src/modules/CMakeLists.txt @@ -35,6 +35,7 @@ add_library(Radamsa SHARED common/mutator/RadamsaDropByteMutator.cpp common/mutator/RadamsaFlipByteMutator.cpp common/mutator/RadamsaInsertByteMutator.cpp + common/mutator/RadamsaRepeatByteMutator.cpp ) # Build-time dependencies for Radamsa diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteMutator.cpp new file mode 100644 index 0000000..10868e5 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteMutator.cpp @@ -0,0 +1,154 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaRepeatByteMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaRepeatByteMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaRepeatByteMutator::build(std::string name) +{ + return new RadamsaRepeatByteMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaRepeatByteMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaRepeatByteMutator::RadamsaRepeatByteMutator object + * + * @param name The of the name module + */ +RadamsaRepeatByteMutator::RadamsaRepeatByteMutator(std::string name) : MutatorModule(name) +{ + rand.randInit(); +} + +/** + * @brief Destroy the RadamsaRepeatByteMutator::RadamsaRepeatByteMutator object + * + */ +RadamsaRepeatByteMutator::~RadamsaRepeatByteMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaRepeatByteMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +void RadamsaRepeatByteMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + // Consume the original buffer by repeating a byte a random number of times and appending a null-terminator to the end. + + constexpr size_t minimumSize{1u}; + const size_t minimumSeedIndex{0u}; + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); + + if (originalSize < minimumSize) + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; + + if (minimumSeedIndex > originalSize - 1u) + throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + + if (originalBuffer == nullptr) + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + + // The new buffer size will contain a random number of additional elements since we are repeating a random byte. + // Furthermore, it will contain one more element since we are appending a null-terminator to the end. + + const size_t numberOfRandomByteRepetitions{GetRandomByteRepetitionLength(rand)}; + const size_t newBufferSize{originalSize + numberOfRandomByteRepetitions + 1u}; + + // Allocate the new buffer and set it's elements to zero. + + char* newBuffer{newEntry->allocateBuffer(testCaseKey, static_cast(newBufferSize))}; + memset(newBuffer, 0u, newBufferSize); + + // Select a random index from which the new bytes will be repeated. + + const size_t lower{0u}; + const size_t upper{originalSize - 1u}; + const size_t maximumRandomIndexValue{originalSize - minimumSeedIndex}; + const size_t randomByteRepetitionIndex{ + std::clamp( + rand.randBetween( + lower, + maximumRandomIndexValue) + minimumSeedIndex, + lower, + upper + ) + }; + + // Copy data from the original buffer into the new buffer, but repeat the target byte. + // The last element in the new buffer is skipped since it was implicitly set to zero during allocation. + + for (size_t sourceIndex{0u}, destinationIndex{0u}; sourceIndex < originalSize; ++sourceIndex) + { + if (sourceIndex == randomByteRepetitionIndex) + { + memset(&newBuffer[destinationIndex], originalBuffer[sourceIndex], numberOfRandomByteRepetitions + 1u); + + ++destinationIndex += numberOfRandomByteRepetitions; + } + else + { + newBuffer[destinationIndex] = originalBuffer[sourceIndex]; + + ++destinationIndex; + } + } +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteMutator.hpp new file mode 100644 index 0000000..25b9b7f --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteMutator.hpp @@ -0,0 +1,57 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "mutationBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaRepeatByteMutator: public MutatorModule, public MutationBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaRepeatByteMutator(std::string name); + virtual ~RadamsaRepeatByteMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand rand; +}; +} \ No newline at end of file diff --git a/dockerfiles/Dockerfile b/dockerfiles/Dockerfile index 9a44c45..b9d0f6d 100644 --- a/dockerfiles/Dockerfile +++ b/dockerfiles/Dockerfile @@ -66,4 +66,14 @@ RUN set -ex \ && make && make install \ && set +ex +# Create experimental config file +RUN set -ex \ + && cd /usr/local/test/config \ + && cp basicModules.yaml experimentalModules.yaml \ + && echo '\n - className: RadamsaDropByteMutator' >> experimentalModules.yaml \ + && echo ' - className: RadamsaFlipByteMutator' >> experimentalModules.yaml \ + && echo ' - className: RadamsaInsertByteMutator' >> experimentalModules.yaml \ + && echo ' - className: RadamsaRepeatByteMutator' >> experimentalModules.yaml \ + && set +ex + CMD bash diff --git a/dockerfiles/Dockerfile.kali b/dockerfiles/Dockerfile.kali index 9a44c45..4e91616 100644 --- a/dockerfiles/Dockerfile.kali +++ b/dockerfiles/Dockerfile.kali @@ -66,4 +66,14 @@ RUN set -ex \ && make && make install \ && set +ex +# Create experimental config file +RUN set -ex \ + && cd /usr/local/config \ + && cp basicModules.yaml experimentalModules.yaml \ + && echo '\n - className: RadamsaDropByteMutator' >> experimentalModules.yaml \ + && echo ' - className: RadamsaFlipByteMutator' >> experimentalModules.yaml \ + && echo ' - className: RadamsaInsertByteMutator' >> experimentalModules.yaml \ + && echo ' - className: RadamsaRepeatByteMutator' >> experimentalModules.yaml \ + && set +ex + CMD bash From 47730e047df86028ed5acaa204081faeed96db62 Mon Sep 17 00:00:00 2001 From: Marc Date: Wed, 14 Aug 2024 13:58:21 -0400 Subject: [PATCH 18/31] Fixed GetRandomByteRepititionLength --- .../src/modules/common/mutator/RadamsaRepeatByteMutator.cpp | 2 +- Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteMutator.cpp index 10868e5..d556727 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteMutator.cpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteMutator.cpp @@ -110,7 +110,7 @@ void RadamsaRepeatByteMutator::mutateTestCase(StorageModule& storage, StorageEnt // The new buffer size will contain a random number of additional elements since we are repeating a random byte. // Furthermore, it will contain one more element since we are appending a null-terminator to the end. - const size_t numberOfRandomByteRepetitions{GetRandomByteRepetitionLength(rand)}; + const size_t numberOfRandomByteRepetitions{GetRandomByteRepetitionLength()}; const size_t newBufferSize{originalSize + numberOfRandomByteRepetitions + 1u}; // Allocate the new buffer and set it's elements to zero. diff --git a/Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp b/Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp index 684959a..7d94e26 100644 --- a/Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp +++ b/Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp @@ -4,7 +4,7 @@ #include #include #include -#include "VmfRand.hpp" +#include namespace vmf { @@ -12,8 +12,9 @@ class MutationBase { public: - static size_t GetRandomByteRepetitionLength(vmf::VmfRand rand) noexcept + static size_t GetRandomByteRepetitionLength() noexcept { + rand.randInit(); constexpr size_t MINIMUM_UPPER_LIMIT{0x2u}; constexpr size_t MAXIMUM_UPPER_LIMIT{0x20000u}; From ae837c2f12203676f2c73d592be5ffdb08fe4193 Mon Sep 17 00:00:00 2001 From: Marc Date: Wed, 14 Aug 2024 14:16:14 -0400 Subject: [PATCH 19/31] Passd rand by reference --- .../src/modules/common/mutator/RadamsaRepeatByteMutator.cpp | 2 +- Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteMutator.cpp index d556727..10868e5 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteMutator.cpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteMutator.cpp @@ -110,7 +110,7 @@ void RadamsaRepeatByteMutator::mutateTestCase(StorageModule& storage, StorageEnt // The new buffer size will contain a random number of additional elements since we are repeating a random byte. // Furthermore, it will contain one more element since we are appending a null-terminator to the end. - const size_t numberOfRandomByteRepetitions{GetRandomByteRepetitionLength()}; + const size_t numberOfRandomByteRepetitions{GetRandomByteRepetitionLength(rand)}; const size_t newBufferSize{originalSize + numberOfRandomByteRepetitions + 1u}; // Allocate the new buffer and set it's elements to zero. diff --git a/Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp b/Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp index 7d94e26..7211cef 100644 --- a/Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp +++ b/Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp @@ -4,7 +4,7 @@ #include #include #include -#include +#include "VmfRand.hpp" namespace vmf { @@ -12,9 +12,8 @@ class MutationBase { public: - static size_t GetRandomByteRepetitionLength() noexcept + static size_t GetRandomByteRepetitionLength(VmfRand& rand) noexcept { - rand.randInit(); constexpr size_t MINIMUM_UPPER_LIMIT{0x2u}; constexpr size_t MAXIMUM_UPPER_LIMIT{0x20000u}; From 008386437f7d1c69326a2553864fd2e798510dae Mon Sep 17 00:00:00 2001 From: Marc Date: Wed, 14 Aug 2024 15:26:34 -0400 Subject: [PATCH 20/31] Added permutebyte --- Radamsa/vmf/src/modules/CMakeLists.txt | 1 + .../mutator/RadamsaPermuteByteMutator.cpp | 146 ++++++++++++++++++ .../mutator/RadamsaPermuteByteMutator.hpp | 57 +++++++ 3 files changed, 204 insertions(+) create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaPermuteByteMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaPermuteByteMutator.hpp diff --git a/Radamsa/vmf/src/modules/CMakeLists.txt b/Radamsa/vmf/src/modules/CMakeLists.txt index ea8fd54..a2425b9 100644 --- a/Radamsa/vmf/src/modules/CMakeLists.txt +++ b/Radamsa/vmf/src/modules/CMakeLists.txt @@ -36,6 +36,7 @@ add_library(Radamsa SHARED common/mutator/RadamsaFlipByteMutator.cpp common/mutator/RadamsaInsertByteMutator.cpp common/mutator/RadamsaRepeatByteMutator.cpp + common/mutator/RadamsaPermuteByteMutator.cpp ) # Build-time dependencies for Radamsa diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaPermuteByteMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaPermuteByteMutator.cpp new file mode 100644 index 0000000..c6f3493 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaPermuteByteMutator.cpp @@ -0,0 +1,146 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaPermuteByteMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaPermuteByteMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaPermuteByteMutator::build(std::string name) +{ + return new RadamsaPermuteByteMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaPermuteByteMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaPermuteByteMutator::RadamsaPermuteByteMutator object + * + * @param name The of the name module + */ +RadamsaPermuteByteMutator::RadamsaPermuteByteMutator(std::string name) : MutatorModule(name) +{ + rand.randInit(); +} + +/** + * @brief Destroy the RadamsaPermuteByteMutator::RadamsaPermuteByteMutator object + * + */ +RadamsaPermuteByteMutator::~RadamsaPermuteByteMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaPermuteByteMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +void RadamsaPermuteByteMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + // Consume the original buffer by rearranging a random number of bytes and appending a null-terminator to the end. + + constexpr size_t minimumSize{1u}; + const size_t minimumSeedIndex{0u}; + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); + + if (originalSize < minimumSize) + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; + + if (minimumSeedIndex > originalSize - 1u) + throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + + if (originalBuffer == nullptr) + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + + // The new buffer size will contain one additional element since we are appending a null-terminator to the end. + + const size_t newBufferSize{originalSize + 1u}; + + // Allocate the new buffer, set it's elements to those of the original buffer, and append a null-terminator to the end. + + char* newBuffer{newEntry->allocateBuffer(testCaseKey, static_cast(newBufferSize))}; + memset(newBuffer, 0u, newBufferSize); + memcpy(newBuffer, originalBuffer, originalSize); + + // Copy data from the original buffer into the new buffer, but swap random bytes. + // The last element in the new buffer is skipped since it was implicitly set to zero during allocation. + + for (size_t sourceIndex{minimumSeedIndex}; sourceIndex < originalSize; ++sourceIndex) + { + // Select a random index and swap the two bytes. + + const size_t lower{0u}; + const size_t upper{originalSize - 1u}; + const size_t maximumRandomIndexValue{originalSize - minimumSeedIndex}; + const size_t randomIndexToSwap{ + std::clamp( + rand.randBetween( + lower, + maximumRandomIndexValue) + minimumSeedIndex, + lower, + upper + ) + }; + + const char sourceByte{newBuffer[sourceIndex]}; + const char swappedByte{newBuffer[randomIndexToSwap]}; + + newBuffer[sourceIndex] = swappedByte; + newBuffer[randomIndexToSwap] = sourceByte; + } +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaPermuteByteMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaPermuteByteMutator.hpp new file mode 100644 index 0000000..03714a6 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaPermuteByteMutator.hpp @@ -0,0 +1,57 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "mutationBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaPermuteByteMutator: public MutatorModule, public MutationBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaPermuteByteMutator(std::string name); + virtual ~RadamsaPermuteByteMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand rand; +}; +} \ No newline at end of file From eeb0155b2f18bfc7ce71c82fec34184ed2aa1805 Mon Sep 17 00:00:00 2001 From: Marc Bohler Date: Wed, 21 Aug 2024 15:29:34 -0400 Subject: [PATCH 21/31] Added permute mutator to Dockerfile --- dockerfiles/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/dockerfiles/Dockerfile b/dockerfiles/Dockerfile index b9d0f6d..e4da0bb 100644 --- a/dockerfiles/Dockerfile +++ b/dockerfiles/Dockerfile @@ -74,6 +74,7 @@ RUN set -ex \ && echo ' - className: RadamsaFlipByteMutator' >> experimentalModules.yaml \ && echo ' - className: RadamsaInsertByteMutator' >> experimentalModules.yaml \ && echo ' - className: RadamsaRepeatByteMutator' >> experimentalModules.yaml \ + && echo ' - className: RadamsaPermuteByteMutator' >> experimentalModules.yaml \ && set +ex CMD bash From 1c7f8f8bbd2d7d3501c5ba10b52aac1c9e2a6bc2 Mon Sep 17 00:00:00 2001 From: Marc Bohler Date: Wed, 21 Aug 2024 16:30:04 -0400 Subject: [PATCH 22/31] Added IncrementByte Mutator --- Radamsa/vmf/src/modules/CMakeLists.txt | 1 + .../mutator/RadamsaIncrementByteMutator.cpp | 136 ++++++++++++++++++ .../mutator/RadamsaIncrementByteMutator.hpp | 57 ++++++++ dockerfiles/Dockerfile | 1 + 4 files changed, 195 insertions(+) create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaIncrementByteMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaIncrementByteMutator.hpp diff --git a/Radamsa/vmf/src/modules/CMakeLists.txt b/Radamsa/vmf/src/modules/CMakeLists.txt index a2425b9..0eeabc8 100644 --- a/Radamsa/vmf/src/modules/CMakeLists.txt +++ b/Radamsa/vmf/src/modules/CMakeLists.txt @@ -37,6 +37,7 @@ add_library(Radamsa SHARED common/mutator/RadamsaInsertByteMutator.cpp common/mutator/RadamsaRepeatByteMutator.cpp common/mutator/RadamsaPermuteByteMutator.cpp + common/mutator/RadamsaIncrementByteMutator.cpp ) # Build-time dependencies for Radamsa diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaIncrementByteMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaIncrementByteMutator.cpp new file mode 100644 index 0000000..c4be505 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaIncrementByteMutator.cpp @@ -0,0 +1,136 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaIncrementByteMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaIncrementByteMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaIncrementByteMutator::build(std::string name) +{ + return new RadamsaIncrementByteMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaIncrementByteMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaIncrementByteMutator::RadamsaIncrementByteMutator object + * + * @param name The of the name module + */ +RadamsaIncrementByteMutator::RadamsaIncrementByteMutator(std::string name) : MutatorModule(name) +{ + rand.randInit(); +} + +/** + * @brief Destroy the RadamsaIncrementByteMutator::RadamsaIncrementByteMutator object + * + */ +RadamsaIncrementByteMutator::~RadamsaIncrementByteMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaIncrementByteMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +void RadamsaIncrementByteMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + // Consume the original buffer by incrementing a random byte and appending a null-terminator to the end. + + constexpr size_t minimumSize{1u}; + const size_t minimumSeedIndex{0u}; + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); + + if (originalSize < minimumSize) + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; + + if (minimumSeedIndex > originalSize - 1u) + throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + + if (originalBuffer == nullptr) + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + + // The new buffer size will contain one additional element since we are appending a null-terminator to the end. + + const size_t newBufferSize{originalSize + 1u}; + + // Allocate the new buffer, set it's elements to those of the original buffer, and append a null-terminator to the end. + + char* newBuffer{newEntry->allocateBuffer(testCaseKey, static_cast(newBufferSize))}; + memset(newBuffer, 0u, newBufferSize); + memcpy(newBuffer, originalBuffer, originalSize); + + // Select a random byte to circularly increment. + + const size_t lower{0u}; + const size_t upper{originalSize - 1u}; + const size_t maximumRandomIndexValue{originalSize - minimumSeedIndex}; + const size_t randomIndexToIncrement{ + std::clamp( + rand.randBetween( + lower, + maximumRandomIndexValue) + minimumSeedIndex, + lower, + upper + ) + }; + + newBuffer[randomIndexToIncrement] = static_cast((originalBuffer[randomIndexToIncrement] + 0x01u) % std::numeric_limits::max()); +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaIncrementByteMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaIncrementByteMutator.hpp new file mode 100644 index 0000000..91b365e --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaIncrementByteMutator.hpp @@ -0,0 +1,57 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "mutationBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaIncrementByteMutator: public MutatorModule, public MutationBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaIncrementByteMutator(std::string name); + virtual ~RadamsaIncrementByteMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand rand; +}; +} \ No newline at end of file diff --git a/dockerfiles/Dockerfile b/dockerfiles/Dockerfile index e4da0bb..f696258 100644 --- a/dockerfiles/Dockerfile +++ b/dockerfiles/Dockerfile @@ -75,6 +75,7 @@ RUN set -ex \ && echo ' - className: RadamsaInsertByteMutator' >> experimentalModules.yaml \ && echo ' - className: RadamsaRepeatByteMutator' >> experimentalModules.yaml \ && echo ' - className: RadamsaPermuteByteMutator' >> experimentalModules.yaml \ + && echo ' - className: RadamsaIncrementByteMutator' >> experimentalModules.yaml \ && set +ex CMD bash From e914f84b04acf6c5dace12af47c1dbdd95fe9551 Mon Sep 17 00:00:00 2001 From: Marc Bohler Date: Wed, 21 Aug 2024 17:17:17 -0400 Subject: [PATCH 23/31] Added DecrementByte Mutator --- Radamsa/vmf/src/modules/CMakeLists.txt | 1 + .../mutator/RadamsaDecrementByteMutator.cpp | 137 ++++++++++++++++++ .../mutator/RadamsaDecrementByteMutator.hpp | 57 ++++++++ dockerfiles/Dockerfile | 1 + 4 files changed, 196 insertions(+) create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaDecrementByteMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaDecrementByteMutator.hpp diff --git a/Radamsa/vmf/src/modules/CMakeLists.txt b/Radamsa/vmf/src/modules/CMakeLists.txt index 0eeabc8..7ea2166 100644 --- a/Radamsa/vmf/src/modules/CMakeLists.txt +++ b/Radamsa/vmf/src/modules/CMakeLists.txt @@ -38,6 +38,7 @@ add_library(Radamsa SHARED common/mutator/RadamsaRepeatByteMutator.cpp common/mutator/RadamsaPermuteByteMutator.cpp common/mutator/RadamsaIncrementByteMutator.cpp + common/mutator/RadamsaDecrementByteMutator.cpp ) # Build-time dependencies for Radamsa diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaDecrementByteMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaDecrementByteMutator.cpp new file mode 100644 index 0000000..30cbd04 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaDecrementByteMutator.cpp @@ -0,0 +1,137 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaDecrementByteMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaDecrementByteMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaDecrementByteMutator::build(std::string name) +{ + return new RadamsaDecrementByteMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaDecrementByteMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaDecrementByteMutator::RadamsaDecrementByteMutator object + * + * @param name The of the name module + */ +RadamsaDecrementByteMutator::RadamsaDecrementByteMutator(std::string name) : MutatorModule(name) +{ + rand.randInit(); +} + +/** + * @brief Destroy the RadamsaDecrementByteMutator::RadamsaDecrementByteMutator object + * + */ +RadamsaDecrementByteMutator::~RadamsaDecrementByteMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaDecrementByteMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +void RadamsaDecrementByteMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + // Consume the original buffer by decrementing a random byte and appending a null-terminator to the end. + + constexpr size_t minimumSize{1u}; + const size_t minimumSeedIndex{0u}; + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); + + + if (originalSize < minimumSize) + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; + + if (minimumSeedIndex > originalSize - 1u) + throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + + if (originalBuffer == nullptr) + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + + // The new buffer size will contain one additional element since we are appending a null-terminator to the end. + + const size_t newBufferSize{originalSize + 1u}; + + // Allocate the new buffer, set it's elements to those of the original buffer, and append a null-terminator to the end. + + char* newBuffer{newEntry->allocateBuffer(testCaseKey, static_cast(newBufferSize))}; + memset(newBuffer, 0u, newBufferSize); + memcpy(newBuffer, originalBuffer, originalSize); + + // Select a random byte to circularly decrement. + + const size_t lower{0u}; + const size_t upper{originalSize - 1u}; + const size_t maximumRandomIndexValue{originalSize - minimumSeedIndex}; + const size_t randomIndexToDecrement{ + std::clamp( + rand.randBetween( + lower, + maximumRandomIndexValue) + minimumSeedIndex, + lower, + upper + ) + }; + + newBuffer[randomIndexToDecrement] = static_cast((originalBuffer[randomIndexToDecrement] - 0x01u) % std::numeric_limits::max()); +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaDecrementByteMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaDecrementByteMutator.hpp new file mode 100644 index 0000000..b8be538 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaDecrementByteMutator.hpp @@ -0,0 +1,57 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "mutationBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaDecrementByteMutator: public MutatorModule, public MutationBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaDecrementByteMutator(std::string name); + virtual ~RadamsaDecrementByteMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand rand; +}; +} \ No newline at end of file diff --git a/dockerfiles/Dockerfile b/dockerfiles/Dockerfile index f696258..134a183 100644 --- a/dockerfiles/Dockerfile +++ b/dockerfiles/Dockerfile @@ -76,6 +76,7 @@ RUN set -ex \ && echo ' - className: RadamsaRepeatByteMutator' >> experimentalModules.yaml \ && echo ' - className: RadamsaPermuteByteMutator' >> experimentalModules.yaml \ && echo ' - className: RadamsaIncrementByteMutator' >> experimentalModules.yaml \ + && echo ' - className: RadamsaDecrementByteMutator' >> experimentalModules.yaml \ && set +ex CMD bash From b76e5be9fc1cb3f0ef37bf2c9cb07072cf79caf9 Mon Sep 17 00:00:00 2001 From: Marc Bohler Date: Wed, 21 Aug 2024 18:00:44 -0400 Subject: [PATCH 24/31] Added RandomizeByte Mutator --- Radamsa/vmf/src/modules/CMakeLists.txt | 1 + .../mutator/RadamsaRandomizeByteMutator.cpp | 136 ++++++++++++++++++ .../mutator/RadamsaRandomizeByteMutator.hpp | 57 ++++++++ dockerfiles/Dockerfile | 1 + 4 files changed, 195 insertions(+) create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaRandomizeByteMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaRandomizeByteMutator.hpp diff --git a/Radamsa/vmf/src/modules/CMakeLists.txt b/Radamsa/vmf/src/modules/CMakeLists.txt index 7ea2166..4a17cb6 100644 --- a/Radamsa/vmf/src/modules/CMakeLists.txt +++ b/Radamsa/vmf/src/modules/CMakeLists.txt @@ -39,6 +39,7 @@ add_library(Radamsa SHARED common/mutator/RadamsaPermuteByteMutator.cpp common/mutator/RadamsaIncrementByteMutator.cpp common/mutator/RadamsaDecrementByteMutator.cpp + common/mutator/RadamsaRandomizeByteMutator.cpp ) # Build-time dependencies for Radamsa diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaRandomizeByteMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaRandomizeByteMutator.cpp new file mode 100644 index 0000000..c230bd4 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaRandomizeByteMutator.cpp @@ -0,0 +1,136 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaRandomizeByteMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaRandomizeByteMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaRandomizeByteMutator::build(std::string name) +{ + return new RadamsaRandomizeByteMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaRandomizeByteMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaRandomizeByteMutator::RadamsaRandomizeByteMutator object + * + * @param name The of the name module + */ +RadamsaRandomizeByteMutator::RadamsaRandomizeByteMutator(std::string name) : MutatorModule(name) +{ + rand.randInit(); +} + +/** + * @brief Destroy the RadamsaRandomizeByteMutator::RadamsaRandomizeByteMutator object + * + */ +RadamsaRandomizeByteMutator::~RadamsaRandomizeByteMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaRandomizeByteMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +void RadamsaRandomizeByteMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + // Consume the original buffer by randomizing a random byte and appending a null-terminator to the end. + + constexpr size_t minimumSize{1u}; + const size_t minimumSeedIndex{0u}; + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); + + if (originalSize < minimumSize) + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; + + if (minimumSeedIndex > originalSize - 1u) + throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + + if (originalBuffer == nullptr) + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + + // The new buffer size will contain one additional element since we are appending a null-terminator to the end. + + const size_t newBufferSize{originalSize + 1u}; + + // Allocate the new buffer, set it's elements to those of the original buffer, and append a null-terminator to the end. + + char* newBuffer{newEntry->allocateBuffer(testCaseKey, static_cast(newBufferSize))}; + memset(newBuffer, 0u, newBufferSize); + memcpy(newBuffer, originalBuffer, originalSize); + + // Select a random byte to randomize + + const size_t lower{0u}; + const size_t upper{originalSize - 1u}; + const size_t maximumRandomIndexValue{originalSize - minimumSeedIndex}; + const size_t randomIndexToRandomize{ + std::clamp( + rand.randBetween( + lower, + maximumRandomIndexValue) + minimumSeedIndex, + lower, + upper + ) + }; + + newBuffer[randomIndexToRandomize] = static_cast(rand.randBetween(0u, std::numeric_limits::max())); +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaRandomizeByteMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaRandomizeByteMutator.hpp new file mode 100644 index 0000000..c8b64b4 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaRandomizeByteMutator.hpp @@ -0,0 +1,57 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "mutationBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaRandomizeByteMutator: public MutatorModule, public MutationBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaRandomizeByteMutator(std::string name); + virtual ~RadamsaRandomizeByteMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand rand; +}; +} \ No newline at end of file diff --git a/dockerfiles/Dockerfile b/dockerfiles/Dockerfile index 134a183..317322f 100644 --- a/dockerfiles/Dockerfile +++ b/dockerfiles/Dockerfile @@ -77,6 +77,7 @@ RUN set -ex \ && echo ' - className: RadamsaPermuteByteMutator' >> experimentalModules.yaml \ && echo ' - className: RadamsaIncrementByteMutator' >> experimentalModules.yaml \ && echo ' - className: RadamsaDecrementByteMutator' >> experimentalModules.yaml \ + && echo ' - className: RadamsaRandomizeByteMutator' >> experimentalModules.yaml \ && set +ex CMD bash From dc626329410b3b0c5e0820ec0691bdc1ec0b1e57 Mon Sep 17 00:00:00 2001 From: Marc Bohler Date: Thu, 22 Aug 2024 13:10:35 -0400 Subject: [PATCH 25/31] Copy files locally --- Radamsa/test/config/experimentalModules.yaml | 34 ++++++++++++++++++++ dockerfiles/Dockerfile | 18 +++-------- 2 files changed, 39 insertions(+), 13 deletions(-) create mode 100644 Radamsa/test/config/experimentalModules.yaml diff --git a/Radamsa/test/config/experimentalModules.yaml b/Radamsa/test/config/experimentalModules.yaml new file mode 100644 index 0000000..0c41d36 --- /dev/null +++ b/Radamsa/test/config/experimentalModules.yaml @@ -0,0 +1,34 @@ +vmfModules: + storage: #a storage module must be specified + className: SimpleStorage + controller: #a controller module must be specified + className: IterativeController + children: + - className: DirectoryBasedSeedGen + - className: GeneticAlgorithmInputGenerator + - className: AFLForkserverExecutor + - className: AFLFeedback + - className: SaveCorpusOutput + - className: StatsOutput + GeneticAlgorithmInputGenerator: + children: + - className: AFLFlipBitMutator + - className: AFLFlip2BitMutator + - className: AFLFlip4BitMutator + - className: AFLFlipByteMutator + - className: AFLFlip2ByteMutator + - className: AFLFlip4ByteMutator + - className: AFLRandomByteAddSubMutator + - className: AFLRandomByteMutator + - className: AFLDeleteMutator + - className: AFLCloneMutator + - className: AFLSpliceMutator + + - className: RadamsaDropByteMutator + - className: RadamsaFlipByteMutator + - className: RadamsaInsertByteMutator + - className: RadamsaRepeatByteMutator + - className: RadamsaPermuteByteMutator + - className: RadamsaIncrementByteMutator + - className: RadamsaDecrementByteMutator + - className: RadamsaRandomizeByteMutator diff --git a/dockerfiles/Dockerfile b/dockerfiles/Dockerfile index 317322f..a94533d 100644 --- a/dockerfiles/Dockerfile +++ b/dockerfiles/Dockerfile @@ -55,11 +55,11 @@ RUN set -ex \ && make install \ && set +ex -# Clone, build, install VMFExperimental +# Copy, build, install VmfExperimental +COPY . /usr/local/src/VmfExperimental + RUN set -ex \ - && cd /usr/local/src/ \ - && git clone --depth 1 https://github.com/crusoe112/VmfExperimental.git VmfExperimental\ - && cd VmfExperimental \ + && cd /usr/local/src/VmfExperimental \ && mkdir build \ && cd build \ && cmake -DVMF_INSTALL=/usr/local .. \ @@ -69,15 +69,7 @@ RUN set -ex \ # Create experimental config file RUN set -ex \ && cd /usr/local/test/config \ - && cp basicModules.yaml experimentalModules.yaml \ - && echo '\n - className: RadamsaDropByteMutator' >> experimentalModules.yaml \ - && echo ' - className: RadamsaFlipByteMutator' >> experimentalModules.yaml \ - && echo ' - className: RadamsaInsertByteMutator' >> experimentalModules.yaml \ - && echo ' - className: RadamsaRepeatByteMutator' >> experimentalModules.yaml \ - && echo ' - className: RadamsaPermuteByteMutator' >> experimentalModules.yaml \ - && echo ' - className: RadamsaIncrementByteMutator' >> experimentalModules.yaml \ - && echo ' - className: RadamsaDecrementByteMutator' >> experimentalModules.yaml \ - && echo ' - className: RadamsaRandomizeByteMutator' >> experimentalModules.yaml \ + && cp /usr/local/src/VmfExperimental/Radamsa/test/config/experimentalModules.yaml /usr/local/test/config/ \ && set +ex CMD bash From 3f8b99347d1b01846446690b70a55e6c205582da Mon Sep 17 00:00:00 2001 From: Marc Bohler Date: Thu, 22 Aug 2024 13:11:38 -0400 Subject: [PATCH 26/31] Added Kali Dockerfile --- dockerfiles/Dockerfile.kali | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/dockerfiles/Dockerfile.kali b/dockerfiles/Dockerfile.kali index 4e91616..a94533d 100644 --- a/dockerfiles/Dockerfile.kali +++ b/dockerfiles/Dockerfile.kali @@ -55,11 +55,11 @@ RUN set -ex \ && make install \ && set +ex -# Clone, build, install VMFExperimental +# Copy, build, install VmfExperimental +COPY . /usr/local/src/VmfExperimental + RUN set -ex \ - && cd /usr/local/src/ \ - && git clone --depth 1 https://github.com/crusoe112/VmfExperimental.git VmfExperimental\ - && cd VmfExperimental \ + && cd /usr/local/src/VmfExperimental \ && mkdir build \ && cd build \ && cmake -DVMF_INSTALL=/usr/local .. \ @@ -68,12 +68,8 @@ RUN set -ex \ # Create experimental config file RUN set -ex \ - && cd /usr/local/config \ - && cp basicModules.yaml experimentalModules.yaml \ - && echo '\n - className: RadamsaDropByteMutator' >> experimentalModules.yaml \ - && echo ' - className: RadamsaFlipByteMutator' >> experimentalModules.yaml \ - && echo ' - className: RadamsaInsertByteMutator' >> experimentalModules.yaml \ - && echo ' - className: RadamsaRepeatByteMutator' >> experimentalModules.yaml \ + && cd /usr/local/test/config \ + && cp /usr/local/src/VmfExperimental/Radamsa/test/config/experimentalModules.yaml /usr/local/test/config/ \ && set +ex CMD bash From 8762bf64dbfedbd6ee6180633e9b2b4f1b825bf4 Mon Sep 17 00:00:00 2001 From: GabeClark99 <54868591+GabeClark99@users.noreply.github.com> Date: Tue, 17 Jun 2025 09:09:39 -0500 Subject: [PATCH 27/31] 4.1.0 release (#5) * Rand refactoring for 4.1.0 * DecrementByte Length Test * TestByteDecremented * DropByte TestBufferSize * DropByte TestByteDropped * FlipByte TestBufferSize * FlibByte TestByteFlipped * IncrementByte tests * InsertByte tests * fixed test name * PermuteByte tests TestPermuteTwoBytes currently failing due to buff having the same values as modBuff. Need to discuss if this is intended behavior for mutators in general. * RandomizeByte TestRandomize * RepeatByte * misc cleanup Added license header, removed superfluous comments, combined buffer length test cases * buff_len, equality check simplified buff length check by calling it once and storing the result; asserting buff != modBuff for buff_len where buff_len+1 == modBuff_len * migrated to separate gtest binary can now run our tests without piggybacking off of stock vmf * DeleteLine * the rest * DeleteLine Exception Cases tests for buffer size and buffer exists * LineMutatorBase stub class for LineMutatorBase and telling mutators to inherit * ByteMutatorBase stub class for ByteMutatorBase and telling mutators to inherit * moved byte-specific helper function GetRandomByteRepetitionLength is specific to byte mutators, so it should live in the new ByteMutatorBase instead * Squashed commit of the following: commit 95bdd8767ab530669646a478a8711ae910158d46 Merge: 7b5d68d f3b3834 Author: GabeClark99 <54868591+GabeClark99@users.noreply.github.com> Date: Fri Jan 24 17:14:18 2025 -0600 Merge pull request #2 from crusoe112/mutator-bases Mutator bases commit f3b3834bee9cf7da35836c356949b680d9c1afe4 Author: GabeClark99 <54868591+GabeClark99@users.noreply.github.com> Date: Fri Jan 24 15:27:20 2025 -0500 moved byte-specific helper function GetRandomByteRepetitionLength is specific to byte mutators, so it should live in the new ByteMutatorBase instead commit 9030be9f5748a056f58924b1f598197e413565f4 Author: GabeClark99 <54868591+GabeClark99@users.noreply.github.com> Date: Fri Jan 24 15:22:54 2025 -0500 ByteMutatorBase stub class for ByteMutatorBase and telling mutators to inherit commit 86f1f26a098c4cb50689858f300aa6035c31e1c5 Author: GabeClark99 <54868591+GabeClark99@users.noreply.github.com> Date: Fri Jan 24 15:15:46 2025 -0500 LineMutatorBase stub class for LineMutatorBase and telling mutators to inherit * implemented Line struct * implemented LineVector struct * implemented LineList struct * fixed typo * DeleteLine typical usage tests Intentionally excluding testing the code under the IsBinarish conditional because it doesn't appear to be correctly implemented in the original and may not be carried over into the new refactoring * OneLine content test * fixed DeleteLine buff tests DeleteLine will append a null terminator, which was not accounted for previously. * DeleteSequentialLines exception tests * DeleteSequentialLines typical usage tests * DuplicateLine exception tests * Fixed testing buffer equality also added buffer equality test to cases that needed it * DuplicateLine OneLine * DuplicateLine TwoLines and ThreeLines * CopyLineCloseBy tests * DuplicateLineMutatorTest fixes - previous version assumed DuplicateLine operated like RepeatLine; this has been corrected - simplified buffer content tests - various cosmetic changes to improve readability * RepeatLine Tests * SwapLine tests * Merge pull request #4 from crusoe112/Radamsa-Mutator-Refactoring Splitting each mutator off into its own class --------- Signed-off-by: GabeClark99 <54868591+GabeClark99@users.noreply.github.com> Co-authored-by: Marc Bohler Co-authored-by: crusoe112 --- .gitignore | 3 +- CMakeLists.txt | 5 + README.md | 26 +- .../RadamsaCopyLineCloseByMutatorTest.cpp | 251 + .../test/RadamsaDecrementByteMutatorTest.cpp | 117 + Radamsa/test/RadamsaDeleteLineMutatorTest.cpp | 239 + ...adamsaDeleteSequentialLinesMutatorTest.cpp | 240 + Radamsa/test/RadamsaDropByteMutatorTest.cpp | 107 + .../test/RadamsaDuplicateLineMutatorTest.cpp | 266 + Radamsa/test/RadamsaFlipByteMutatorTest.cpp | 108 + .../test/RadamsaIncrementByteMutatorTest.cpp | 107 + Radamsa/test/RadamsaInsertByteMutatorTest.cpp | 107 + .../test/RadamsaPermuteByteMutatorTest.cpp | 159 + .../test/RadamsaRandomizeByteMutatorTest.cpp | 106 + Radamsa/test/RadamsaRepeatByteMutatorTest.cpp | 148 + Radamsa/test/RadamsaRepeatLineMutatorTest.cpp | 266 + Radamsa/test/RadamsaSwapLineMutatorTest.cpp | 236 + Radamsa/test/byteMutationTest.cpp | 715 --- Radamsa/test/byteMutationTest.h | 195 - Radamsa/test/config/experimentalModules.yaml | 9 + Radamsa/test/lineMutationTest.cpp | 4647 ----------------- Radamsa/test/lineMutationTest.h | 220 - Radamsa/test/mutationBaseTest.cpp | 104 - Radamsa/test/mutationBaseTest.h | 58 - Radamsa/test/radamsaMutatorTest.cpp | 493 -- Radamsa/vmf/src/modules/CMakeLists.txt | 6 + .../common/mutator/.byteMutations.hpp.swp | Bin 16384 -> 0 bytes .../common/mutator/RadamsaByteMutatorBase.hpp | 63 + .../mutator/RadamsaCopyLineCloseByMutator.cpp | 171 + .../mutator/RadamsaCopyLineCloseByMutator.hpp | 57 + .../mutator/RadamsaDecrementByteMutator.cpp | 4 +- .../mutator/RadamsaDecrementByteMutator.hpp | 6 +- .../mutator/RadamsaDeleteLineMutator.cpp | 158 + .../mutator/RadamsaDeleteLineMutator.hpp | 57 + .../RadamsaDeleteSequentialLinesMutator.cpp | 170 + .../RadamsaDeleteSequentialLinesMutator.hpp | 57 + .../common/mutator/RadamsaDropByteMutator.cpp | 4 +- .../common/mutator/RadamsaDropByteMutator.hpp | 6 +- .../mutator/RadamsaDuplicateLineMutator.cpp | 179 + .../mutator/RadamsaDuplicateLineMutator.hpp | 57 + .../common/mutator/RadamsaFlipByteMutator.cpp | 6 +- .../common/mutator/RadamsaFlipByteMutator.hpp | 6 +- .../mutator/RadamsaIncrementByteMutator.cpp | 4 +- .../mutator/RadamsaIncrementByteMutator.hpp | 6 +- .../mutator/RadamsaInsertByteMutator.cpp | 6 +- .../mutator/RadamsaInsertByteMutator.hpp | 6 +- ...tations.hpp => RadamsaLineMutatorBase.hpp} | 331 +- .../common/mutator/RadamsaMutatorBase.hpp | 45 + .../mutator/RadamsaPermuteByteMutator.cpp | 4 +- .../mutator/RadamsaPermuteByteMutator.hpp | 6 +- .../mutator/RadamsaRandomizeByteMutator.cpp | 6 +- .../mutator/RadamsaRandomizeByteMutator.hpp | 6 +- .../mutator/RadamsaRepeatByteMutator.cpp | 4 +- .../mutator/RadamsaRepeatByteMutator.hpp | 6 +- .../mutator/RadamsaRepeatLineMutator.cpp | 167 + .../mutator/RadamsaRepeatLineMutator.hpp | 57 + .../common/mutator/RadamsaSwapLineMutator.cpp | 207 + .../common/mutator/RadamsaSwapLineMutator.hpp | 57 + .../modules/common/mutator/byteMutations.cpp | 476 -- .../modules/common/mutator/byteMutations.hpp | 141 - .../modules/common/mutator/lineMutations.cpp | 930 ---- .../modules/common/mutator/mutationBase.hpp | 36 - .../modules/common/mutator/radamsaMutator.cpp | 219 - .../modules/common/mutator/radamsaMutator.hpp | 134 - test/CMakeLists.txt | 1 + test/unittest/CMakeLists.txt | 80 + 66 files changed, 4326 insertions(+), 8548 deletions(-) create mode 100644 Radamsa/test/RadamsaCopyLineCloseByMutatorTest.cpp create mode 100644 Radamsa/test/RadamsaDecrementByteMutatorTest.cpp create mode 100644 Radamsa/test/RadamsaDeleteLineMutatorTest.cpp create mode 100644 Radamsa/test/RadamsaDeleteSequentialLinesMutatorTest.cpp create mode 100644 Radamsa/test/RadamsaDropByteMutatorTest.cpp create mode 100644 Radamsa/test/RadamsaDuplicateLineMutatorTest.cpp create mode 100644 Radamsa/test/RadamsaFlipByteMutatorTest.cpp create mode 100644 Radamsa/test/RadamsaIncrementByteMutatorTest.cpp create mode 100644 Radamsa/test/RadamsaInsertByteMutatorTest.cpp create mode 100644 Radamsa/test/RadamsaPermuteByteMutatorTest.cpp create mode 100644 Radamsa/test/RadamsaRandomizeByteMutatorTest.cpp create mode 100644 Radamsa/test/RadamsaRepeatByteMutatorTest.cpp create mode 100644 Radamsa/test/RadamsaRepeatLineMutatorTest.cpp create mode 100644 Radamsa/test/RadamsaSwapLineMutatorTest.cpp delete mode 100644 Radamsa/test/byteMutationTest.cpp delete mode 100644 Radamsa/test/byteMutationTest.h delete mode 100644 Radamsa/test/lineMutationTest.cpp delete mode 100644 Radamsa/test/lineMutationTest.h delete mode 100644 Radamsa/test/mutationBaseTest.cpp delete mode 100644 Radamsa/test/mutationBaseTest.h delete mode 100644 Radamsa/test/radamsaMutatorTest.cpp delete mode 100644 Radamsa/vmf/src/modules/common/mutator/.byteMutations.hpp.swp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaByteMutatorBase.hpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaCopyLineCloseByMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaCopyLineCloseByMutator.hpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteLineMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteLineMutator.hpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteSequentialLinesMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteSequentialLinesMutator.hpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaDuplicateLineMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaDuplicateLineMutator.hpp rename Radamsa/vmf/src/modules/common/mutator/{lineMutations.hpp => RadamsaLineMutatorBase.hpp} (52%) create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaMutatorBase.hpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatLineMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatLineMutator.hpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaSwapLineMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaSwapLineMutator.hpp delete mode 100644 Radamsa/vmf/src/modules/common/mutator/byteMutations.cpp delete mode 100644 Radamsa/vmf/src/modules/common/mutator/byteMutations.hpp delete mode 100644 Radamsa/vmf/src/modules/common/mutator/lineMutations.cpp delete mode 100644 Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp delete mode 100644 Radamsa/vmf/src/modules/common/mutator/radamsaMutator.cpp delete mode 100644 Radamsa/vmf/src/modules/common/mutator/radamsaMutator.hpp create mode 100644 test/CMakeLists.txt create mode 100644 test/unittest/CMakeLists.txt diff --git a/.gitignore b/.gitignore index fb47903..3251c8e 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,5 @@ classes/ */classes/ build/ targets/ -.vscode/ \ No newline at end of file +.vscode/ +*.swp \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index eb279a6..5aaf05f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,6 +47,11 @@ list(APPEND CMAKE_MODULE_PATH "${VMF_INSTALL}/cmake") include(vmf_imports) include(vmf) +# Configure testing +include(GoogleTest) +enable_testing() +add_subdirectory(${PROJECT_SOURCE_DIR}/test) + # ---- TAILOR SPECIFIC EXTENSION PACKAGES HERE ---- # Add in extension package directories diff --git a/README.md b/README.md index 2828d7c..35bf5ff 100644 --- a/README.md +++ b/README.md @@ -53,8 +53,32 @@ To install the VMF extension libary, do this in the build directory: make install ``` - ## License All experimental modules must be license-compatible with VMF itself, which is licensed under the GNU General Public License Version 2. +## Unit Tests + +VMF uses the Google Test framework for unit testing. A basic overview of the framework as well as example unit test are available here: [Primer](http://google.github.io/googletest/primer.html). + +### Running the Unit Tests +To run the existing unit tests, use the following commands +```bash +cd build +ctest +``` + +For additional output on any failed tests +```bash +ctest --output-on-failure +``` + +For additional output on all of the tests +```bash +ctest --VV +``` + +To build and run +```bash +cmake -DVMF_INSTALL= .. && make -j8 && ctest +``` diff --git a/Radamsa/test/RadamsaCopyLineCloseByMutatorTest.cpp b/Radamsa/test/RadamsaCopyLineCloseByMutatorTest.cpp new file mode 100644 index 0000000..1a155f7 --- /dev/null +++ b/Radamsa/test/RadamsaCopyLineCloseByMutatorTest.cpp @@ -0,0 +1,251 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaCopyLineCloseByMutator.hpp" +#include "RuntimeException.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaCopyLineCloseByMutator; +using vmf::BaseException; +using vmf::RuntimeException; + +class RadamsaCopyLineCloseByMutatorTest : public ::testing::Test { + protected: + RadamsaCopyLineCloseByMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaCopyLineCloseByMutator("RadamsaCopyLineCloseByMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaCopyLineCloseByMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + // int_key = registry->registerKey( + // "TEST_INT", + // StorageRegistry::INT, + // StorageRegistry::READ_WRITE + // ); + // normalTag = registry->registerTag( + // "RAN_SUCCESSFULLY", + // StorageRegistry::WRITE_ONLY + // ); + // // registry->validateRegistration(); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } + + RadamsaCopyLineCloseByMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; +}; + +/*TEST_F(RadamsaCopyLineCloseByMutatorTest, BufferNotNull) +{ + // no way to test this without mocks +}*/ + +TEST_F(RadamsaCopyLineCloseByMutatorTest, BufferSizeGEOne) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + // char* buff = baseEntry->allocateBuffer(testCaseKey, 1); + /* By not allocating the buffer, we're forcing + StorageEntry::getBufferSize() to return '-1'. + */ + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaCopyLineCloseByMutatorTest, OneLine) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + size_t buff_len = 2; + size_t line_len = 2; + char* modBuff; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + buff[1] = '\n'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + + // test buff ne + ASSERT_FALSE(std::equal(buff, buff + buff_len, + modBuff, modBuff + modBuff_len - 1)); + // test number of lines + EXPECT_EQ(std::count(modBuff, modBuff + modBuff_len, '\n'), + buff_len / line_len + 1); + // test buff len + EXPECT_EQ(modBuff_len, buff_len + line_len + 1); + // test buff contents + EXPECT_EQ(modString, "4\n4\n\0"); +} + +TEST_F(RadamsaCopyLineCloseByMutatorTest, TwoLines) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + size_t buff_len = 4; + size_t line_len = 2; + char* modBuff; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + buff[1] = '\n'; + buff[2] = '5'; + buff[3] = '\n'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + + // test buff ne + ASSERT_FALSE(std::equal(buff, buff + buff_len, + modBuff, modBuff + modBuff_len - 1)); + // test number of lines + EXPECT_EQ(std::count(modBuff, modBuff + modBuff_len, '\n'), + buff_len / line_len + 1); + // test buff len + EXPECT_EQ(modBuff_len, buff_len + line_len + 1); + // test buff contents + EXPECT_TRUE(modString == "4\n4\n5\n\0" || // coppied "4\n" + modString == "4\n5\n4\n\0" || + modString == "5\n4\n5\n\0" || // coppied "5\n" + modString == "4\n5\n5\n\0" + ); +} + +TEST_F(RadamsaCopyLineCloseByMutatorTest, ThreeLines) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + size_t buff_len = 6; + size_t line_len = 2; + char* modBuff; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + buff[1] = '\n'; + buff[2] = '5'; + buff[3] = '\n'; + buff[4] = '6'; + buff[5] = '\n'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + + // test buff ne + ASSERT_FALSE(std::equal(buff, buff + buff_len, + modBuff, modBuff + modBuff_len - 1)); + // test number of lines + EXPECT_EQ(std::count(modBuff, modBuff + modBuff_len, '\n'), + buff_len / line_len + 1); + // test buff len + EXPECT_EQ(modBuff_len, buff_len + line_len + 1); + // test buff contents + EXPECT_TRUE(modString == "4\n4\n5\n6\n\0" || // coppied "4\n" // position 0/1 + modString == "4\n5\n4\n6\n\0" || // position 2 + modString == "4\n5\n6\n4\n\0" || // position 3 + modString == "5\n4\n5\n6\n\0" || // coppied "5\n" // position 0 + modString == "4\n5\n5\n6\n\0" || // position 1/2 + modString == "4\n5\n6\n5\n\0" || // position 3 + modString == "6\n4\n5\n6\n\0" || // coppied "6\n" // position 0 + modString == "4\n6\n5\n6\n\0" || // position 1 + modString == "4\n5\n6\n6\n\0" // position 2/3 + ); +} diff --git a/Radamsa/test/RadamsaDecrementByteMutatorTest.cpp b/Radamsa/test/RadamsaDecrementByteMutatorTest.cpp new file mode 100644 index 0000000..ef97895 --- /dev/null +++ b/Radamsa/test/RadamsaDecrementByteMutatorTest.cpp @@ -0,0 +1,117 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaDecrementByteMutator.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaDecrementByteMutator; +using vmf::BaseException; + +class RadamsaDecrementByteMutatorTest : public ::testing::Test { + protected: + RadamsaDecrementByteMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaDecrementByteMutator("RadamsaDecrementByteMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaDecrementByteMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + // int_key = registry->registerKey( + // "TEST_INT", + // StorageRegistry::INT, + // StorageRegistry::READ_WRITE + // ); + // normalTag = registry->registerTag( + // "RAN_SUCCESSFULLY", + // StorageRegistry::WRITE_ONLY + // ); + // // registry->validateRegistration(); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } + + RadamsaDecrementByteMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; +}; + +TEST_F(RadamsaDecrementByteMutatorTest, TestByteDecremented) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + int buff_len = 1; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + char* modBuff = modEntry->getBufferPointer(testCaseKey); + ASSERT_FALSE(std::equal(buff, buff + buff_len, + modBuff, modBuff + modEntry->getBufferSize(testCaseKey) - 1)); + EXPECT_EQ(buff_len + 1, modEntry->getBufferSize(testCaseKey)); + EXPECT_EQ(modBuff[0], '3'); +} diff --git a/Radamsa/test/RadamsaDeleteLineMutatorTest.cpp b/Radamsa/test/RadamsaDeleteLineMutatorTest.cpp new file mode 100644 index 0000000..8de543e --- /dev/null +++ b/Radamsa/test/RadamsaDeleteLineMutatorTest.cpp @@ -0,0 +1,239 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaDeleteLineMutator.hpp" +#include "RuntimeException.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaDeleteLineMutator; +using vmf::BaseException; +using vmf::RuntimeException; + +class RadamsaDeleteLineMutatorTest : public ::testing::Test { + protected: + RadamsaDeleteLineMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaDeleteLineMutator("RadamsaDeleteLineMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaDeleteLineMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + // int_key = registry->registerKey( + // "TEST_INT", + // StorageRegistry::INT, + // StorageRegistry::READ_WRITE + // ); + // normalTag = registry->registerTag( + // "RAN_SUCCESSFULLY", + // StorageRegistry::WRITE_ONLY + // ); + // // registry->validateRegistration(); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } + + RadamsaDeleteLineMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; +}; + +/*TEST_F(RadamsaDeleteLineMutatorTest, BufferNotNull) +{ + // no way to test this without mocks +}*/ + +TEST_F(RadamsaDeleteLineMutatorTest, BufferSizeGEOne) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + // char* buff = baseEntry->allocateBuffer(testCaseKey, 1); + /* By not allocating the buffer, we're forcing + StorageEntry::getBufferSize() to return '-1'. + */ + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaDeleteLineMutatorTest, OneLine) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + size_t buff_len = 2; + size_t line_len = 2; + char* modBuff; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + buff[1] = '\n'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + std::string modString = std::string(modBuff); + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + + EXPECT_FALSE(std::equal(buff, buff + buff_len, + modBuff, modBuff + modBuff_len - 1) + ) << "Modified buffer must not be equal to original buffer"; + + EXPECT_EQ(buff_len / line_len - 1, + std::count(modBuff, modBuff + buff_len, '\n') + ) << "Number of lines in modified buffer must be one less than those in the original buffer"; + + EXPECT_EQ(buff_len - line_len + 1, modBuff_len + ) << "Modified buffer length must be equal to the original buffer less one line plus one"; + + EXPECT_EQ(modString, "\0"); +} + +TEST_F(RadamsaDeleteLineMutatorTest, TwoLines) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + size_t buff_len = 4; + size_t line_len = 2; + char* modBuff; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + buff[1] = '\n'; + buff[2] = '5'; + buff[3] = '\n'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + // test buff ne + ASSERT_FALSE(std::equal(buff, buff + buff_len, + modBuff, modBuff + modEntry->getBufferSize(testCaseKey) - 1)); + // test number of lines in buff + EXPECT_EQ(buff_len / line_len - 1, + std::count(modBuff, modBuff + buff_len, '\n')); + // test buff len + EXPECT_EQ(buff_len - line_len + 1, modEntry->getBufferSize(testCaseKey)); + // test buff contents + std::string modString = std::string(modBuff); + EXPECT_TRUE(modString == "4\n\0" | + modString == "5\n\0"); +} + +TEST_F(RadamsaDeleteLineMutatorTest, ThreeLines) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + size_t buff_len = 6; + size_t line_len = 2; + char* modBuff; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + buff[1] = '\n'; + buff[2] = '5'; + buff[3] = '\n'; + buff[4] = '6'; + buff[5] = '\n'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + // test buff ne + ASSERT_FALSE(std::equal(buff, buff + buff_len, + modBuff, modBuff + modEntry->getBufferSize(testCaseKey) - 1)); + // test number of lines in buff + EXPECT_EQ(buff_len / line_len - 1, + std::count(modBuff, modBuff + buff_len, '\n')); + // test buff len + EXPECT_EQ(buff_len - line_len + 1, modEntry->getBufferSize(testCaseKey)); + // test buff contents + std::string modString = std::string(modBuff); + EXPECT_TRUE(modString == "4\n5\n\0" | + modString == "5\n6\n\0" | + modString == "4\n6\n\0"); +} \ No newline at end of file diff --git a/Radamsa/test/RadamsaDeleteSequentialLinesMutatorTest.cpp b/Radamsa/test/RadamsaDeleteSequentialLinesMutatorTest.cpp new file mode 100644 index 0000000..1f62856 --- /dev/null +++ b/Radamsa/test/RadamsaDeleteSequentialLinesMutatorTest.cpp @@ -0,0 +1,240 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaDeleteSequentialLinesMutator.hpp" +#include "RuntimeException.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaDeleteSequentialLinesMutator; +using vmf::BaseException; +using vmf::RuntimeException; + +class RadamsaDeleteSequentialLinesMutatorTest : public ::testing::Test { + protected: + RadamsaDeleteSequentialLinesMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaDeleteSequentialLinesMutator("RadamsaDeleteSequentialLinesMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaDeleteSequentialLinesMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + // int_key = registry->registerKey( + // "TEST_INT", + // StorageRegistry::INT, + // StorageRegistry::READ_WRITE + // ); + // normalTag = registry->registerTag( + // "RAN_SUCCESSFULLY", + // StorageRegistry::WRITE_ONLY + // ); + // // registry->validateRegistration(); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } + + RadamsaDeleteSequentialLinesMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; +}; + +/*TEST_F(RadamsaDeleteSequentialLinesMutatorTest, BufferNotNull) +{ + // no way to test this without mocks +}*/ + +TEST_F(RadamsaDeleteSequentialLinesMutatorTest, BufferSizeGEOne) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + // char* buff = baseEntry->allocateBuffer(testCaseKey, 1); + /* By not allocating the buffer, we're forcing + StorageEntry::getBufferSize() to return '-1'. + */ + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaDeleteSequentialLinesMutatorTest, OneLine) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + size_t buff_len = 2; + size_t line_len = 2; + char* modBuff; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + buff[1] = '\n'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + // test buff ne + ASSERT_FALSE(std::equal(buff, buff + buff_len, + modBuff, modBuff + modEntry->getBufferSize(testCaseKey) - 1)); + // test number of lines in buff + EXPECT_EQ(buff_len / line_len - 1, + std::count(modBuff, modBuff + buff_len, '\n')); + // test buff len + EXPECT_EQ(buff_len - line_len + 1, modEntry->getBufferSize(testCaseKey)); + // test buff contents + std::string modString = std::string(modBuff); + EXPECT_EQ(modString, "\0"); +} + +TEST_F(RadamsaDeleteSequentialLinesMutatorTest, TwoLines) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + size_t buff_len = 4; + size_t line_len = 2; + char* modBuff; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + buff[1] = '\n'; + buff[2] = '5'; + buff[3] = '\n'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + // test buff ne + ASSERT_FALSE(std::equal(buff, buff + buff_len, + modBuff, modBuff + modEntry->getBufferSize(testCaseKey) - 1)); + // test number of lines in buff (at least one line removed) + EXPECT_LE(std::count(modBuff, modBuff + buff_len, '\n'), + buff_len / line_len - 1); + // test buff len + EXPECT_LE(modEntry->getBufferSize(testCaseKey), buff_len - line_len + 1); + // test buff contents + std::string modString = std::string(modBuff); + EXPECT_TRUE(modString == "4\n\0" | // deleted one line + modString == "5\n\0" | + modString == "\0"); // deleted two lines +} + +TEST_F(RadamsaDeleteSequentialLinesMutatorTest, ThreeLines) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + size_t buff_len = 6; + size_t line_len = 2; + char* modBuff; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + buff[1] = '\n'; + buff[2] = '5'; + buff[3] = '\n'; + buff[4] = '6'; + buff[5] = '\n'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + // test buff ne + ASSERT_FALSE(std::equal(buff, buff + buff_len, + modBuff, modBuff + modEntry->getBufferSize(testCaseKey) - 1)); + // test number of lines in buff (at least one line removed) + EXPECT_LE(std::count(modBuff, modBuff + buff_len, '\n'), + buff_len / line_len - 1); + // test buff len + EXPECT_LE(modEntry->getBufferSize(testCaseKey), buff_len - line_len + 1); + // test buff contents + std::string modString = std::string(modBuff); + EXPECT_TRUE(modString == "4\n5\n\0" | // deleted one line + modString == "5\n6\n\0" | + modString == "4\n6\n\0" | + modString == "4\n\0" | // deleted two lines + modString == "5\n\0" | + modString == "6\n\0" | + modString == "\0"); // deleted three lines +} \ No newline at end of file diff --git a/Radamsa/test/RadamsaDropByteMutatorTest.cpp b/Radamsa/test/RadamsaDropByteMutatorTest.cpp new file mode 100644 index 0000000..69e13df --- /dev/null +++ b/Radamsa/test/RadamsaDropByteMutatorTest.cpp @@ -0,0 +1,107 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaDropByteMutator.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaDropByteMutator; +using vmf::BaseException; + +class RadamsaDropByteMutatorTest : public ::testing::Test { + protected: + RadamsaDropByteMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaDropByteMutator("RadamsaDropByteMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaDropByteMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } + + RadamsaDropByteMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; +}; + +TEST_F(RadamsaDropByteMutatorTest, TestByteDropped) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + int buff_len = 1; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + char* modBuff = modEntry->getBufferPointer(testCaseKey); + ASSERT_FALSE(std::equal(buff, buff + buff_len, + modBuff, modBuff + modEntry->getBufferSize(testCaseKey) - 1)); + EXPECT_EQ(buff_len, modEntry->getBufferSize(testCaseKey)); + EXPECT_EQ(modBuff[0], '\0'); +} diff --git a/Radamsa/test/RadamsaDuplicateLineMutatorTest.cpp b/Radamsa/test/RadamsaDuplicateLineMutatorTest.cpp new file mode 100644 index 0000000..04d2c79 --- /dev/null +++ b/Radamsa/test/RadamsaDuplicateLineMutatorTest.cpp @@ -0,0 +1,266 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaDuplicateLineMutator.hpp" +#include "RuntimeException.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaDuplicateLineMutator; +using vmf::BaseException; +using vmf::RuntimeException; + +class RadamsaDuplicateLineMutatorTest : public ::testing::Test { + protected: + RadamsaDuplicateLineMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaDuplicateLineMutator("RadamsaDuplicateLineMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaDuplicateLineMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + // int_key = registry->registerKey( + // "TEST_INT", + // StorageRegistry::INT, + // StorageRegistry::READ_WRITE + // ); + // normalTag = registry->registerTag( + // "RAN_SUCCESSFULLY", + // StorageRegistry::WRITE_ONLY + // ); + // // registry->validateRegistration(); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } + + int GetNumOcc(std::string baseStr, std::string toFind) { + int count = 0; + size_t pos = baseStr.find(toFind); + while(pos != std::string::npos) { + ++count; + pos = baseStr.find(toFind, pos + toFind.length()); + } + + return count; + } + + RadamsaDuplicateLineMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; +}; + +/*TEST_F(RadamsaDuplicateLineMutatorTest, BufferNotNull) +{ + // no way to test this without mocks +}*/ + +TEST_F(RadamsaDuplicateLineMutatorTest, BufferSizeGEOne) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + // char* buff = baseEntry->allocateBuffer(testCaseKey, 1); + /* By not allocating the buffer, we're forcing + StorageEntry::getBufferSize() to return '-1'. + */ + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaDuplicateLineMutatorTest, OneLine) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + size_t buff_len = 2; + size_t line_len = 2; + char* modBuff; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + buff[1] = '\n'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + int count = GetNumOcc(modString, "4\n"); + + // test buff ne + ASSERT_FALSE(std::equal(buff, buff + buff_len, + modBuff, modBuff + modBuff_len - 1) + ); + // test number of lines + EXPECT_EQ(std::count(modBuff, modBuff + modBuff_len, '\n'), + buff_len / line_len + 1 + ); + // test buff len + EXPECT_EQ(modBuff_len, buff_len + line_len + 1); + // test buff contents + EXPECT_EQ(count, 2); +} + +TEST_F(RadamsaDuplicateLineMutatorTest, TwoLines) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + size_t buff_len = 4; + size_t line_len = 2; + char* modBuff; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + buff[1] = '\n'; + buff[2] = '5'; + buff[3] = '\n'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + int count4 = GetNumOcc(modString, "4\n"); + int count5 = GetNumOcc(modString, "5\n"); + + // test buff ne + ASSERT_FALSE(std::equal(buff, buff + buff_len, + modBuff, modBuff + modBuff_len - 1) + ); + // test number of lines + EXPECT_EQ(std::count(modBuff, modBuff + modBuff_len, '\n'), + buff_len / line_len + 1 + ); + // test buff len + EXPECT_EQ(modBuff_len, buff_len + line_len + 1); + // test buff contents + EXPECT_TRUE((count4 == 2 && count5 == 1) || + (count5 == 2 && count4 == 1) + ); +} + +TEST_F(RadamsaDuplicateLineMutatorTest, ThreeLines) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + size_t buff_len = 6; + size_t line_len = 2; + char* modBuff; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + buff[1] = '\n'; + buff[2] = '5'; + buff[3] = '\n'; + buff[4] = '6'; + buff[5] = '\n'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + int count4 = GetNumOcc(modString, "4\n"); + int count5 = GetNumOcc(modString, "5\n"); + int count6 = GetNumOcc(modString, "6\n"); + + // test buff ne + ASSERT_FALSE(std::equal(buff, buff + buff_len, + modBuff, modBuff + modBuff_len - 1) + ); + // test number of lines + EXPECT_EQ(std::count(modBuff, modBuff + modBuff_len, '\n'), + buff_len / line_len + 1 + ); + // test buff len + EXPECT_EQ(modBuff_len, buff_len + line_len + 1); + // test buff contents + EXPECT_TRUE((count4 == 2 && count5 == 1 && count6 == 1) || + (count5 == 2 && count4 == 1 && count6 == 1) || + (count6 == 2 && count4 == 1 && count5 == 1) + ); +} diff --git a/Radamsa/test/RadamsaFlipByteMutatorTest.cpp b/Radamsa/test/RadamsaFlipByteMutatorTest.cpp new file mode 100644 index 0000000..1549bca --- /dev/null +++ b/Radamsa/test/RadamsaFlipByteMutatorTest.cpp @@ -0,0 +1,108 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaFlipByteMutator.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaFlipByteMutator; +using vmf::BaseException; + +class RadamsaFlipByteMutatorTest : public ::testing::Test { + protected: + RadamsaFlipByteMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaFlipByteMutator("RadamsaFlipByteMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaFlipByteMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } + + RadamsaFlipByteMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; +}; + +TEST_F(RadamsaFlipByteMutatorTest, TestByteFlipped) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + int buff_len = 1; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + char* modBuff = modEntry->getBufferPointer(testCaseKey); + char expected = buff[0] ^ 0b10; // 0b10 is the mask when using the default seed + ASSERT_FALSE(std::equal(buff, buff + buff_len, + modBuff, modBuff + modEntry->getBufferSize(testCaseKey) - 1)); + EXPECT_EQ(buff_len + 1, modEntry->getBufferSize(testCaseKey)); + EXPECT_EQ(modBuff[0], expected); +} diff --git a/Radamsa/test/RadamsaIncrementByteMutatorTest.cpp b/Radamsa/test/RadamsaIncrementByteMutatorTest.cpp new file mode 100644 index 0000000..9603786 --- /dev/null +++ b/Radamsa/test/RadamsaIncrementByteMutatorTest.cpp @@ -0,0 +1,107 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaIncrementByteMutator.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaIncrementByteMutator; +using vmf::BaseException; + +class RadamsaIncrementByteMutatorTest : public ::testing::Test { + protected: + RadamsaIncrementByteMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaIncrementByteMutator("RadamsaIncrementByteMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaIncrementByteMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } + + RadamsaIncrementByteMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; +}; + +TEST_F(RadamsaIncrementByteMutatorTest, TestByteIncremented) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + int buff_len = 1; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + char* modBuff = modEntry->getBufferPointer(testCaseKey); + ASSERT_FALSE(std::equal(buff, buff + buff_len, + modBuff, modBuff + modEntry->getBufferSize(testCaseKey) - 1)); + EXPECT_EQ(buff_len + 1, modEntry->getBufferSize(testCaseKey)); + EXPECT_EQ(modBuff[0], '5'); +} diff --git a/Radamsa/test/RadamsaInsertByteMutatorTest.cpp b/Radamsa/test/RadamsaInsertByteMutatorTest.cpp new file mode 100644 index 0000000..543b2b4 --- /dev/null +++ b/Radamsa/test/RadamsaInsertByteMutatorTest.cpp @@ -0,0 +1,107 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaInsertByteMutator.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaInsertByteMutator; +using vmf::BaseException; + +class RadamsaInsertByteMutatorTest : public ::testing::Test { + protected: + RadamsaInsertByteMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaInsertByteMutator("RadamsaInsertByteMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaInsertByteMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } + + RadamsaInsertByteMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; +}; + +TEST_F(RadamsaInsertByteMutatorTest, TestByteInserted) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + int buff_len = 1; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + char* modBuff = modEntry->getBufferPointer(testCaseKey); + ASSERT_FALSE(std::equal(buff, buff + buff_len, + modBuff, modBuff + modEntry->getBufferSize(testCaseKey) - 1)); + EXPECT_EQ(buff_len + 2, modEntry->getBufferSize(testCaseKey)); + EXPECT_TRUE(modBuff[0] != '4' | modBuff[1] != '4'); +} diff --git a/Radamsa/test/RadamsaPermuteByteMutatorTest.cpp b/Radamsa/test/RadamsaPermuteByteMutatorTest.cpp new file mode 100644 index 0000000..73ec701 --- /dev/null +++ b/Radamsa/test/RadamsaPermuteByteMutatorTest.cpp @@ -0,0 +1,159 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaPermuteByteMutator.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaPermuteByteMutator; +using vmf::BaseException; + +class RadamsaPermuteByteMutatorTest : public ::testing::Test { + protected: + RadamsaPermuteByteMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaPermuteByteMutator("RadamsaPermuteByteMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaPermuteByteMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } + + RadamsaPermuteByteMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; +}; + +//TODO: flip byte in this case? +TEST_F(RadamsaPermuteByteMutatorTest, TestPermuteSingleByte) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + int buff_len = 1; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + char* modBuff = modEntry->getBufferPointer(testCaseKey); + // ASSERT_FALSE(std::equal(buff, buff + buff_len, + // modBuff, modBuff + modEntry->getBufferSize(testCaseKey) - 1)); + EXPECT_EQ(buff_len + 1, modEntry->getBufferSize(testCaseKey)); + EXPECT_EQ(modBuff[0], '4'); +} + +TEST_F(RadamsaPermuteByteMutatorTest, TestPermuteTwoBytes) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + int buff_len = 2; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + buff[1] = '5'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + char* modBuff = modEntry->getBufferPointer(testCaseKey); + // ASSERT_FALSE(std::equal(buff, buff + buff_len, + // modBuff, modBuff + modEntry->getBufferSize(testCaseKey) - 1)); + EXPECT_EQ(buff_len + 1, modEntry->getBufferSize(testCaseKey)); + EXPECT_TRUE(std::is_permutation(buff, buff+buff_len, modBuff)); +} + +TEST_F(RadamsaPermuteByteMutatorTest, TestPermuteThreeBytes) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + int buff_len = 3; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + buff[1] = '5'; + buff[2] = '6'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + char* modBuff = modEntry->getBufferPointer(testCaseKey); + // ASSERT_FALSE(std::equal(buff, buff + buff_len, + // modBuff, modBuff + modEntry->getBufferSize(testCaseKey) - 1)); + EXPECT_EQ(buff_len + 1, modEntry->getBufferSize(testCaseKey)); + EXPECT_TRUE(std::is_permutation(buff, buff+buff_len, modBuff)); +} \ No newline at end of file diff --git a/Radamsa/test/RadamsaRandomizeByteMutatorTest.cpp b/Radamsa/test/RadamsaRandomizeByteMutatorTest.cpp new file mode 100644 index 0000000..9d510fa --- /dev/null +++ b/Radamsa/test/RadamsaRandomizeByteMutatorTest.cpp @@ -0,0 +1,106 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaRandomizeByteMutator.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaRandomizeByteMutator; +using vmf::BaseException; + +class RadamsaRandomizeByteMutatorTest : public ::testing::Test { + protected: + RadamsaRandomizeByteMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaRandomizeByteMutator("RadamsaRandomizeByteMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaRandomizeByteMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } + + RadamsaRandomizeByteMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; +}; + +TEST_F(RadamsaRandomizeByteMutatorTest, TestRandomize) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + int buff_len = 1; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + char* modBuff = modEntry->getBufferPointer(testCaseKey); + ASSERT_FALSE(std::equal(buff, buff + buff_len, + modBuff, modBuff + modEntry->getBufferSize(testCaseKey) - 1)); + EXPECT_EQ(buff_len + 1, modEntry->getBufferSize(testCaseKey)); +} \ No newline at end of file diff --git a/Radamsa/test/RadamsaRepeatByteMutatorTest.cpp b/Radamsa/test/RadamsaRepeatByteMutatorTest.cpp new file mode 100644 index 0000000..84d8bfe --- /dev/null +++ b/Radamsa/test/RadamsaRepeatByteMutatorTest.cpp @@ -0,0 +1,148 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaRepeatByteMutator.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaRepeatByteMutator; +using vmf::BaseException; + +class RadamsaRepeatByteMutatorTest : public ::testing::Test { + protected: + RadamsaRepeatByteMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaRepeatByteMutator("RadamsaRepeatByteMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaRepeatByteMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } + + RadamsaRepeatByteMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; +}; + +TEST_F(RadamsaRepeatByteMutatorTest, TestOneByteRepeat) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + int buff_len = 1; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + char* modBuff = modEntry->getBufferPointer(testCaseKey); + int modBuff_len = modEntry->getBufferSize(testCaseKey); + int counter = 0; + + for(int i=0; i < modBuff_len; i++){ + if(modBuff[i] == '4') + counter++; + } + + ASSERT_FALSE(std::equal(buff, buff + buff_len, + modBuff, modBuff + modEntry->getBufferSize(testCaseKey) - 1)); + EXPECT_GT(modBuff_len, buff_len + 1); + EXPECT_EQ(modBuff_len - 1, counter); +} + +TEST_F(RadamsaRepeatByteMutatorTest, TestTwoBytesRepeat) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + int buff_len = 2; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + buff[1] = '5'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + char* modBuff = modEntry->getBufferPointer(testCaseKey); + int modBuff_len = modEntry->getBufferSize(testCaseKey); + int counter = 0; + + for(int i=0; i < buff_len; i++){ + if(modBuff[i] == '4') + counter++; + } + + ASSERT_FALSE(std::equal(buff, buff + buff_len, + modBuff, modBuff + modEntry->getBufferSize(testCaseKey) - 1)); + EXPECT_GT(modBuff_len, buff_len + 1); + EXPECT_TRUE(counter == 1 | counter == modBuff_len - 2); +} \ No newline at end of file diff --git a/Radamsa/test/RadamsaRepeatLineMutatorTest.cpp b/Radamsa/test/RadamsaRepeatLineMutatorTest.cpp new file mode 100644 index 0000000..2902b62 --- /dev/null +++ b/Radamsa/test/RadamsaRepeatLineMutatorTest.cpp @@ -0,0 +1,266 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaRepeatLineMutator.hpp" +#include "RuntimeException.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaRepeatLineMutator; +using vmf::BaseException; +using vmf::RuntimeException; + +class RadamsaRepeatLineMutatorTest : public ::testing::Test { + protected: + RadamsaRepeatLineMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaRepeatLineMutator("RadamsaRepeatLineMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaRepeatLineMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + // int_key = registry->registerKey( + // "TEST_INT", + // StorageRegistry::INT, + // StorageRegistry::READ_WRITE + // ); + // normalTag = registry->registerTag( + // "RAN_SUCCESSFULLY", + // StorageRegistry::WRITE_ONLY + // ); + // // registry->validateRegistration(); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } + + int GetNumOcc(std::string baseStr, std::string toFind) { + int count = 0; + size_t pos = baseStr.find(toFind); + while(pos != std::string::npos) { + ++count; + pos = baseStr.find(toFind, pos + toFind.length()); + } + + return count; + } + + RadamsaRepeatLineMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; +}; + +/*TEST_F(RadamsaRepeatLineMutatorTest, BufferNotNull) +{ + // no way to test this without mocks +}*/ + +TEST_F(RadamsaRepeatLineMutatorTest, BufferSizeGEOne) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + // char* buff = baseEntry->allocateBuffer(testCaseKey, 1); + /* By not allocating the buffer, we're forcing + StorageEntry::getBufferSize() to return '-1'. + */ + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaRepeatLineMutatorTest, OneLine) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + size_t buff_len = 2; + size_t line_len = 2; + char* modBuff; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + buff[1] = '\n'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + int count = GetNumOcc(modString, "4\n"); + + // test buff ne + ASSERT_FALSE(std::equal(buff, buff + buff_len, + modBuff, modBuff + modBuff_len - 1) + ); + // test number of lines + EXPECT_GT(std::count(modBuff, modBuff + modBuff_len, '\n'), + buff_len / line_len + ); + // test buff len (should be a multiple of line_len plus \0) + EXPECT_EQ(modBuff_len % line_len, 1); + // test buff contents + EXPECT_GT(count, 1); +} + +TEST_F(RadamsaRepeatLineMutatorTest, TwoLines) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + size_t buff_len = 4; + size_t line_len = 2; + char* modBuff; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + buff[1] = '\n'; + buff[2] = '5'; + buff[3] = '\n'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + int count4 = GetNumOcc(modString, "4\n"); + int count5 = GetNumOcc(modString, "5\n"); + + // test buff ne + ASSERT_FALSE(std::equal(buff, buff + buff_len, + modBuff, modBuff + modBuff_len - 1) + ); + // test number of lines + EXPECT_GT(std::count(modBuff, modBuff + modBuff_len, '\n'), + buff_len / line_len + ); + // test buff len (should be a multiple of line_len plus \0) + EXPECT_EQ(modBuff_len % line_len, 1); + // test buff contents + EXPECT_TRUE((count4 > 1 && count5 == 1) || + (count5 > 1 && count4 == 1) + ); +} + +TEST_F(RadamsaRepeatLineMutatorTest, ThreeLines) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + size_t buff_len = 6; + size_t line_len = 2; + char* modBuff; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + buff[1] = '\n'; + buff[2] = '5'; + buff[3] = '\n'; + buff[4] = '6'; + buff[5] = '\n'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + int count4 = GetNumOcc(modString, "4\n"); + int count5 = GetNumOcc(modString, "5\n"); + int count6 = GetNumOcc(modString, "6\n"); + + // test buff ne + ASSERT_FALSE(std::equal(buff, buff + buff_len, + modBuff, modBuff + modBuff_len - 1) + ); + // test number of lines + EXPECT_GT(std::count(modBuff, modBuff + modBuff_len, '\n'), + buff_len / line_len + ); + // test buff len (should be a multiple of line_len plus \0) + EXPECT_EQ(modBuff_len % line_len, 1); + // test buff contents + EXPECT_TRUE((count4 > 1 && count5 == 1 && count6 == 1) || + (count5 > 1 && count4 == 1 && count6 == 1) || + (count6 > 1 && count4 == 1 && count5 == 1) + ); +} diff --git a/Radamsa/test/RadamsaSwapLineMutatorTest.cpp b/Radamsa/test/RadamsaSwapLineMutatorTest.cpp new file mode 100644 index 0000000..1707e74 --- /dev/null +++ b/Radamsa/test/RadamsaSwapLineMutatorTest.cpp @@ -0,0 +1,236 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaSwapLineMutator.hpp" +#include "RuntimeException.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaSwapLineMutator; +using vmf::BaseException; +using vmf::RuntimeException; + +class RadamsaSwapLineMutatorTest : public ::testing::Test { + protected: + RadamsaSwapLineMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaSwapLineMutator("RadamsaSwapLineMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaSwapLineMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + // int_key = registry->registerKey( + // "TEST_INT", + // StorageRegistry::INT, + // StorageRegistry::READ_WRITE + // ); + // normalTag = registry->registerTag( + // "RAN_SUCCESSFULLY", + // StorageRegistry::WRITE_ONLY + // ); + // // registry->validateRegistration(); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } + + RadamsaSwapLineMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; +}; + +/*TEST_F(RadamsaSwapLineMutatorTest, BufferNotNull) +{ + // no way to test this without mocks +}*/ + +TEST_F(RadamsaSwapLineMutatorTest, BufferSizeGEOne) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + // char* buff = baseEntry->allocateBuffer(testCaseKey, 1); + /* By not allocating the buffer, we're forcing + StorageEntry::getBufferSize() to return '-1'. + */ + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaSwapLineMutatorTest, OneLine) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + size_t buff_len = 2; + size_t line_len = 2; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + buff[1] = '\n'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaSwapLineMutatorTest, TwoLines) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + size_t buff_len = 4; + size_t line_len = 2; + char* modBuff; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + buff[1] = '\n'; + buff[2] = '5'; + buff[3] = '\n'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + + // test buff ne + // ASSERT_FALSE(std::equal(buff, buff + buff_len, + // modBuff, modBuff + modBuff_len - 1) + // ); + // test number of lines + EXPECT_EQ(std::count(modBuff, modBuff + modBuff_len, '\n'), + buff_len / line_len + ); + // test buff len + EXPECT_EQ(modBuff_len, buff_len + 1); + // test buff contents + EXPECT_TRUE(modString == "4\n5\n\0" || + modString == "5\n4\n\0"); +} + +TEST_F(RadamsaSwapLineMutatorTest, ThreeLines) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + size_t buff_len = 6; + size_t line_len = 2; + char* modBuff; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + buff[1] = '\n'; + buff[2] = '5'; + buff[3] = '\n'; + buff[4] = '6'; + buff[5] = '\n'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + + // test buff ne + // ASSERT_FALSE(std::equal(buff, buff + buff_len, + // modBuff, modBuff + modBuff_len - 1) + // ); + // test number of lines + EXPECT_EQ(std::count(modBuff, modBuff + modBuff_len, '\n'), + buff_len / line_len + ); + // test buff len + EXPECT_EQ(modBuff_len, buff_len + 1); + // test buff contents + EXPECT_TRUE(modString == "4\n5\n6\n\0" || + modString == "5\n4\n6\n\0" || + modString == "4\n6\n5\n\0" || + modString == "6\n5\n4\n\0" + ); +} diff --git a/Radamsa/test/byteMutationTest.cpp b/Radamsa/test/byteMutationTest.cpp deleted file mode 100644 index 93923c9..0000000 --- a/Radamsa/test/byteMutationTest.cpp +++ /dev/null @@ -1,715 +0,0 @@ -/* ============================================================================= -* Vader Modular Fuzzer -* Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. -* -* -* Effort sponsored by the U.S. Government under Other Transaction number -* W9124P-19-9-0001 between AMTC and the Government. The U.S. Government -* is authorized to reproduce and distribute reprints for Governmental purposes -* notwithstanding any copyright notation thereon. -* -* The views and conclusions contained herein are those of the authors and -* should not be interpreted as necessarily representing the official policies -* or endorsements, either expressed or implied, of the U.S. Government. -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -* -* @license GPL-3.0-or-later -* ===========================================================================*/ - -// VMF Includes -#include "byteMutationTest.h" - -namespace vader::test::modules::radamsa::mutations -{ -TEST_F(ByteMutationTest, TestDefaultConstructor) -{ - ASSERT_EQ(RANDOM_NUMBER_GENERATOR_, std::default_random_engine{}); -} - -TEST_F(ByteMutationTest, TestDropByte) -{ - // Test the DropByte() method in the ByteMutation class. - // The method accepts a character buffer, size, and a minimum seed index. - // The internal algorithm selects a random byte from the original character buffer, - // removes it, and copies the contents to a null-terminated character buffer. - - // The expected output data was gathered during a previous run using the default random seed. - // If the random seed is changed, the output data will also change and the unit tests will fail. - - constexpr size_t expectedSize{inputBufferSize_}; - - const std::map, const std::array> expectedOutput{ - {{0u, 0u}, {0x02, 0x03, 0x04, 0x05, 0x00}}, - {{0u, 1u}, {0x02, 0x03, 0x04, 0x05, 0x00}}, - {{0u, 2u}, {0x01, 0x02, 0x03, 0x04, 0x00}}, - {{0u, 3u}, {0x01, 0x02, 0x04, 0x05, 0x00}}, - {{0u, 4u}, {0x01, 0x02, 0x03, 0x05, 0x00}}, - {{0u, 5u}, {0x01, 0x03, 0x04, 0x05, 0x00}}, - {{0u, 6u}, {0x02, 0x03, 0x04, 0x05, 0x00}}, - {{0u, 7u}, {0x01, 0x02, 0x03, 0x04, 0x00}}, - {{0u, 8u}, {0x01, 0x02, 0x03, 0x04, 0x00}}, - {{0u, 9u}, {0x01, 0x02, 0x03, 0x04, 0x00}}, - - {{1u, 0u}, {0x01, 0x02, 0x04, 0x05, 0x00}}, - {{1u, 1u}, {0x01, 0x02, 0x03, 0x05, 0x00}}, - {{1u, 2u}, {0x01, 0x02, 0x03, 0x04, 0x00}}, - {{1u, 3u}, {0x01, 0x03, 0x04, 0x05, 0x00}}, - {{1u, 4u}, {0x01, 0x03, 0x04, 0x05, 0x00}}, - {{1u, 5u}, {0x01, 0x02, 0x03, 0x05, 0x00}}, - {{1u, 6u}, {0x01, 0x02, 0x03, 0x04, 0x00}}, - {{1u, 7u}, {0x01, 0x03, 0x04, 0x05, 0x00}}, - {{1u, 8u}, {0x01, 0x02, 0x04, 0x05, 0x00}}, - {{1u, 9u}, {0x01, 0x03, 0x04, 0x05, 0x00}}, - - {{2u, 0u}, {0x01, 0x02, 0x03, 0x05, 0x00}}, - {{2u, 1u}, {0x01, 0x02, 0x03, 0x04, 0x00}}, - {{2u, 2u}, {0x01, 0x02, 0x03, 0x04, 0x00}}, - {{2u, 3u}, {0x01, 0x02, 0x03, 0x04, 0x00}}, - {{2u, 4u}, {0x01, 0x02, 0x03, 0x04, 0x00}}, - {{2u, 5u}, {0x01, 0x02, 0x03, 0x04, 0x00}}, - {{2u, 6u}, {0x01, 0x02, 0x04, 0x05, 0x00}}, - {{2u, 7u}, {0x01, 0x02, 0x03, 0x04, 0x00}}, - {{2u, 8u}, {0x01, 0x02, 0x03, 0x05, 0x00}}, - {{2u, 9u}, {0x01, 0x02, 0x03, 0x04, 0x00}}, - - {{3u, 0u}, {0x01, 0x02, 0x03, 0x04, 0x00}}, - {{3u, 1u}, {0x01, 0x02, 0x03, 0x04, 0x00}}, - {{3u, 2u}, {0x01, 0x02, 0x03, 0x05, 0x00}}, - {{3u, 3u}, {0x01, 0x02, 0x03, 0x05, 0x00}}, - {{3u, 4u}, {0x01, 0x02, 0x03, 0x04, 0x00}}, - {{3u, 5u}, {0x01, 0x02, 0x03, 0x05, 0x00}}, - {{3u, 6u}, {0x01, 0x02, 0x03, 0x04, 0x00}}, - {{3u, 7u}, {0x01, 0x02, 0x03, 0x04, 0x00}}, - {{3u, 8u}, {0x01, 0x02, 0x03, 0x04, 0x00}}, - {{3u, 9u}, {0x01, 0x02, 0x03, 0x04, 0x00}}, - - {{4u, 0u}, {0x01, 0x02, 0x03, 0x04, 0x00}}, - {{4u, 1u}, {0x01, 0x02, 0x03, 0x04, 0x00}}, - {{4u, 2u}, {0x01, 0x02, 0x03, 0x04, 0x00}}, - {{4u, 3u}, {0x01, 0x02, 0x03, 0x04, 0x00}}, - {{4u, 4u}, {0x01, 0x02, 0x03, 0x04, 0x00}}, - {{4u, 5u}, {0x01, 0x02, 0x03, 0x04, 0x00}}, - {{4u, 6u}, {0x01, 0x02, 0x03, 0x04, 0x00}}, - {{4u, 7u}, {0x01, 0x02, 0x03, 0x04, 0x00}}, - {{4u, 8u}, {0x01, 0x02, 0x03, 0x04, 0x00}}, - {{4u, 9u}, {0x01, 0x02, 0x03, 0x04, 0x00}}}; - - using namespace std::placeholders; - - RunSubtest(expectedOutput, std::bind(&ByteMutations::DropByte, this, _1, _2, _3, _4, _5)); -} - -TEST_F(ByteMutationTest, TestFlipByte) -{ - // Test the FlipByte() method in the ByteMutation class. - // The method accepts a character buffer, size, and a minimum seed index. - // The internal algorithm selects a random byte from the original character buffer, - // flips it, and copies the contents to a null-terminated character buffer. - - - // The expected output data was gathered during a previous run using the default random seed. - // If the random seed is changed, the output data will also change and the unit tests will fail. - - constexpr size_t expectedSize_{inputBufferSize_ + 1u}; - - const std::map, const std::array> expectedOutput{ - {{0u, 0u}, {0x03, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{0u, 1u}, {0x01, 0x02, 0x03, 0x04, 0x15, 0x00}}, - {{0u, 2u}, {0x01, 0x02, 0x03, 0x06, 0x05, 0x00}}, - {{0u, 3u}, {0x41, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{0u, 4u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{0u, 5u}, {0x01, 0x02, 0x13, 0x04, 0x05, 0x00}}, - {{0u, 6u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{0u, 7u}, {0x11, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{0u, 8u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{0u, 9u}, {0x01, 0x02, 0x02, 0x04, 0x05, 0x00}}, - - {{1u, 0u}, {0x01, 0x02, 0x03, 0x44, 0x05, 0x00}}, - {{1u, 1u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{1u, 2u}, {0x01, 0x02, 0x03, 0x04, 0x15, 0x00}}, - {{1u, 3u}, {0x01, 0x22, 0x03, 0x04, 0x05, 0x00}}, - {{1u, 4u}, {0x01, 0x02, 0x03, 0x44, 0x05, 0x00}}, - {{1u, 5u}, {0x01, 0x02, 0x03, 0x04, 0x45, 0x00}}, - {{1u, 6u}, {0x01, 0x02, 0x02, 0x04, 0x05, 0x00}}, - {{1u, 7u}, {0x01, 0x02, 0x03, 0x04, 0x01, 0x00}}, - {{1u, 8u}, {0x01, 0x02, 0x03, 0x04, 0x45, 0x00}}, - {{1u, 9u}, {0x01, 0x02, 0x03, 0x04, 0x0d, 0x00}}, - - {{2u, 0u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{2u, 1u}, {0x01, 0x02, 0x03, 0x04, 0x45, 0x00}}, - {{2u, 2u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{2u, 3u}, {0x01, 0x02, 0x03, 0x04, -0x7b, 0x00}}, - {{2u, 4u}, {0x01, 0x02, 0x03, 0x0c, 0x05, 0x00}}, - {{2u, 5u}, {0x01, 0x02, 0x03, 0x04, 0x15, 0x00}}, - {{2u, 6u}, {0x01, 0x02, 0x07, 0x04, 0x05, 0x00}}, - {{2u, 7u}, {0x01, 0x02, 0x03, 0x06, 0x05, 0x00}}, - {{2u, 8u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{2u, 9u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - - {{3u, 0u}, {0x01, 0x02, 0x03, 0x04, 0x15, 0x00}}, - {{3u, 1u}, {0x01, 0x02, 0x03, 0x04, 0x01, 0x00}}, - {{3u, 2u}, {0x01, 0x02, 0x03, 0x04, 0x15, 0x00}}, - {{3u, 3u}, {0x01, 0x02, 0x03, 0x05, 0x05, 0x00}}, - {{3u, 4u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{3u, 5u}, {0x01, 0x02, 0x03, 0x04, 0x0d, 0x00}}, - {{3u, 6u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{3u, 7u}, {0x01, 0x02, 0x03, 0x04, 0x15, 0x00}}, - {{3u, 8u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{3u, 9u}, {0x01, 0x02, 0x03, 0x04, 0x45, 0x00}}, - - {{4u, 0u}, {0x01, 0x02, 0x03, 0x04, 0x07, 0x00}}, - {{4u, 1u}, {0x01, 0x02, 0x03, 0x04, 0x45, 0x00}}, - {{4u, 2u}, {0x01, 0x02, 0x03, 0x04, 0x25, 0x00}}, - {{4u, 3u}, {0x01, 0x02, 0x03, 0x04, 0x45, 0x00}}, - {{4u, 4u}, {0x01, 0x02, 0x03, 0x04, -0x7b, 0x00}}, - {{4u, 5u}, {0x01, 0x02, 0x03, 0x04, 0x01, 0x00}}, - {{4u, 6u}, {0x01, 0x02, 0x03, 0x04, 0x15, 0x00}}, - {{4u, 7u}, {0x01, 0x02, 0x03, 0x04, -0x7b, 0x00}}, - {{4u, 8u}, {0x01, 0x02, 0x03, 0x04, -0x7b, 0x00}}, - {{4u, 9u}, {0x01, 0x02, 0x03, 0x04, 0x0d, 0x00}}}; - - using namespace std::placeholders; - - RunSubtest(expectedOutput, std::bind(&ByteMutations::FlipByte, this, _1, _2, _3, _4, _5)); -} - -TEST_F(ByteMutationTest, TestInsertByte) -{ - // Test the InsertByte() method in the ByteMutation class. - // The method accepts a character buffer, size, and a minimum seed index. - // The internal algorithm selects a random byte from the original character buffer, - // inserts a random byte after it, and copies the contents to a null-terminated character buffer. - - // The expected output data was gathered during a previous run using the default random seed. - // If the random seed is changed, the output data will also change and the unit tests will fail. - - constexpr size_t expectedSize{inputBufferSize_ + 2u}; - - const std::map, const std::array> expectedOutput{ - {{0u, 0u}, {0x01, 0x10, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{0u, 1u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x3a, 0x00}}, - {{0u, 2u}, {0x01, 0x02, 0x03, 0x04, 0x1c, 0x05, 0x00}}, - {{0u, 3u}, {0x01, 0x56, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{0u, 4u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x77, 0x00}}, - {{0u, 5u}, {0x01, 0x02, 0x03, 0x42, 0x04, 0x05, 0x00}}, - {{0u, 6u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x04, 0x00}}, - {{0u, 7u}, {0x01, 0x43, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{0u, 8u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x00}}, - {{0u, 9u}, {0x01, 0x02, 0x03, 0x08, 0x04, 0x05, 0x00}}, - - {{1u, 0u}, {0x01, 0x02, 0x03, 0x04, 0x57, 0x05, 0x00}}, - {{1u, 1u}, {0x01, 0x02, 0x03, 0x04, 0x77, 0x05, 0x00}}, - {{1u, 2u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x43, 0x00}}, - {{1u, 3u}, {0x01, 0x02, 0x53, 0x03, 0x04, 0x05, 0x00}}, - {{1u, 4u}, {0x01, 0x02, 0x03, 0x04, 0x59, 0x05, 0x00}}, - {{1u, 5u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x61, 0x00}}, - {{1u, 6u}, {0x01, 0x02, 0x03, 0x06, 0x04, 0x05, 0x00}}, - {{1u, 7u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x2a, 0x00}}, - {{1u, 8u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x60, 0x00}}, - {{1u, 9u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x2e, 0x00}}, - - {{2u, 0u}, {0x01, 0x02, 0x03, 0x7d, 0x04, 0x05, 0x00}}, - {{2u, 1u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x60, 0x00}}, - {{2u, 2u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x09, 0x00}}, - {{2u, 3u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x71, 0x00}}, - {{2u, 4u}, {0x01, 0x02, 0x03, 0x04, 0x37, 0x05, 0x00}}, - {{2u, 5u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x3d, 0x00}}, - {{2u, 6u}, {0x01, 0x02, 0x03, 0x23, 0x04, 0x05, 0x00}}, - {{2u, 7u}, {0x01, 0x02, 0x03, 0x04, 0x15, 0x05, 0x00}}, - {{2u, 8u}, {0x01, 0x02, 0x03, 0x04, 0x72, 0x05, 0x00}}, - {{2u, 9u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x07, 0x00}}, - - {{3u, 0u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x40, 0x00}}, - {{3u, 1u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x28, 0x00}}, - {{3u, 2u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x3f, 0x00}}, - {{3u, 3u}, {0x01, 0x02, 0x03, 0x04, 0x0b, 0x05, 0x00}}, - {{3u, 4u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x09, 0x00}}, - {{3u, 5u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x31, 0x00}}, - {{3u, 6u}, {0x01, 0x02, 0x03, 0x04, 0x74, 0x05, 0x00}}, - {{3u, 7u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x3b, 0x00}}, - {{3u, 8u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00}}, - {{3u, 9u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x62, 0x00}}, - - {{4u, 0u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x10, 0x00}}, - {{4u, 1u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x58, 0x00}}, - {{4u, 2u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x50, 0x00}}, - {{4u, 3u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x5c, 0x00}}, - {{4u, 4u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x71, 0x00}}, - {{4u, 5u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x27, 0x00}}, - {{4u, 6u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x41, 0x00}}, - {{4u, 7u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x6c, 0x00}}, - {{4u, 8u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x6b, 0x00}}, - {{4u, 9u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x35, 0x00}}}; - - using namespace std::placeholders; - - RunSubtest(expectedOutput, std::bind(&ByteMutations::InsertByte, this, _1, _2, _3, _4, _5)); -} - -TEST_F(ByteMutationTest, TestIncrementByte) -{ - // Test the IncrementByte() method in the ByteMutation class. - // The method accepts a character buffer, size, and a minimum seed index. - // The internal algorithm selects a random byte from the original character buffer, - // increments it circularly, and copies the contents to a null-terminated character buffer. - - // The expected output data was gathered during a previous run using the default random seed. - // If the random seed is changed, the output data will also change and the unit tests will fail. - - constexpr size_t expectedSize{inputBufferSize_ + 1u}; - - const std::map, const std::array> expectedOutput{ - {{0u, 0u}, {0x02, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{0u, 1u}, {0x02, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{0u, 2u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}, - {{0u, 3u}, {0x01, 0x02, 0x04, 0x04, 0x05, 0x00}}, - {{0u, 4u}, {0x01, 0x02, 0x03, 0x05, 0x05, 0x00}}, - {{0u, 5u}, {0x01, 0x03, 0x03, 0x04, 0x05, 0x00}}, - {{0u, 6u}, {0x02, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{0u, 7u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}, - {{0u, 8u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}, - {{0u, 9u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}, - - {{1u, 0u}, {0x01, 0x02, 0x04, 0x04, 0x05, 0x00}}, - {{1u, 1u}, {0x01, 0x02, 0x03, 0x05, 0x05, 0x00}}, - {{1u, 2u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}, - {{1u, 3u}, {0x01, 0x03, 0x03, 0x04, 0x05, 0x00}}, - {{1u, 4u}, {0x01, 0x03, 0x03, 0x04, 0x05, 0x00}}, - {{1u, 5u}, {0x01, 0x02, 0x03, 0x05, 0x05, 0x00}}, - {{1u, 6u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}, - {{1u, 7u}, {0x01, 0x03, 0x03, 0x04, 0x05, 0x00}}, - {{1u, 8u}, {0x01, 0x02, 0x04, 0x04, 0x05, 0x00}}, - {{1u, 9u}, {0x01, 0x03, 0x03, 0x04, 0x05, 0x00}}, - - {{2u, 0u}, {0x01, 0x02, 0x03, 0x05, 0x05, 0x00}}, - {{2u, 1u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}, - {{2u, 2u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}, - {{2u, 3u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}, - {{2u, 4u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}, - {{2u, 5u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}, - {{2u, 6u}, {0x01, 0x02, 0x04, 0x04, 0x05, 0x00}}, - {{2u, 7u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}, - {{2u, 8u}, {0x01, 0x02, 0x03, 0x05, 0x05, 0x00}}, - {{2u, 9u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}, - - {{3u, 0u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}, - {{3u, 1u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}, - {{3u, 2u}, {0x01, 0x02, 0x03, 0x05, 0x05, 0x00}}, - {{3u, 3u}, {0x01, 0x02, 0x03, 0x05, 0x05, 0x00}}, - {{3u, 4u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}, - {{3u, 5u}, {0x01, 0x02, 0x03, 0x05, 0x05, 0x00}}, - {{3u, 6u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}, - {{3u, 7u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}, - {{3u, 8u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}, - {{3u, 9u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}, - - {{4u, 0u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}, - {{4u, 1u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}, - {{4u, 2u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}, - {{4u, 3u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}, - {{4u, 4u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}, - {{4u, 5u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}, - {{4u, 6u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}, - {{4u, 7u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}, - {{4u, 8u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}, - {{4u, 9u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}}; - - using namespace std::placeholders; - - RunSubtest(expectedOutput, std::bind(&ByteMutations::IncrementByte, this, _1, _2, _3, _4, _5)); -} - -TEST_F(ByteMutationTest, TestDecrementByte) -{ - // Test the DecrementByte() method in the ByteMutation class. - // The method accepts a character buffer, size, and a minimum seed index. - // The internal algorithm selects a random byte from the original character buffer, - // decrements it circularly, and copies the contents to a null-terminated character buffer. - - // The expected output data was gathered during a previous run using the default random seed. - // If the random seed is changed, the output data will also change and the unit tests will fail. - - constexpr size_t expectedSize{inputBufferSize_ + 1u}; - - const std::map, const std::array> expectedOutput{ - {{0u, 0u}, {0x00, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{0u, 1u}, {0x00, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{0u, 2u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{0u, 3u}, {0x01, 0x02, 0x02, 0x04, 0x05, 0x00}}, - {{0u, 4u}, {0x01, 0x02, 0x03, 0x03, 0x05, 0x00}}, - {{0u, 5u}, {0x01, 0x01, 0x03, 0x04, 0x05, 0x00}}, - {{0u, 6u}, {0x00, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{0u, 7u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{0u, 8u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{0u, 9u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - - {{1u, 0u}, {0x01, 0x02, 0x02, 0x04, 0x05, 0x00}}, - {{1u, 1u}, {0x01, 0x02, 0x03, 0x03, 0x05, 0x00}}, - {{1u, 2u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{1u, 3u}, {0x01, 0x01, 0x03, 0x04, 0x05, 0x00}}, - {{1u, 4u}, {0x01, 0x01, 0x03, 0x04, 0x05, 0x00}}, - {{1u, 5u}, {0x01, 0x02, 0x03, 0x03, 0x05, 0x00}}, - {{1u, 6u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{1u, 7u}, {0x01, 0x01, 0x03, 0x04, 0x05, 0x00}}, - {{1u, 8u}, {0x01, 0x02, 0x02, 0x04, 0x05, 0x00}}, - {{1u, 9u}, {0x01, 0x01, 0x03, 0x04, 0x05, 0x00}}, - - {{2u, 0u}, {0x01, 0x02, 0x03, 0x03, 0x05, 0x00}}, - {{2u, 1u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{2u, 2u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{2u, 3u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{2u, 4u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{2u, 5u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{2u, 6u}, {0x01, 0x02, 0x02, 0x04, 0x05, 0x00}}, - {{2u, 7u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{2u, 8u}, {0x01, 0x02, 0x03, 0x03, 0x05, 0x00}}, - {{2u, 9u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - - {{3u, 0u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{3u, 1u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{3u, 2u}, {0x01, 0x02, 0x03, 0x03, 0x05, 0x00}}, - {{3u, 3u}, {0x01, 0x02, 0x03, 0x03, 0x05, 0x00}}, - {{3u, 4u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{3u, 5u}, {0x01, 0x02, 0x03, 0x03, 0x05, 0x00}}, - {{3u, 6u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{3u, 7u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{3u, 8u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{3u, 9u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - - {{4u, 0u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{4u, 1u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{4u, 2u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{4u, 3u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{4u, 4u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{4u, 5u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{4u, 6u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{4u, 7u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{4u, 8u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{4u, 9u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}}; - - using namespace std::placeholders; - - RunSubtest(expectedOutput, std::bind(&ByteMutations::DecrementByte, this, _1, _2, _3, _4, _5)); -} - -TEST_F(ByteMutationTest, TestRandomizeByte) -{ - // Test the RandomizeByte() method in the ByteMutation class. - // The method accepts a character buffer, size, and a minimum seed index. - // The internal algorithm selects a random byte from the original character buffer, - // randomizes it, and copies the contents to a null-terminated character buffer. - - // The expected output data was gathered during a previous run using the default random seed. - // If the random seed is changed, the output data will also change and the unit tests will fail. - - constexpr size_t expectedSize{inputBufferSize_ + 1u}; - - const std::map, const std::array> expectedOutput{ - {{0u, 0u}, {0x10, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{0u, 1u}, {0x01, 0x02, 0x03, 0x04, 0x3a, 0x00}}, - {{0u, 2u}, {0x01, 0x02, 0x03, 0x1c, 0x05, 0x00}}, - {{0u, 3u}, {0x56, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{0u, 4u}, {0x01, 0x02, 0x03, 0x04, 0x77, 0x00}}, - {{0u, 5u}, {0x01, 0x02, 0x42, 0x04, 0x05, 0x00}}, - {{0u, 6u}, {0x01, 0x02, 0x03, 0x04, 0x04, 0x00}}, - {{0u, 7u}, {0x43, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{0u, 8u}, {0x01, 0x02, 0x03, 0x04, 0x00, 0x00}}, - {{0u, 9u}, {0x01, 0x02, 0x08, 0x04, 0x05, 0x00}}, - - {{1u, 0u}, {0x01, 0x02, 0x03, 0x57, 0x05, 0x00}}, - {{1u, 1u}, {0x01, 0x02, 0x03, 0x77, 0x05, 0x00}}, - {{1u, 2u}, {0x01, 0x02, 0x03, 0x04, 0x43, 0x00}}, - {{1u, 3u}, {0x01, 0x53, 0x03, 0x04, 0x05, 0x00}}, - {{1u, 4u}, {0x01, 0x02, 0x03, 0x59, 0x05, 0x00}}, - {{1u, 5u}, {0x01, 0x02, 0x03, 0x04, 0x61, 0x00}}, - {{1u, 6u}, {0x01, 0x02, 0x06, 0x04, 0x05, 0x00}}, - {{1u, 7u}, {0x01, 0x02, 0x03, 0x04, 0x2a, 0x00}}, - {{1u, 8u}, {0x01, 0x02, 0x03, 0x04, 0x60, 0x00}}, - {{1u, 9u}, {0x01, 0x02, 0x03, 0x04, 0x2e, 0x00}}, - - {{2u, 0u}, {0x01, 0x02, 0x7d, 0x04, 0x05, 0x00}}, - {{2u, 1u}, {0x01, 0x02, 0x03, 0x04, 0x60, 0x00}}, - {{2u, 2u}, {0x01, 0x02, 0x03, 0x04, 0x09, 0x00}}, - {{2u, 3u}, {0x01, 0x02, 0x03, 0x04, 0x71, 0x00}}, - {{2u, 4u}, {0x01, 0x02, 0x03, 0x37, 0x05, 0x00}}, - {{2u, 5u}, {0x01, 0x02, 0x03, 0x04, 0x3d, 0x00}}, - {{2u, 6u}, {0x01, 0x02, 0x23, 0x04, 0x05, 0x00}}, - {{2u, 7u}, {0x01, 0x02, 0x03, 0x15, 0x05, 0x00}}, - {{2u, 8u}, {0x01, 0x02, 0x03, 0x72, 0x05, 0x00}}, - {{2u, 9u}, {0x01, 0x02, 0x03, 0x04, 0x07, 0x00}}, - - {{3u, 0u}, {0x01, 0x02, 0x03, 0x04, 0x40, 0x00}}, - {{3u, 1u}, {0x01, 0x02, 0x03, 0x04, 0x28, 0x00}}, - {{3u, 2u}, {0x01, 0x02, 0x03, 0x04, 0x3f, 0x00}}, - {{3u, 3u}, {0x01, 0x02, 0x03, 0x0b, 0x05, 0x00}}, - {{3u, 4u}, {0x01, 0x02, 0x03, 0x04, 0x09, 0x00}}, - {{3u, 5u}, {0x01, 0x02, 0x03, 0x04, 0x31, 0x00}}, - {{3u, 6u}, {0x01, 0x02, 0x03, 0x74, 0x05, 0x00}}, - {{3u, 7u}, {0x01, 0x02, 0x03, 0x04, 0x3b, 0x00}}, - {{3u, 8u}, {0x01, 0x02, 0x03, 0x04, 0x06, 0x00}}, - {{3u, 9u}, {0x01, 0x02, 0x03, 0x04, 0x62, 0x00}}, - - {{4u, 0u}, {0x01, 0x02, 0x03, 0x04, 0x10, 0x00}}, - {{4u, 1u}, {0x01, 0x02, 0x03, 0x04, 0x58, 0x00}}, - {{4u, 2u}, {0x01, 0x02, 0x03, 0x04, 0x50, 0x00}}, - {{4u, 3u}, {0x01, 0x02, 0x03, 0x04, 0x5c, 0x00}}, - {{4u, 4u}, {0x01, 0x02, 0x03, 0x04, 0x71, 0x00}}, - {{4u, 5u}, {0x01, 0x02, 0x03, 0x04, 0x27, 0x00}}, - {{4u, 6u}, {0x01, 0x02, 0x03, 0x04, 0x41, 0x00}}, - {{4u, 7u}, {0x01, 0x02, 0x03, 0x04, 0x6c, 0x00}}, - {{4u, 8u}, {0x01, 0x02, 0x03, 0x04, 0x6b, 0x00}}, - {{4u, 9u}, {0x01, 0x02, 0x03, 0x04, 0x35, 0x00}}}; - - using namespace std::placeholders; - - RunSubtest(expectedOutput, std::bind(&ByteMutations::RandomizeByte, this, _1, _2, _3, _4, _5)); -} - -TEST_F(ByteMutationTest, TestRepeatByte) -{ - // Test the RepeatByte() method in the ByteMutation class. - // The method accepts a character buffer, size, and a minimum seed index. - // The internal algorithm selects a random byte from the original character buffer, - // repeats it a random number of times, and copies the contents to a null-terminated character buffer. - - try - { - using namespace std::placeholders; - - Byte_Mutation_Callback callback{std::bind(&ByteMutations::RepeatByte, this, _1, _2, _3, _4, _5)}; - - // Execute the callback 10 times per valid minimum seed index. - - constexpr size_t inputBufferSize{5u}; - - constexpr std::array minimumSeedIndices{0u, 1u, 2u, 3u, 4u}; - constexpr std::array inputBuffer{0x01u, 0x02u, 0x03u, 0x04u, 0x05u}; - - // The expected output data was gathered during a previous run using the default random seed. - // If the random seed is changed, the output data will also change and the unit tests will fail. - - std::map, std::tuple> expectedOutput{ - {{0u, 0u}, {0x05, 0x02, inputBufferSize + 0x02}}, - {{0u, 1u}, {0x05, 0x02, inputBufferSize + 0x02}}, - {{0u, 2u}, {0x04, 0x05, inputBufferSize + 0x05}}, - {{0u, 3u}, {0x01, 0x03, inputBufferSize + 0x03}}, - {{0u, 4u}, {0x03, 0x56, inputBufferSize + 0x56}}, - {{0u, 5u}, {0x05, 0x02, inputBufferSize + 0x02}}, - {{0u, 6u}, {0x05, 0x03, inputBufferSize + 0x03}}, - {{0u, 7u}, {0x05, 0x0a, inputBufferSize + 0x0a}}, - {{0u, 8u}, {0x05, 0x07, inputBufferSize + 0x07}}, - {{0u, 9u}, {0x05, 0x03, inputBufferSize + 0x03}}, - - {{1u, 0u}, {0x03, 0x03, inputBufferSize + 0x03}}, - {{1u, 1u}, {0x05, 0x03, inputBufferSize + 0x03}}, - {{1u, 2u}, {0x04, 0x06, inputBufferSize + 0x06}}, - {{1u, 3u}, {0x04, 0x06, inputBufferSize + 0x06}}, - {{1u, 4u}, {0x05, 0x02, inputBufferSize + 0x02}}, - {{1u, 5u}, {0x03, 0x03, inputBufferSize + 0x03}}, - {{1u, 6u}, {0x04, 0x04, inputBufferSize + 0x04}}, - {{1u, 7u}, {0x05, 0x08, inputBufferSize + 0x08}}, - {{1u, 8u}, {0x05, 0x02, inputBufferSize + 0x02}}, - {{1u, 9u}, {0x03, 0x29, inputBufferSize + 0x29}}, - - {{2u, 0u}, {0x05, 0x1d, inputBufferSize + 0x1d}}, - {{2u, 1u}, {0x03, 0x02, inputBufferSize + 0x02}}, - {{2u, 2u}, {0x04, 0x06, inputBufferSize + 0x06}}, - {{2u, 3u}, {0x05, 0x1d, inputBufferSize + 0x1d}}, - {{2u, 4u}, {0x04, 0x02, inputBufferSize + 0x02}}, - {{2u, 5u}, {0x03, 0x03, inputBufferSize + 0x03}}, - {{2u, 6u}, {0x04, 0x03, inputBufferSize + 0x03}}, - {{2u, 7u}, {0x04, 0x08, inputBufferSize + 0x08}}, - {{2u, 8u}, {0x05, 0x07, inputBufferSize + 0x07}}, - {{2u, 9u}, {0x04, 0x12, inputBufferSize + 0x12}}, - - {{3u, 0u}, {0x04, 0x03, inputBufferSize + 0x03}}, - {{3u, 1u}, {0x04, 0x05, inputBufferSize + 0x05}}, - {{3u, 2u}, {0x05, 0x05, inputBufferSize + 0x05}}, - {{3u, 3u}, {0x05, 0x04, inputBufferSize + 0x04}}, - {{3u, 4u}, {0x05, 0x02, inputBufferSize + 0x02}}, - {{3u, 5u}, {0x05, 0x06, inputBufferSize + 0x06}}, - {{3u, 6u}, {0x04, 0x04, inputBufferSize + 0x04}}, - {{3u, 7u}, {0x05, 0x02, inputBufferSize + 0x02}}, - {{3u, 8u}, {0x05, 0x02, inputBufferSize + 0x02}}, - {{3u, 9u}, {0x05, 0x59, inputBufferSize + 0x59}}, - - {{4u, 0u}, {0x05, 0x0004, inputBufferSize + 0x0004}}, - {{4u, 1u}, {0x05, 0x44cd, inputBufferSize + 0x44cd}}, - {{4u, 2u}, {0x05, 0x0003, inputBufferSize + 0x0003}}, - {{4u, 3u}, {0x05, 0x01c8, inputBufferSize + 0x01c8}}, - {{4u, 4u}, {0x05, 0x0005, inputBufferSize + 0x0005}}, - {{4u, 5u}, {0x05, 0x000a, inputBufferSize + 0x000a}}, - {{4u, 6u}, {0x05, 0x0006, inputBufferSize + 0x0006}}, - {{4u, 7u}, {0x05, 0x0003, inputBufferSize + 0x0003}}, - {{4u, 8u}, {0x05, 0x0082, inputBufferSize + 0x0082}}, - {{4u, 9u}, {0x05, 0x0002, inputBufferSize + 0x0002}}}; - - for (const auto& minimumSeedIndex : minimumSeedIndices) - { - constexpr size_t numberOfRandomDraws{10u}; - - for (size_t it{0u}; it < numberOfRandomDraws; ++it) - { - std::tuple, unsigned long> testCaseStorageTuple{ - RunByteMutationCallback( - inputBuffer.data(), - inputBuffer.size(), - minimumSeedIndex, - callback)}; - - const int testCaseKey{std::get<0u>(testCaseStorageTuple)}; - const unsigned long entryId{std::get<2u>(testCaseStorageTuple)}; - StorageEntry* storageEntryPtr{std::get<1u>(testCaseStorageTuple)->getEntryByID(entryId)}; - - const int outputBufferSize{storageEntryPtr->getBufferSize(testCaseKey)}; - const char* const outputBuffer{storageEntryPtr->getBufferPointer(testCaseKey)}; - - const std::tuple& expectedData{expectedOutput[std::make_pair(minimumSeedIndex, it)]}; - - const size_t expectedByteValue{std::get<0u>(expectedData)}; - const size_t numberOfExpectedByteRepetitions{std::get<1u>(expectedData)}; - const size_t expectedSize{std::get<2u>(expectedData)}; - - const char* const byteRepetitionIndex{std::adjacent_find(outputBuffer, outputBuffer + outputBufferSize)}; - const std::ptrdiff_t numberOfByteRepetitions{std::count(byteRepetitionIndex, outputBuffer + outputBufferSize, *byteRepetitionIndex)}; - - ASSERT_EQ(outputBufferSize, expectedSize); - EXPECT_EQ(outputBuffer[outputBufferSize - 1u], 0u); - EXPECT_EQ(expectedByteValue, *byteRepetitionIndex); - EXPECT_EQ(numberOfExpectedByteRepetitions, numberOfByteRepetitions); - } - } - - { - // Execute callback with an invalid minimum seed index. - - EXPECT_THROW( - RunByteMutationCallback( - inputBuffer.data(), - inputBuffer.size(), - inputBuffer.size(), // This minimum seed index is invalid - callback), - RuntimeException); - } - - { - // Execute callback with an invalid buffer size. - - constexpr int minimumSeedIndex{0u}; - - EXPECT_THROW( - RunByteMutationCallback( - inputBuffer.data(), - 0u, // This size is invalid - minimumSeedIndex, - callback), - RuntimeException); - } - - { - // Execute callback with an invalid buffer. - - constexpr int minimumSeedIndex{0u}; - - EXPECT_THROW( - RunByteMutationCallback( - nullptr, // This pointer is invalid - inputBuffer.size(), - minimumSeedIndex, - callback), - RuntimeException); - } - } - catch(...) - { - GTEST_DECORATOR << "Unknown Error occurred" << std::endl; - - EXPECT_TRUE(false); - } -} - -TEST_F(ByteMutationTest, TestPermuteByte) -{ - // Test the PermuteByte() method in the ByteMutation class. - // The method accepts a character buffer, size, and a minimum seed index. - // The internal algorithm randomizes bytes from the original character buffer - // and copies the contents to a null-terminated character buffer. - - // The expected output data was gathered during a previous run using the default random seed. - // If the random seed is changed, the output data will also change and the unit tests will fail. - - constexpr size_t expectedSize{inputBufferSize_ + 1u}; - - const std::map, const std::array> expectedOutput{ - {{0u, 0u}, {0x02, 0x01, 0x04, 0x03, 0x05, 0x00}}, - {{0u, 1u}, {0x01, 0x02, 0x05, 0x03, 0x04, 0x00}}, - {{0u, 2u}, {0x01, 0x04, 0x05, 0x03, 0x02, 0x00}}, - {{0u, 3u}, {0x02, 0x05, 0x01, 0x04, 0x03, 0x00}}, - {{0u, 4u}, {0x03, 0x05, 0x04, 0x02, 0x01, 0x00}}, - {{0u, 5u}, {0x02, 0x04, 0x03, 0x01, 0x05, 0x00}}, - {{0u, 6u}, {0x04, 0x03, 0x01, 0x05, 0x02, 0x00}}, - {{0u, 7u}, {0x02, 0x04, 0x01, 0x03, 0x05, 0x00}}, - {{0u, 8u}, {0x02, 0x05, 0x01, 0x04, 0x03, 0x00}}, - {{0u, 9u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x00}}, - - {{1u, 0u}, {0x01, 0x05, 0x02, 0x04, 0x03, 0x00}}, - {{1u, 1u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{1u, 2u}, {0x01, 0x03, 0x05, 0x04, 0x02, 0x00}}, - {{1u, 3u}, {0x01, 0x04, 0x03, 0x02, 0x05, 0x00}}, - {{1u, 4u}, {0x01, 0x04, 0x03, 0x05, 0x02, 0x00}}, - {{1u, 5u}, {0x01, 0x04, 0x02, 0x03, 0x05, 0x00}}, - {{1u, 6u}, {0x01, 0x03, 0x02, 0x05, 0x04, 0x00}}, - {{1u, 7u}, {0x01, 0x04, 0x02, 0x03, 0x05, 0x00}}, - {{1u, 8u}, {0x01, 0x02, 0x05, 0x03, 0x04, 0x00}}, - {{1u, 9u}, {0x01, 0x05, 0x02, 0x03, 0x04, 0x00}}, - - {{2u, 0u}, {0x01, 0x02, 0x03, 0x05, 0x04, 0x00}}, - {{2u, 1u}, {0x01, 0x02, 0x05, 0x03, 0x04, 0x00}}, - {{2u, 2u}, {0x01, 0x02, 0x04, 0x03, 0x05, 0x00}}, - {{2u, 3u}, {0x01, 0x02, 0x04, 0x03, 0x05, 0x00}}, - {{2u, 4u}, {0x01, 0x02, 0x05, 0x04, 0x03, 0x00}}, - {{2u, 5u}, {0x01, 0x02, 0x04, 0x03, 0x05, 0x00}}, - {{2u, 6u}, {0x01, 0x02, 0x05, 0x04, 0x03, 0x00}}, - {{2u, 7u}, {0x01, 0x02, 0x05, 0x03, 0x04, 0x00}}, - {{2u, 8u}, {0x01, 0x02, 0x04, 0x03, 0x05, 0x00}}, - {{2u, 9u}, {0x01, 0x02, 0x04, 0x05, 0x03, 0x00}}, - - {{3u, 0u}, {0x01, 0x02, 0x03, 0x05, 0x04, 0x00}}, - {{3u, 1u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{3u, 2u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{3u, 3u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{3u, 4u}, {0x01, 0x02, 0x03, 0x05, 0x04, 0x00}}, - {{3u, 5u}, {0x01, 0x02, 0x03, 0x05, 0x04, 0x00}}, - {{3u, 6u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{3u, 7u}, {0x01, 0x02, 0x03, 0x05, 0x04, 0x00}}, - {{3u, 8u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{3u, 9u}, {0x01, 0x02, 0x03, 0x05, 0x04, 0x00}}, - - {{4u, 0u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{4u, 1u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{4u, 2u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{4u, 3u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{4u, 4u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{4u, 5u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{4u, 6u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{4u, 7u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{4u, 8u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x00}}, - {{4u, 9u}, {0x01, 0x02, 0x03, 0x04, 0x05, 0x00}}}; - - using namespace std::placeholders; - - RunSubtest(expectedOutput, std::bind(&ByteMutations::PermuteByte, this, _1, _2, _3, _4, _5)); -} -} \ No newline at end of file diff --git a/Radamsa/test/byteMutationTest.h b/Radamsa/test/byteMutationTest.h deleted file mode 100644 index 5edf2a5..0000000 --- a/Radamsa/test/byteMutationTest.h +++ /dev/null @@ -1,195 +0,0 @@ -/* ============================================================================= -* Vader Modular Fuzzer -* Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. -* -* -* Effort sponsored by the U.S. Government under Other Transaction number -* W9124P-19-9-0001 between AMTC and the Government. The U.S. Government -* is authorized to reproduce and distribute reprints for Governmental purposes -* notwithstanding any copyright notation thereon. -* -* The views and conclusions contained herein are those of the authors and -* should not be interpreted as necessarily representing the official policies -* or endorsements, either expressed or implied, of the U.S. Government. -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -* -* @license GPL-3.0-or-later -* ===========================================================================*/ - -#pragma once - -#ifndef GTEST_DECORATOR -#define GTEST_DECORATOR std::cout << "\033[32m[ ] \033[37m[ INFO ] " -#endif - -// C/C++ Includes -#include -#include -#include - -// Google Test Includes -#include "gtest/gtest.h" - -// VMF Includes -#include "SimpleStorage.hpp" -#include "byteMutations.hpp" - -namespace vader::test::modules::radamsa::mutations -{ -class ByteMutationTest : public ::testing::Test, - public ::vader::radamsa::mutations::ByteMutations -{ -public: - virtual ~ByteMutationTest() = default; - - ByteMutationTest() : ::vader::radamsa::mutations::ByteMutations{randomNumberGenerator_} {} - -protected: - typedef std::function Byte_Mutation_Callback; - - static constexpr size_t inputBufferSize_{5u}; - - std::tuple, unsigned long> RunByteMutationCallback( - const char* inputBuffer, - const int size, - const int minimumSeedIndex, - const Byte_Mutation_Callback& callback) const - { - // Subtest prologue - Get testcase key and storage entry - - std::unique_ptr storage{std::make_unique("storage")}; - std::unique_ptr registry{ - std::make_unique( - "TEST_INT", - vader::StorageRegistry::INT, - vader::StorageRegistry::ASCENDING)}; - std::unique_ptr metadata{std::make_unique()}; - - const int testCaseKey{ - registry->registerKey( - "TEST_CASE", - vader::StorageRegistry::BUFFER, - vader::StorageRegistry::READ_WRITE)}; - - storage->configure(registry.get(), metadata.get()); - - vader::StorageEntry* storageEntryPtr{storage->createNewEntry()}; - - storage->saveEntry(storageEntryPtr); - - // Execute the subtest against the desired callback. - - callback( - storageEntryPtr, - size, - inputBuffer, - minimumSeedIndex, - testCaseKey); - - return std::make_tuple(testCaseKey, std::move(storage), storageEntryPtr->getID()); - } - - template - void RunSubtest( - const std::map, const std::array>& expectedOutput, - const Byte_Mutation_Callback& callback) const - { - try - { - // Execute the callback 10 times per valid minimum seed index. - - for (const auto& minimumSeedIndex : minimumSeedIndices_) - { - constexpr size_t numberOfRandomDraws{10u}; - - for (size_t it{0u}; it < numberOfRandomDraws; ++it) - { - std::tuple, unsigned long> testCaseStorageTuple{ - RunByteMutationCallback( - inputBuffer_.data(), - inputBuffer_.size(), - minimumSeedIndex, - callback)}; - - const int testCaseKey{std::get<0u>(testCaseStorageTuple)}; - const unsigned long entryId{std::get<2u>(testCaseStorageTuple)}; - StorageEntry* storageEntryPtr{std::get<1u>(testCaseStorageTuple)->getEntryByID(entryId)}; - - const int outputBufferSize{storageEntryPtr->getBufferSize(testCaseKey)}; - const char* const outputBuffer{storageEntryPtr->getBufferPointer(testCaseKey)}; - - const std::array& expectedBuffer{expectedOutput.at(std::make_pair(minimumSeedIndex, it))}; - - ASSERT_EQ(outputBufferSize, N); - EXPECT_EQ(outputBuffer[outputBufferSize - 1u], 0u); - EXPECT_EQ(memcmp(outputBuffer, expectedBuffer.data(), outputBufferSize), 0); - } - } - - { - // Execute callback with an invalid minimum seed index. - - EXPECT_THROW( - RunByteMutationCallback( - inputBuffer_.data(), - inputBuffer_.size(), - inputBuffer_.size(), // This minimum seed index is invalid - callback), - RuntimeException); - } - - { - // Execute callback with an invalid buffer size. - - constexpr int minimumSeedIndex{0u}; - - EXPECT_THROW( - RunByteMutationCallback( - inputBuffer_.data(), - 0u, // This size is invalid - minimumSeedIndex, - callback), - RuntimeException); - } - - { - // Execute callback with an invalid buffer. - - constexpr int minimumSeedIndex{0u}; - - EXPECT_THROW( - RunByteMutationCallback( - nullptr, // This pointer is invalid - inputBuffer_.size(), - minimumSeedIndex, - callback), - RuntimeException); - } - } - catch(...) - { - GTEST_DECORATOR << "Unknown Error occurred" << std::endl; - - EXPECT_TRUE(false); - } - } - -private: - static constexpr std::array minimumSeedIndices_{0u, 1u, 2u, 3u, 4u}; - static constexpr std::array inputBuffer_{0x01u, 0x02u, 0x03u, 0x04u, 0x05u}; - - std::default_random_engine randomNumberGenerator_; -}; -} \ No newline at end of file diff --git a/Radamsa/test/config/experimentalModules.yaml b/Radamsa/test/config/experimentalModules.yaml index 0c41d36..fec73f3 100644 --- a/Radamsa/test/config/experimentalModules.yaml +++ b/Radamsa/test/config/experimentalModules.yaml @@ -9,6 +9,7 @@ vmfModules: - className: AFLForkserverExecutor - className: AFLFeedback - className: SaveCorpusOutput + - className: ComputeStats - className: StatsOutput GeneticAlgorithmInputGenerator: children: @@ -32,3 +33,11 @@ vmfModules: - className: RadamsaIncrementByteMutator - className: RadamsaDecrementByteMutator - className: RadamsaRandomizeByteMutator + +# Modules-specific parameters +#(The SUT-specific portions of these all defined using YAML anchors) +AFLForkserverExecutor: + sutArgv: *SUT_ARGV + +DirectoryBasedSeedGen: + inputDir: *INPUT_DIR \ No newline at end of file diff --git a/Radamsa/test/lineMutationTest.cpp b/Radamsa/test/lineMutationTest.cpp deleted file mode 100644 index 73d8851..0000000 --- a/Radamsa/test/lineMutationTest.cpp +++ /dev/null @@ -1,4647 +0,0 @@ -/* ============================================================================= -* Vader Modular Fuzzer -* Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. -* -* -* Effort sponsored by the U.S. Government under Other Transaction number -* W9124P-19-9-0001 between AMTC and the Government. The U.S. Government -* is authorized to reproduce and distribute reprints for Governmental purposes -* notwithstanding any copyright notation thereon. -* -* The views and conclusions contained herein are those of the authors and -* should not be interpreted as necessarily representing the official policies -* or endorsements, either expressed or implied, of the U.S. Government. -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -* -* @license GPL-3.0-or-later -* ===========================================================================*/ - -// VMF Includes -#include "lineMutationTest.h" - -namespace vader::test::modules::radamsa::mutations -{ -TEST_F(LineMutationTest, TestDefaultConstructor) -{ - ASSERT_EQ(RANDOM_NUMBER_GENERATOR_, std::default_random_engine{}); -} - -TEST_F(LineMutationTest, TestGetNumberOfLinesAfterIndex) -{ - // Test the GetNumberOfLinesAfterIndex() method in the LineMutations class. - // The method accepts a character buffer, size, and a character index. - // The total number of lines in the character buffer should be returned. - - const std::map expectedOutput{ - {0u, 5u}, {1u, 5u}, - {2u, 5u}, {3u, 5u}, - {4u, 5u}, {5u, 5u}, - - {6u, 4u}, {7u, 4u}, - {8u, 4u}, {9u, 4u}, - {10u, 4u}, {11u, 4u}, - - {12u, 3u}, {13u, 3u}, - {14u, 3u}, {15u, 3u}, - {16u, 3u}, {17u, 3u}, - - {18u, 2u}, {19u, 2u}, - {20u, 2u}, {21u, 2u}, - {22u, 2u}, {23u, 2u}, - - {24u, 1u}, {25u, 1u}, - {26u, 1u}, {27u, 1u}, - {28u, 1u}, {29u, 1u}, - {30u, 1u}}; - - { - // Valid Input - This subtest should count the number of lines in the buffer and execute successfuly. - - for (const auto& it : expectedOutput) - { - const size_t index{it.first}; - const size_t expectedNumberOfLines{it.second}; - - ASSERT_EQ(GetNumberOfLinesAfterIndex(asciiInputBuffer_, sizeof(asciiInputBuffer_), index), expectedNumberOfLines); - } - } - - { - // Valid Input - This subtest should count the number of lines in the null buffer of size 1 and execute successfuly. - - constexpr char validBuffer[]{'\0'}; - constexpr int validBufferSize{sizeof(validBuffer)}; - constexpr int validIndex{0}; - constexpr int expectedNumberOfLines{1}; - - ASSERT_EQ(GetNumberOfLinesAfterIndex(validBuffer, validBufferSize, validIndex), expectedNumberOfLines); - } - - { - // Valid Input - This subtest should count the number of lines in the null buffer of size 2 and execute successfuly. - - constexpr char validBuffer[]{"\0"}; - constexpr int validBufferSize{sizeof(validBuffer)}; - constexpr int validIndex{1}; - constexpr int expectedNumberOfLines{1}; - - ASSERT_EQ(GetNumberOfLinesAfterIndex(validBuffer, validBufferSize, validIndex), expectedNumberOfLines); - } - - { - // Valid Input - This subtest should count the number of lines in the newline buffer of size 1 and execute successfuly. - - constexpr char validBuffer[]{'\n'}; - constexpr int validBufferSize{sizeof(validBuffer)}; - constexpr int validIndex{0u}; - constexpr int expectedNumberOfLines{2}; - - ASSERT_EQ(GetNumberOfLinesAfterIndex(validBuffer, validBufferSize, validIndex), expectedNumberOfLines); - } - - { - // Valid Input - This subtest should count the number of lines in the newline buffer of size 2 and execute successfuly. - - constexpr char validBuffer[]{"\n"}; - constexpr int validBufferSize{sizeof(validBuffer)}; - constexpr int validIndex{0u}; - constexpr int expectedNumberOfLines{2}; - - ASSERT_EQ(GetNumberOfLinesAfterIndex(validBuffer, validBufferSize, validIndex), expectedNumberOfLines); - } - - { - // Valid Input - This subtest should count the number of lines in the buffer and execute successfuly. - - constexpr char validBuffer[]{"line1\nline2\0\nline3"}; - constexpr int validBufferSize{sizeof(validBuffer)}; - constexpr int validIndex{0u}; - constexpr int expectedNumberOfLines{3}; - - ASSERT_EQ(GetNumberOfLinesAfterIndex(validBuffer, validBufferSize, validIndex), expectedNumberOfLines); - } - - { - // Valid Input - This subtest should count the number of lines in the buffer, but ignore all newlines after the null terminator. - - constexpr char validBuffer[]{"line1\nline2\0\nline3"}; - const int validBufferSize{static_cast(strlen(validBuffer))}; - constexpr int validIndex{0u}; - constexpr int expectedNumberOfLines{2}; - - ASSERT_EQ(GetNumberOfLinesAfterIndex(validBuffer, validBufferSize, validIndex), expectedNumberOfLines); - } - - { - // Erroneous Input - This subtest should trigger a runtime exception since the buffer size is 0. - - constexpr int invalidBufferSize{0}; - constexpr int validIndex{0}; - - EXPECT_THROW(GetNumberOfLinesAfterIndex(asciiInputBuffer_, invalidBufferSize, validIndex), RuntimeException); - } - - { - // Erroneous Input - This subtest should trigger a runtime exception since the index is greater than the buffer size. - - constexpr int validBufferSize{sizeof(asciiInputBuffer_)}; - constexpr int invalidIndex{sizeof(asciiInputBuffer_)}; - - EXPECT_THROW(GetNumberOfLinesAfterIndex(asciiInputBuffer_, validBufferSize, invalidIndex), RuntimeException); - } - - { - // Erroneous Input - This subtest should trigger a runtime exception since the buffer is null. - - constexpr int validBufferSize{sizeof(asciiInputBuffer_)}; - constexpr int validIndex{0u}; - - EXPECT_THROW(GetNumberOfLinesAfterIndex(nullptr, validBufferSize, validIndex), RuntimeException); - } -} - -TEST_F(LineMutationTest, TestGetLineData) -{ - // Test the GetLineData() method in the LineMutations class. - // The method accepts a character buffer, size, line index, and number of lines after index. - // A structure containing information about the line in the character buffer should be returned. - - typedef size_t character_index, line_index; - - auto runGetNumberOfLinesAfterIndexMethod{ - [&](const std::map, Line>& expectedOutputData) - { - for (const auto& it : expectedOutputData) - { - const character_index characterIndex{it.first.first}; - const line_index lineIndex{it.first.second}; - - const size_t numberOfLinesAfterIndex{ - GetNumberOfLinesAfterIndex( - asciiInputBuffer_, - sizeof(asciiInputBuffer_), - characterIndex)}; - - ASSERT_EQ( - it.second, - GetLineData( - asciiInputBuffer_, - sizeof(asciiInputBuffer_), - lineIndex, - numberOfLinesAfterIndex)); - }}}; - - { - // Valid Input - This subtest should return the line data information associated with the buffer and execute successfuly. - // The character indices and line indices are within the expected bounds. - - const std::map, Line> expectedOutput{ - {{0u, 0u}, Line{true, 0u, 6u}}, {{1u, 0u}, Line{true, 0u, 6u}}, - {{2u, 0u}, Line{true, 0u, 6u}}, {{3u, 0u}, Line{true, 0u, 6u}}, - {{4u, 0u}, Line{true, 0u, 6u}}, {{5u, 0u}, Line{true, 0u, 6u}}, - {{6u, 0u}, Line{true, 6u, 6u}}, {{7u, 0u}, Line{true, 6u, 6u}}, - {{8u, 0u}, Line{true, 6u, 6u}}, {{9u, 0u}, Line{true, 6u, 6u}}, - {{10u, 0u}, Line{true, 6u, 6u}}, {{11u, 0u}, Line{true, 6u, 6u}}, - {{12u, 0u}, Line{true, 12u, 6u}}, {{13u, 0u}, Line{true, 12u, 6u}}, - {{14u, 0u}, Line{true, 12u, 6u}}, {{15u, 0u}, Line{true, 12u, 6u}}, - {{16u, 0u}, Line{true, 12u, 6u}}, {{17u, 0u}, Line{true, 12u, 6u}}, - {{18u, 0u}, Line{true, 18u, 6u}}, {{19u, 0u}, Line{true, 18u, 6u}}, - {{20u, 0u}, Line{true, 18u, 6u}}, {{21u, 0u}, Line{true, 18u, 6u}}, - {{22u, 0u}, Line{true, 18u, 6u}}, {{23u, 0u}, Line{true, 18u, 6u}}, - {{24u, 0u}, Line{true, 24u, 7u}}, {{25u, 0u}, Line{true, 24u, 7u}}, - {{26u, 0u}, Line{true, 24u, 7u}}, {{27u, 0u}, Line{true, 24u, 7u}}, - {{28u, 0u}, Line{true, 24u, 7u}}, {{29u, 0u}, Line{true, 24u, 7u}}, - {{30u, 0u}, Line{true, 24u, 7u}}, - - {{0u, 1u}, Line{true, 6u, 6u}}, {{1u, 1u}, Line{true, 6u, 6u}}, - {{2u, 1u}, Line{true, 6u, 6u}}, {{3u, 1u}, Line{true, 6u, 6u}}, - {{4u, 1u}, Line{true, 6u, 6u}}, {{5u, 1u}, Line{true, 6u, 6u}}, - {{6u, 1u}, Line{true, 12u, 6u}}, {{7u, 1u}, Line{true, 12u, 6u}}, - {{8u, 1u}, Line{true, 12u, 6u}}, {{9u, 1u}, Line{true, 12u, 6u}}, - {{10u, 1u}, Line{true, 12u, 6u}}, {{11u, 1u}, Line{true, 12u, 6u}}, - {{12u, 1u}, Line{true, 18u, 6u}}, {{13u, 1u}, Line{true, 18u, 6u}}, - {{14u, 1u}, Line{true, 18u, 6u}}, {{15u, 1u}, Line{true, 18u, 6u}}, - {{16u, 1u}, Line{true, 18u, 6u}}, {{17u, 1u}, Line{true, 18u, 6u}}, - {{18u, 1u}, Line{true, 24u, 7u}}, {{19u, 1u}, Line{true, 24u, 7u}}, - {{20u, 1u}, Line{true, 24u, 7u}}, {{21u, 1u}, Line{true, 24u, 7u}}, - {{22u, 1u}, Line{true, 24u, 7u}}, {{23u, 1u}, Line{true, 24u, 7u}}, - {{24u, 1u}, Line{true, 24u, 7u}}, {{25u, 1u}, Line{true, 24u, 7u}}, - {{26u, 1u}, Line{true, 24u, 7u}}, {{27u, 1u}, Line{true, 24u, 7u}}, - {{28u, 1u}, Line{true, 24u, 7u}}, {{29u, 1u}, Line{true, 24u, 7u}}, - {{30u, 1u}, Line{true, 24u, 7u}}, - - {{0u, 2u}, Line{true, 12u, 6u}}, {{1u, 2u}, Line{true, 12u, 6u}}, - {{2u, 2u}, Line{true, 12u, 6u}}, {{3u, 2u}, Line{true, 12u, 6u}}, - {{4u, 2u}, Line{true, 12u, 6u}}, {{5u, 2u}, Line{true, 12u, 6u}}, - {{6u, 2u}, Line{true, 18u, 6u}}, {{7u, 2u}, Line{true, 18u, 6u}}, - {{8u, 2u}, Line{true, 18u, 6u}}, {{9u, 2u}, Line{true, 18u, 6u}}, - {{10u, 2u}, Line{true, 18u, 6u}}, {{11u, 2u}, Line{true, 18u, 6u}}, - {{12u, 2u}, Line{true, 24u, 7u}}, {{13u, 2u}, Line{true, 24u, 7u}}, - {{14u, 2u}, Line{true, 24u, 7u}}, {{15u, 2u}, Line{true, 24u, 7u}}, - {{16u, 2u}, Line{true, 24u, 7u}}, {{17u, 2u}, Line{true, 24u, 7u}}, - {{18u, 2u}, Line{true, 24u, 7u}}, {{19u, 2u}, Line{true, 24u, 7u}}, - {{20u, 2u}, Line{true, 24u, 7u}}, {{21u, 2u}, Line{true, 24u, 7u}}, - {{22u, 2u}, Line{true, 24u, 7u}}, {{23u, 2u}, Line{true, 24u, 7u}}, - {{24u, 2u}, Line{true, 24u, 7u}}, {{25u, 2u}, Line{true, 24u, 7u}}, - {{26u, 2u}, Line{true, 24u, 7u}}, {{27u, 2u}, Line{true, 24u, 7u}}, - {{28u, 2u}, Line{true, 24u, 7u}}, {{29u, 2u}, Line{true, 24u, 7u}}, - {{30u, 2u}, Line{true, 24u, 7u}}, - - {{0u, 3u}, Line{true, 18u, 6u}}, {{1u, 3u}, Line{true, 18u, 6u}}, - {{2u, 3u}, Line{true, 18u, 6u}}, {{3u, 3u}, Line{true, 18u, 6u}}, - {{4u, 3u}, Line{true, 18u, 6u}}, {{5u, 3u}, Line{true, 18u, 6u}}, - {{6u, 3u}, Line{true, 24u, 7u}}, {{7u, 3u}, Line{true, 24u, 7u}}, - {{8u, 3u}, Line{true, 24u, 7u}}, {{9u, 3u}, Line{true, 24u, 7u}}, - {{10u, 3u}, Line{true, 24u, 7u}}, {{11u, 3u}, Line{true, 24u, 7u}}, - {{12u, 3u}, Line{true, 24u, 7u}}, {{13u, 3u}, Line{true, 24u, 7u}}, - {{14u, 3u}, Line{true, 24u, 7u}}, {{15u, 3u}, Line{true, 24u, 7u}}, - {{16u, 3u}, Line{true, 24u, 7u}}, {{17u, 3u}, Line{true, 24u, 7u}}, - {{18u, 3u}, Line{true, 24u, 7u}}, {{19u, 3u}, Line{true, 24u, 7u}}, - {{20u, 3u}, Line{true, 24u, 7u}}, {{21u, 3u}, Line{true, 24u, 7u}}, - {{22u, 3u}, Line{true, 24u, 7u}}, {{23u, 3u}, Line{true, 24u, 7u}}, - {{24u, 3u}, Line{true, 24u, 7u}}, {{25u, 3u}, Line{true, 24u, 7u}}, - {{26u, 3u}, Line{true, 24u, 7u}}, {{27u, 3u}, Line{true, 24u, 7u}}, - {{28u, 3u}, Line{true, 24u, 7u}}, {{29u, 3u}, Line{true, 24u, 7u}}, - {{30u, 3u}, Line{true, 24u, 7u}}, - - {{0u, 4u}, Line{true, 24u, 7u}}, {{1u, 4u}, Line{true, 24u, 7u}}, - {{2u, 4u}, Line{true, 24u, 7u}}, {{3u, 4u}, Line{true, 24u, 7u}}, - {{4u, 4u}, Line{true, 24u, 7u}}, {{5u, 4u}, Line{true, 24u, 7u}}, - {{6u, 4u}, Line{true, 24u, 7u}}, {{7u, 4u}, Line{true, 24u, 7u}}, - {{8u, 4u}, Line{true, 24u, 7u}}, {{9u, 4u}, Line{true, 24u, 7u}}, - {{10u, 4u}, Line{true, 24u, 7u}}, {{11u, 4u}, Line{true, 24u, 7u}}, - {{12u, 4u}, Line{true, 24u, 7u}}, {{13u, 4u}, Line{true, 24u, 7u}}, - {{14u, 4u}, Line{true, 24u, 7u}}, {{15u, 4u}, Line{true, 24u, 7u}}, - {{16u, 4u}, Line{true, 24u, 7u}}, {{17u, 4u}, Line{true, 24u, 7u}}, - {{18u, 4u}, Line{true, 24u, 7u}}, {{19u, 4u}, Line{true, 24u, 7u}}, - {{20u, 4u}, Line{true, 24u, 7u}}, {{21u, 4u}, Line{true, 24u, 7u}}, - {{22u, 4u}, Line{true, 24u, 7u}}, {{23u, 4u}, Line{true, 24u, 7u}}, - {{24u, 4u}, Line{true, 24u, 7u}}, {{25u, 4u}, Line{true, 24u, 7u}}, - {{26u, 4u}, Line{true, 24u, 7u}}, {{27u, 4u}, Line{true, 24u, 7u}}, - {{28u, 4u}, Line{true, 24u, 7u}}, {{29u, 4u}, Line{true, 24u, 7u}}, - {{30u, 4u}, Line{true, 24u, 7u}}}; - - runGetNumberOfLinesAfterIndexMethod(expectedOutput); - } - - { - // Erroneous Input - This subtest should throw an exception since the line index exceeds the maximum allowable limit. - - const character_index characterIndex{0u}; - - const size_t numberOfLinesAfterIndex{ - GetNumberOfLinesAfterIndex( - asciiInputBuffer_, - sizeof(asciiInputBuffer_), - characterIndex)}; - - const size_t invalidLineIndex{numberOfLinesAfterIndex}; - - ASSERT_THROW( - GetLineData( - asciiInputBuffer_, - sizeof(asciiInputBuffer_), - invalidLineIndex, - numberOfLinesAfterIndex), - RuntimeException); - } - - { - // Erroneous Input - This subtest should throw an exception since the number of lines after index exceeds the maximum allowable limit. - - const character_index characterIndex{0u}; - - const size_t invalidNumberOfLinesAfterIndex{ - GetNumberOfLinesAfterIndex( - asciiInputBuffer_, - sizeof(asciiInputBuffer_), - characterIndex) + 1u}; - - const size_t lineIndex{0u}; - - ASSERT_THROW( - GetLineData( - asciiInputBuffer_, - sizeof(asciiInputBuffer_), - lineIndex, - invalidNumberOfLinesAfterIndex);, - RuntimeException); - } -} - -TEST_F(LineMutationTest, TestDeleteLine) -{ - // Test the DeleteLine() method in the LineMutations class. - // The method accepts a character buffer, size, and character index. - // If the original character buffer is ASCII, the internal algorithm selects a selects a random line - // removes it, and copies the contents to a null-terminated character buffer. - // If the original character buffer is UTF-8, no line is removed and the - // original contents are copied to a null-terminated character buffer. - - // The expected output data was gathered during a previous run using the default random seed. - // If the random seed is changed, the output data will also change and the unit tests will fail. - - const std::map, std::pair> asciiOutput{ - {{0u, 0u}, {"Line1\nLine2\nLine3\nLine4\0\0", 26}}, - {{0u, 1u}, {"Line1\nLine2\nLine3\nLine4\0\0", 26}}, - {{0u, 2u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{0u, 3u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{0u, 4u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{0u, 5u}, {"Line0\nLine2\nLine3\nLine4\0\0", 26}}, - {{0u, 6u}, {"Line1\nLine2\nLine3\nLine4\0\0", 26}}, - {{0u, 7u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{0u, 8u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{0u, 9u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - - {{1u, 0u}, {"Line0\nLine2\nLine3\nLine4\0\0", 26}}, - {{1u, 1u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{1u, 2u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{1u, 3u}, {"Line1\nLine2\nLine3\nLine4\0\0", 26}}, - {{1u, 4u}, {"Line1\nLine2\nLine3\nLine4\0\0", 26}}, - {{1u, 5u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{1u, 6u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{1u, 7u}, {"Line1\nLine2\nLine3\nLine4\0\0", 26}}, - {{1u, 8u}, {"Line0\nLine2\nLine3\nLine4\0\0", 26}}, - {{1u, 9u}, {"Line1\nLine2\nLine3\nLine4\0\0", 26}}, - - {{2u, 0u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{2u, 1u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{2u, 2u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{2u, 3u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{2u, 4u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{2u, 5u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{2u, 6u}, {"Line1\nLine2\nLine3\nLine4\0\0", 26}}, - {{2u, 7u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{2u, 8u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{2u, 9u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - - {{3u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{3u, 1u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{3u, 2u}, {"Line0\nLine2\nLine3\nLine4\0\0", 26}}, - {{3u, 3u}, {"Line1\nLine2\nLine3\nLine4\0\0", 26}}, - {{3u, 4u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{3u, 5u}, {"Line0\nLine2\nLine3\nLine4\0\0", 26}}, - {{3u, 6u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{3u, 7u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{3u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{3u, 9u}, {"Line0\nLine2\nLine3\nLine4\0\0", 26}}, - - {{4u, 0u}, {"Line0\nLine2\nLine3\nLine4\0\0", 26}}, - {{4u, 1u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{4u, 2u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{4u, 3u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{4u, 4u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{4u, 5u}, {"Line1\nLine2\nLine3\nLine4\0\0", 26}}, - {{4u, 6u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{4u, 7u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{4u, 8u}, {"Line0\nLine2\nLine3\nLine4\0\0", 26}}, - {{4u, 9u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - - {{5u, 0u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{5u, 1u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{5u, 2u}, {"Line0\nLine2\nLine3\nLine4\0\0", 26}}, - {{5u, 3u}, {"Line0\nLine2\nLine3\nLine4\0\0", 26}}, - {{5u, 4u}, {"Line0\nLine2\nLine3\nLine4\0\0", 26}}, - {{5u, 5u}, {"Line1\nLine2\nLine3\nLine4\0\0", 26}}, - {{5u, 6u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{5u, 7u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{5u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{5u, 9u}, {"Line1\nLine2\nLine3\nLine4\0\0", 26}}, - - {{6u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{6u, 1u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{6u, 2u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{6u, 3u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{6u, 4u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{6u, 5u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{6u, 6u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{6u, 7u}, {"Line0\nLine2\nLine3\nLine4\0\0", 26}}, - {{6u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{6u, 9u}, {"Line0\nLine2\nLine3\nLine4\0\0", 26}}, - - {{7u, 0u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{7u, 1u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{7u, 2u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{7u, 3u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{7u, 4u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{7u, 5u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{7u, 6u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{7u, 7u}, {"Line0\nLine2\nLine3\nLine4\0\0", 26}}, - {{7u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{7u, 9u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - - {{8u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{8u, 1u}, {"Line0\nLine2\nLine3\nLine4\0\0", 26}}, - {{8u, 2u}, {"Line0\nLine2\nLine3\nLine4\0\0", 26}}, - {{8u, 3u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{8u, 4u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{8u, 5u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{8u, 6u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{8u, 7u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{8u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{8u, 9u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - - {{9u, 0u}, {"Line0\nLine2\nLine3\nLine4\0\0", 26}}, - {{9u, 1u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{9u, 2u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{9u, 3u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{9u, 4u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{9u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{9u, 6u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{9u, 7u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{9u, 8u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{9u, 9u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - - {{10u, 0u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{10u, 1u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{10u, 2u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{10u, 3u}, {"Line0\nLine2\nLine3\nLine4\0\0", 26}}, - {{10u, 4u}, {"Line0\nLine2\nLine3\nLine4\0\0", 26}}, - {{10u, 5u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{10u, 6u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{10u, 7u}, {"Line0\nLine2\nLine3\nLine4\0\0", 26}}, - {{10u, 8u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{10u, 9u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - - {{11u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{11u, 1u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{11u, 2u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{11u, 3u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{11u, 4u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{11u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{11u, 6u}, {"Line0\nLine2\nLine3\nLine4\0\0", 26}}, - {{11u, 7u}, {"Line0\nLine2\nLine3\nLine4\0\0", 26}}, - {{11u, 8u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{11u, 9u}, {"Line0\nLine2\nLine3\nLine4\0\0", 26}}, - - {{12u, 0u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{12u, 1u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{12u, 2u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{12u, 3u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{12u, 4u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{12u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{12u, 6u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{12u, 7u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{12u, 8u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{12u, 9u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - - {{13u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{13u, 1u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{13u, 2u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{13u, 3u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{13u, 4u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{13u, 5u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{13u, 6u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{13u, 7u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{13u, 8u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{13u, 9u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - - {{14u, 0u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{14u, 1u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{14u, 2u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{14u, 3u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{14u, 4u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{14u, 5u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{14u, 6u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{14u, 7u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{14u, 8u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{14u, 9u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - - {{15u, 0u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{15u, 1u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{15u, 2u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{15u, 3u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{15u, 4u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{15u, 5u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{15u, 6u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{15u, 7u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{15u, 8u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{15u, 9u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - - {{16u, 0u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{16u, 1u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{16u, 2u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{16u, 3u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{16u, 4u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{16u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{16u, 6u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{16u, 7u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{16u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{16u, 9u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - - {{17u, 0u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{17u, 1u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{17u, 2u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{17u, 3u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{17u, 4u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{17u, 5u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{17u, 6u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{17u, 7u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{17u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{17u, 9u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - - {{18u, 0u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{18u, 1u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{18u, 2u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{18u, 3u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{18u, 4u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{18u, 5u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{18u, 6u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{18u, 7u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{18u, 8u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{18u, 9u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - - {{19u, 0u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{19u, 1u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{19u, 2u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{19u, 3u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{19u, 4u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{19u, 5u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{19u, 6u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{19u, 7u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{19u, 8u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{19u, 9u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - - {{20u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{20u, 1u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{20u, 2u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{20u, 3u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{20u, 4u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{20u, 5u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{20u, 6u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{20u, 7u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{20u, 8u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{20u, 9u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - - {{21u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{21u, 1u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{21u, 2u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{21u, 3u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{21u, 4u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{21u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{21u, 6u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{21u, 7u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{21u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{21u, 9u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - - {{22u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{22u, 1u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{22u, 2u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{22u, 3u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{22u, 4u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{22u, 5u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{22u, 6u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{22u, 7u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{22u, 8u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{22u, 9u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - - {{23u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{23u, 1u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{23u, 2u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{23u, 3u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{23u, 4u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{23u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{23u, 6u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{23u, 7u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{23u, 8u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{23u, 9u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - - {{24u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{24u, 1u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{24u, 2u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{24u, 3u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{24u, 4u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{24u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{24u, 6u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{24u, 7u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{24u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{24u, 9u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - - {{25u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{25u, 1u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{25u, 2u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{25u, 3u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{25u, 4u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{25u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{25u, 6u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{25u, 7u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{25u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{25u, 9u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - - - {{26u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{26u, 1u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{26u, 2u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{26u, 3u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{26u, 4u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{26u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{26u, 6u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{26u, 7u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{26u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{26u, 9u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - - {{27u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{27u, 1u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{27u, 2u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{27u, 3u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{27u, 4u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{27u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{27u, 6u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{27u, 7u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{27u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{27u, 9u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - - {{28u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{28u, 1u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{28u, 2u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{28u, 3u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{28u, 4u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{28u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{28u, 6u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{28u, 7u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{28u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{28u, 9u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - - {{29u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{29u, 1u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{29u, 2u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{29u, 3u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{29u, 4u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{29u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{29u, 6u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{29u, 7u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{29u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{29u, 9u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - - {{30u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{30u, 1u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{30u, 2u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{30u, 3u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{30u, 4u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{30u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{30u, 6u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{30u, 7u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{30u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{30u, 9u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}}; - - const std::map, std::pair> utf8Output{ - {{0u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{0u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{0u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{0u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{0u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{0u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{0u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{0u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{0u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{0u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{1u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{1u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{1u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{1u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{1u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{1u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{1u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{1u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{1u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{1u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{2u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{2u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{2u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{2u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{2u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{2u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{2u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{2u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{2u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{2u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{3u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{3u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{3u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{3u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{3u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{3u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{3u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{3u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{3u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{3u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{4u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{4u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{4u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{4u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{4u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{4u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{4u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{4u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{4u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{4u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{5u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{5u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{5u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{5u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{5u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{5u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{5u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{5u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{5u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{5u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{6u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{6u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{6u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{6u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{6u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{6u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{6u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{6u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{6u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{6u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{7u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{7u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{7u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{7u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{7u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{7u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{7u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{7u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{7u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{7u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{8u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{8u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{8u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{8u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{8u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{8u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{8u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{8u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{8u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{8u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{9u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{9u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{9u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{9u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{9u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{9u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{9u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{9u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{9u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{9u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{10u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{10u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{10u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{10u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{10u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{10u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{10u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{10u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{10u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{10u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{11u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{11u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{11u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{11u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{11u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{11u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{11u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{11u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{11u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{11u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{12u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{12u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{12u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{12u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{12u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{12u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{12u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{12u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{12u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{12u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{13u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{13u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{13u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{13u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{13u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{13u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{13u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{13u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{13u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{13u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{14u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{14u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{14u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{14u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{14u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{14u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{14u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{14u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{14u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{14u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{15u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{15u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{15u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{15u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{15u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{15u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{15u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{15u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{15u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{15u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{16u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{16u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{16u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{16u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{16u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{16u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{16u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{16u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{16u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{16u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{17u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{17u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{17u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{17u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{17u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{17u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{17u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{17u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{17u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{17u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{18u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{18u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{18u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{18u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{18u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{18u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{18u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{18u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{18u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{18u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{19u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{19u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{19u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{19u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{19u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{19u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{19u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{19u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{19u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{19u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{20u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{20u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{20u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{20u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{20u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{20u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{20u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{20u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{20u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{20u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{21u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{21u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{21u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{21u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{21u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{21u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{21u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{21u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{21u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{21u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{22u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{22u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{22u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{22u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{22u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{22u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{22u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{22u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{22u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{22u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{23u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{23u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{23u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{23u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{23u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{23u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{23u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{23u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{23u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{23u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{24u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{24u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{24u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{24u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{24u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{24u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{24u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{24u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{24u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{24u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{25u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{25u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{25u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{25u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{25u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{25u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{25u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{25u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{25u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{25u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{26u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{26u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{26u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{26u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{26u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{26u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{26u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{26u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{26u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{26u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{27u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{27u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{27u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{27u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{27u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{27u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{27u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{27u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{27u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{27u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{28u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{28u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{28u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{28u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{28u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{28u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{28u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{28u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{28u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{28u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{29u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{29u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{29u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{29u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{29u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{29u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{29u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{29u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{29u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{29u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{30u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{30u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{30u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{30u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{30u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{30u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{30u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{30u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{30u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{30u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}}; - - using namespace std::placeholders; - - RunSubtest( - asciiInputBuffer_, - sizeof(asciiInputBuffer_), - asciiOutput, - std::bind(&LineMutations::DeleteLine, this, _1, _2, _3, _4, _5)); - - RunSubtest( - utf8InputBuffer_, - sizeof(utf8InputBuffer_), - utf8Output, - std::bind(&LineMutations::DeleteLine, this, _1, _2, _3, _4, _5)); -} - -TEST_F(LineMutationTest, TestIsBinarish) -{ - // Test the IsBinarish() method in the LineMutations class. - // The method accepts a character buffer and size. - // A boolean flag indicating whether or not the input buffer contains UTF-8 encoding is returned. - - { - // Valid Input - This subtest should indicate that the input does not contain UTF-8 encoding. - - ASSERT_FALSE(IsBinarish(asciiInputBuffer_, sizeof(asciiInputBuffer_))); - } - - { - // Valid Input - This subtest should indicate that the input contains UTF-8 encoding. - - ASSERT_TRUE(IsBinarish(utf8InputBuffer_, sizeof(utf8InputBuffer_))); - } - - { - // Valid Input - This subtest should indicate that the input does not contain UTF-8 encoding. - - constexpr char validBuffer[]{'a'}; - constexpr int validBufferSize{sizeof(validBuffer)}; - - ASSERT_FALSE(IsBinarish(validBuffer, validBufferSize)); - } - - { - // Valid Input - This subtest should indicate that the input contains null. - - constexpr char validBuffer[]{"\0"}; - constexpr int validBufferSize{sizeof(validBuffer)}; - - ASSERT_TRUE(IsBinarish(validBuffer, validBufferSize)); - } - - { - // Erroneous Input - This subtest should trigger a runtime exception since the buffer size is 0. - - constexpr char validBuffer[]{'a'}; - constexpr int invalidBufferSize{0}; - - EXPECT_THROW(IsBinarish(validBuffer, invalidBufferSize), RuntimeException); - } - - { - // Erroneous Input - This subtest should trigger a runtime exception since the buffer is null. - - constexpr int validBufferSize{sizeof(asciiInputBuffer_)}; - - EXPECT_THROW(IsBinarish(nullptr, validBufferSize), RuntimeException); - } -} - -TEST_F(LineMutationTest, TestDeleteSequentialLines) -{ - // Test the DeleteSequentialLines() method in the LineMutations class. - // The method accepts a character buffer, size, and character index. - // If the original character buffer is ASCII, the internal algorithm selects a selects sequential random lines, - // removes them, and copies the contents to a null-terminated character buffer. - // If the original character buffer is UTF-8, no lines are removed and the - // original contents are copied to a null-terminated character buffer. - - // The expected output data was gathered during a previous run using the default random seed. - // If the random seed is changed, the output data will also change and the unit tests will fail. - - const std::map, std::pair> asciiOutput{ - {{0u, 0u}, {"Line1\nLine2\nLine3\nLine4\0\0", 26}}, - {{0u, 1u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{0u, 2u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{0u, 3u}, {"Line4\0\0", 8}}, - {{0u, 4u}, {"Line0\nLine1\nLine2\n", 19}}, - {{0u, 5u}, {"Line0\nLine4\0\0", 14}}, - {{0u, 6u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{0u, 7u}, {"Line3\nLine4\0\0", 14}}, - {{0u, 8u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{0u, 9u}, {"Line0\nLine2\nLine3\nLine4\0\0", 26}}, - - {{1u, 0u}, {"Line0\nLine1\n", 13}}, - {{1u, 1u}, {"Line0\nLine1\n", 13}}, - {{1u, 2u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{1u, 3u}, {"Line4\0\0", 8}}, - {{1u, 4u}, {"Line0\nLine1\n", 13}}, - {{1u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{1u, 6u}, {"Line0\nLine2\nLine3\nLine4\0\0", 26}}, - {{1u, 7u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{1u, 8u}, {"Line0\nLine1\nLine2\n", 19}}, - {{1u, 9u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - - {{2u, 0u}, {"Line0\n", 7}}, - {{2u, 1u}, {"Line0\nLine1\nLine2\n", 19}}, - {{2u, 2u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{2u, 3u}, {"Line0\nLine1\nLine2\n", 19}}, - {{2u, 4u}, {"Line0\nLine3\nLine4\0\0", 20}}, - {{2u, 5u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{2u, 6u}, {"Line0\nLine3\nLine4\0\0", 20}}, - {{2u, 7u}, {"Line0\nLine2\nLine3\nLine4\0\0", 26}}, - {{2u, 8u}, {"Line0\nLine1\n", 13}}, - {{2u, 9u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - - {{3u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{3u, 1u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{3u, 2u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{3u, 3u}, {"Line0\nLine2\nLine3\nLine4\0\0", 26}}, - {{3u, 4u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{3u, 5u}, {"Line0\nLine1\nLine4\0\0", 20}}, - {{3u, 6u}, {"Line0\n", 7}}, - {{3u, 7u}, {"Line0\nLine1\nLine4\0\0", 20}}, - {{3u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{3u, 9u}, {"Line0\nLine1\nLine2\n", 19}}, - - {{4u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{4u, 1u}, {"Line4\0\0", 8}}, - {{4u, 2u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{4u, 3u}, {"Line0\nLine1\nLine2\n", 19}}, - {{4u, 4u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{4u, 5u}, {"Line0\nLine3\nLine4\0\0", 20}}, - {{4u, 6u}, {"Line0\nLine4\0\0", 14}}, - {{4u, 7u}, {"Line0\nLine1\n", 13}}, - {{4u, 8u}, {"Line0\nLine1\n", 13}}, - {{4u, 9u}, {"Line0\nLine3\nLine4\0\0", 20}}, - - {{5u, 0u}, {"Line0\nLine1\nLine4\0\0", 20}}, - {{5u, 1u}, {"Line0\nLine2\nLine3\nLine4\0\0", 26}}, - {{5u, 2u}, {"Line3\nLine4\0\0", 14}}, - {{5u, 3u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{5u, 4u}, {"Line0\nLine1\nLine4\0\0", 20}}, - {{5u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{5u, 6u}, {"Line0\nLine1\n", 13}}, - {{5u, 7u}, {"Line0\nLine1\nLine2\n", 19}}, - {{5u, 8u}, {"Line2\nLine3\nLine4\0\0", 20}}, - {{5u, 9u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - - {{6u, 0u}, {"Line0\nLine3\nLine4\0\0", 20}}, - {{6u, 1u}, {"Line0\nLine3\nLine4\0\0", 20}}, - {{6u, 2u}, {"Line0\nLine4\0\0", 14}}, - {{6u, 3u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{6u, 4u}, {"Line0\nLine3\nLine4\0\0", 20}}, - {{6u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{6u, 6u}, {"Line0\nLine4\0\0", 14}}, - {{6u, 7u}, {"Line0\nLine1\nLine4\0\0", 20}}, - {{6u, 8u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{6u, 9u}, {"Line0\nLine1\nLine2\n", 19}}, - - {{7u, 0u}, {"Line0\nLine1\nLine2\n", 19}}, - {{7u, 1u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{7u, 2u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{7u, 3u}, {"Line0\nLine4\0\0", 14}}, - {{7u, 4u}, {"Line0\nLine1\nLine4\0\0", 20}}, - {{7u, 5u}, {"Line0\nLine1\n", 13}}, - {{7u, 6u}, {"Line0\nLine2\nLine3\nLine4\0\0", 26}}, - {{7u, 7u}, {"Line0\nLine1\nLine4\0\0", 20}}, - {{7u, 8u}, {"Line0\nLine4\0\0", 14}}, - {{7u, 9u}, {"Line0\nLine1\nLine2\n", 19}}, - - {{8u, 0u}, {"Line0\nLine3\nLine4\0\0", 20}}, - {{8u, 1u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{8u, 2u}, {"Line0\n", 7}}, - {{8u, 3u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{8u, 4u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{8u, 5u}, {"Line0\n", 7}}, - {{8u, 6u}, {"Line0\nLine2\nLine3\nLine4\0\0", 26}}, - {{8u, 7u}, {"Line0\nLine3\nLine4\0\0", 20}}, - {{8u, 8u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{8u, 9u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - - {{9u, 0u}, {"Line0\nLine1\nLine4\0\0", 20}}, - {{9u, 1u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{9u, 2u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{9u, 3u}, {"Line0\nLine1\nLine2\n", 19}}, - {{9u, 4u}, {"Line0\nLine1\n", 13}}, - {{9u, 5u}, {"Line0\nLine1\nLine4\0\0", 20}}, - {{9u, 6u}, {"Line0\nLine1\nLine2\n", 19}}, - {{9u, 7u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{9u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{9u, 9u}, {"Line0\nLine1\n", 13}}, - - {{10u, 0u}, {"Line0\nLine1\nLine2\n", 19}}, - {{10u, 1u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{10u, 2u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{10u, 3u}, {"Line0\nLine1\nLine2\n", 19}}, - {{10u, 4u}, {"Line0\nLine3\nLine4\0\0", 20}}, - {{10u, 5u}, {"Line0\nLine1\nLine2\n", 19}}, - {{10u, 6u}, {"Line0\nLine1\n", 13}}, - {{10u, 7u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{10u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{10u, 9u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - - {{11u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{11u, 1u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{11u, 2u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{11u, 3u}, {"Line0\nLine1\nLine2\n", 19}}, - {{11u, 4u}, {"Line0\n", 7}}, - {{11u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{11u, 6u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{11u, 7u}, {"Line0\nLine1\n", 13}}, - {{11u, 8u}, {"Line0\nLine3\nLine4\0\0", 20}}, - {{11u, 9u}, {"Line0\nLine1\nLine4\0\0", 20}}, - - {{12u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{12u, 1u}, {"Line0\nLine1\nLine2\n", 19}}, - {{12u, 2u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{12u, 3u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{12u, 4u}, {"Line0\nLine1\nLine2\n", 19}}, - {{12u, 5u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{12u, 6u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{12u, 7u}, {"Line0\nLine1\nLine4\0\0", 20}}, - {{12u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{12u, 9u}, {"Line0\nLine1\n", 13}}, - - {{13u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{13u, 1u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{13u, 2u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{13u, 3u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{13u, 4u}, {"Line0\nLine1\nLine4\0\0", 20}}, - {{13u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{13u, 6u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{13u, 7u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{13u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{13u, 9u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - - {{14u, 0u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{14u, 1u}, {"Line0\nLine1\n", 13}}, - {{14u, 2u}, {"Line0\nLine1\n", 13}}, - {{14u, 3u}, {"Line0\nLine1\nLine4\0\0", 20}}, - {{14u, 4u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{14u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{14u, 6u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{14u, 7u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{14u, 8u}, {"Line0\nLine1\nLine4\0\0", 20}}, - {{14u, 9u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - - {{15u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{15u, 1u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{15u, 2u}, {"Line0\nLine1\nLine4\0\0", 20}}, - {{15u, 3u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{15u, 4u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{15u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{15u, 6u}, {"Line0\nLine1\nLine2\n", 19}}, - {{15u, 7u}, {"Line0\nLine1\n", 13}}, - {{15u, 8u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{15u, 9u}, {"Line0\nLine1\nLine2\n", 19}}, - - {{16u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{16u, 1u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{16u, 2u}, {"Line0\nLine1\nLine4\0\0", 20}}, - {{16u, 3u}, {"Line0\nLine1\nLine4\0\0", 20}}, - {{16u, 4u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{16u, 5u}, {"Line0\nLine1\nLine4\0\0", 20}}, - {{16u, 6u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{16u, 7u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{16u, 8u}, {"Line0\nLine1\nLine3\nLine4\0\0", 26}}, - {{16u, 9u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - - {{17u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{17u, 1u}, {"Line0\nLine1\nLine2\n", 19}}, - {{17u, 2u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{17u, 3u}, {"Line0\nLine1\nLine2\n", 19}}, - {{17u, 4u}, {"Line0\nLine1\nLine4\0\0", 20}}, - {{17u, 5u}, {"Line0\nLine1\nLine2\n", 19}}, - {{17u, 6u}, {"Line0\nLine1\nLine2\n", 19}}, - {{17u, 7u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{17u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{17u, 9u}, {"Line0\nLine1\nLine2\n", 19}}, - - {{18u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{18u, 1u}, {"Line0\nLine1\nLine2\n", 19}}, - {{18u, 2u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{18u, 3u}, {"Line0\nLine1\nLine2\n", 19}}, - {{18u, 4u}, {"Line0\nLine1\nLine2\n", 19}}, - {{18u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{18u, 6u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{18u, 7u}, {"Line0\nLine1\nLine2\n", 19}}, - {{18u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{18u, 9u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - - {{19u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{19u, 1u}, {"Line0\nLine1\nLine2\n", 19}}, - {{19u, 2u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{19u, 3u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{19u, 4u}, {"Line0\nLine1\nLine2\n", 19}}, - {{19u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{19u, 6u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{19u, 7u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{19u, 8u}, {"Line0\nLine1\nLine2\n", 19}}, - {{19u, 9u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - - {{20u, 0u}, {"Line0\nLine1\nLine2\n", 19}}, - {{20u, 1u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{20u, 2u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{20u, 3u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{20u, 4u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{20u, 5u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{20u, 6u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{20u, 7u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{20u, 8u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{20u, 9u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - - {{21u, 0u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{21u, 1u}, {"Line0\nLine1\nLine2\n", 19}}, - {{21u, 2u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{21u, 3u}, {"Line0\nLine1\nLine2\n", 19}}, - {{21u, 4u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{21u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{21u, 6u}, {"Line0\nLine1\nLine2\n", 19}}, - {{21u, 7u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{21u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{21u, 9u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - - {{22u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{22u, 1u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{22u, 2u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{22u, 3u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{22u, 4u}, {"Line0\nLine1\nLine2\n", 19}}, - {{22u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{22u, 6u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{22u, 7u}, {"Line0\nLine1\nLine2\n", 19}}, - {{22u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{22u, 9u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - - {{23u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{23u, 1u}, {"Line0\nLine1\nLine2\n", 19}}, - {{23u, 2u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{23u, 3u}, {"Line0\nLine1\nLine2\n", 19}}, - {{23u, 4u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{23u, 5u}, {"Line0\nLine1\nLine2\n", 19}}, - {{23u, 6u}, {"Line0\nLine1\nLine2\nLine4\0\0", 26}}, - {{23u, 7u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{23u, 8u}, {"Line0\nLine1\nLine2\n", 19}}, - {{23u, 9u}, {"Line0\nLine1\nLine2\n", 19}}, - - {{24u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{24u, 1u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{24u, 2u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{24u, 3u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{24u, 4u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{24u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{24u, 6u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{24u, 7u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{24u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{24u, 9u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - - {{25u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{25u, 1u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{25u, 2u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{25u, 3u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{25u, 4u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{25u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{25u, 6u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{25u, 7u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{25u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{25u, 9u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - - {{26u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{26u, 1u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{26u, 2u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{26u, 3u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{26u, 4u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{26u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{26u, 6u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{26u, 7u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{26u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{26u, 9u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - - {{27u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{27u, 1u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{27u, 2u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{27u, 3u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{27u, 4u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{27u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{27u, 6u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{27u, 7u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{27u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{27u, 9u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - - {{28u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{28u, 1u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{28u, 2u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{28u, 3u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{28u, 4u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{28u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{28u, 6u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{28u, 7u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{28u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{28u, 9u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - - {{29u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{29u, 1u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{29u, 2u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{29u, 3u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{29u, 4u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{29u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{29u, 6u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{29u, 7u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{29u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{29u, 9u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - - {{30u, 0u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{30u, 1u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{30u, 2u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{30u, 3u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{30u, 4u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{30u, 5u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{30u, 6u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{30u, 7u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{30u, 8u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}, - {{30u, 9u}, {"Line0\nLine1\nLine2\nLine3\n", 25}}}; - - const std::map, std::pair> utf8Output{ - {{0u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{0u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{0u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{0u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{0u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{0u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{0u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{0u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{0u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{0u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{1u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{1u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{1u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{1u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{1u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{1u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{1u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{1u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{1u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{1u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{2u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{2u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{2u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{2u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{2u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{2u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{2u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{2u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{2u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{2u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{3u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{3u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{3u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{3u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{3u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{3u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{3u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{3u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{3u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{3u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{4u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{4u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{4u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{4u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{4u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{4u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{4u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{4u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{4u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{4u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{5u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{5u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{5u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{5u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{5u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{5u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{5u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{5u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{5u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{5u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{6u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{6u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{6u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{6u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{6u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{6u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{6u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{6u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{6u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{6u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{7u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{7u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{7u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{7u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{7u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{7u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{7u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{7u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{7u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{7u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{8u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{8u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{8u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{8u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{8u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{8u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{8u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{8u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{8u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{8u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{9u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{9u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{9u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{9u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{9u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{9u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{9u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{9u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{9u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{9u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{10u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{10u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{10u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{10u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{10u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{10u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{10u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{10u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{10u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{10u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{11u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{11u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{11u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{11u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{11u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{11u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{11u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{11u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{11u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{11u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{12u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{12u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{12u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{12u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{12u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{12u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{12u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{12u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{12u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{12u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{13u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{13u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{13u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{13u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{13u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{13u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{13u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{13u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{13u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{13u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{14u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{14u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{14u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{14u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{14u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{14u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{14u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{14u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{14u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{14u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{15u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{15u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{15u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{15u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{15u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{15u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{15u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{15u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{15u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{15u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{16u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{16u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{16u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{16u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{16u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{16u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{16u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{16u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{16u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{16u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{17u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{17u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{17u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{17u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{17u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{17u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{17u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{17u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{17u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{17u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{18u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{18u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{18u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{18u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{18u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{18u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{18u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{18u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{18u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{18u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{19u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{19u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{19u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{19u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{19u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{19u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{19u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{19u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{19u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{19u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{20u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{20u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{20u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{20u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{20u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{20u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{20u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{20u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{20u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{20u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{21u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{21u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{21u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{21u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{21u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{21u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{21u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{21u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{21u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{21u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{22u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{22u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{22u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{22u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{22u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{22u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{22u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{22u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{22u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{22u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{23u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{23u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{23u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{23u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{23u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{23u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{23u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{23u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{23u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{23u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{24u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{24u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{24u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{24u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{24u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{24u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{24u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{24u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{24u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{24u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{25u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{25u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{25u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{25u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{25u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{25u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{25u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{25u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{25u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{25u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{26u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{26u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{26u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{26u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{26u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{26u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{26u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{26u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{26u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{26u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{27u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{27u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{27u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{27u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{27u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{27u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{27u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{27u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{27u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{27u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{28u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{28u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{28u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{28u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{28u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{28u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{28u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{28u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{28u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{28u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{29u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{29u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{29u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{29u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{29u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{29u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{29u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{29u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{29u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{29u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{30u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{30u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{30u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{30u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{30u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{30u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{30u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{30u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{30u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{30u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}}; - - using namespace std::placeholders; - - RunSubtest( - asciiInputBuffer_, - sizeof(asciiInputBuffer_), - asciiOutput, - std::bind(&LineMutations::DeleteSequentialLines, this, _1, _2, _3, _4, _5)); - - RunSubtest( - utf8InputBuffer_, - sizeof(utf8InputBuffer_), - utf8Output, - std::bind(&LineMutations::DeleteSequentialLines, this, _1, _2, _3, _4, _5)); -} - -TEST_F(LineMutationTest, TestDuplicateLine) -{ - // Test the DuplicateLine() method in the LineMutations class. - // The method accepts a character buffer, size, and character index. - // If the original character buffer is UTF-8, the internal algorithm selects a selects a random line, - // duplicates it, and copies the contents to a null-terminated character buffer. - // If the original character buffer is ASCII, no lines are removed and the - // original contents are copied to a null-terminated character buffer. - - // The expected output data was gathered during a previous run using the default random seed. - // If the random seed is changed, the output data will also change and the unit tests will fail. - - const std::map, std::pair> asciiOutput{ - {{0u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{0u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{0u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{0u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{0u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{0u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{0u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{0u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{0u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{0u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{1u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{1u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{1u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{1u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{1u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{1u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{1u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{1u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{1u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{1u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{2u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{2u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{2u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{2u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{2u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{2u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{2u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{2u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{2u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{2u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{3u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{3u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{3u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{3u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{3u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{3u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{3u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{3u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{3u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{3u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{4u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{4u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{4u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{4u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{4u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{4u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{4u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{4u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{4u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{4u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{5u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{5u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{5u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{5u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{5u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{5u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{5u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{5u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{5u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{5u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{6u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{6u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{6u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{6u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{6u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{6u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{6u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{6u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{6u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{6u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{7u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{7u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{7u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{7u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{7u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{7u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{7u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{7u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{7u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{7u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{8u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{8u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{8u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{8u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{8u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{8u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{8u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{8u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{8u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{8u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{9u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{9u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{9u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{9u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{9u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{9u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{9u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{9u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{9u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{9u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{10u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{10u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{10u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{10u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{10u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{10u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{10u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{10u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{10u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{10u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{11u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{11u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{11u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{11u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{11u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{11u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{11u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{11u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{11u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{11u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{12u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{12u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{12u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{12u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{12u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{12u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{12u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{12u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{12u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{12u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{13u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{13u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{13u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{13u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{13u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{13u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{13u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{13u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{13u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{13u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{14u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{14u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{14u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{14u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{14u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{14u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{14u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{14u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{14u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{14u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{15u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{15u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{15u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{15u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{15u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{15u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{15u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{15u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{15u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{15u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{16u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{16u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{16u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{16u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{16u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{16u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{16u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{16u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{16u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{16u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{17u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{17u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{17u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{17u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{17u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{17u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{17u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{17u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{17u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{17u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{18u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{18u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{18u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{18u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{18u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{18u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{18u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{18u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{18u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{18u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{19u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{19u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{19u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{19u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{19u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{19u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{19u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{19u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{19u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{19u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{20u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{20u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{20u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{20u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{20u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{20u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{20u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{20u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{20u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{20u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{21u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{21u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{21u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{21u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{21u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{21u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{21u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{21u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{21u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{21u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{22u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{22u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{22u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{22u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{22u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{22u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{22u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{22u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{22u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{22u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{23u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{23u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{23u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{23u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{23u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{23u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{23u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{23u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{23u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{23u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{24u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{24u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{24u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{24u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{24u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{24u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{24u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{24u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{24u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{24u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{25u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{25u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{25u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{25u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{25u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{25u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{25u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{25u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{25u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{25u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{26u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{26u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{26u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{26u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{26u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{26u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{26u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{26u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{26u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{26u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{27u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{27u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{27u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{27u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{27u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{27u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{27u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{27u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{27u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{27u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{28u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{28u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{28u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{28u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{28u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{28u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{28u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{28u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{28u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{28u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{29u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{29u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{29u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{29u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{29u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{29u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{29u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{29u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{29u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{29u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{30u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{30u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{30u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{30u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{30u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{30u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{30u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{30u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{30u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{30u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}}; - - const std::map, std::pair> utf8Output{ - {{0u, 0u}, {u8"🤣0\n🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{0u, 1u}, {u8"🤣0\n🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{0u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{0u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{0u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{0u, 5u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{0u, 6u}, {u8"🤣0\n🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{0u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{0u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{0u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - - {{1u, 0u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{1u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{1u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{1u, 3u}, {u8"🤣0\n🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{1u, 4u}, {u8"🤣0\n🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{1u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{1u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{1u, 7u}, {u8"🤣0\n🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{1u, 8u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{1u, 9u}, {u8"🤣0\n🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - - {{2u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{2u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{2u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{2u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{2u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{2u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{2u, 6u}, {u8"🤣0\n🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{2u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{2u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{2u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - - {{3u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{3u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{3u, 2u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{3u, 3u}, {u8"🤣0\n🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{3u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{3u, 5u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{3u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{3u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{3u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{3u, 9u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - - {{4u, 0u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{4u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{4u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{4u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{4u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{4u, 5u}, {u8"🤣0\n🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{4u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{4u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{4u, 8u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{4u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - - {{5u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{5u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{5u, 2u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{5u, 3u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{5u, 4u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{5u, 5u}, {u8"🤣0\n🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{5u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{5u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{5u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{5u, 9u}, {u8"🤣0\n🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - - {{6u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{6u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{6u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{6u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{6u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{6u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{6u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{6u, 7u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{6u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{6u, 9u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - - {{7u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{7u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{7u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{7u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{7u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{7u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{7u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{7u, 7u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{7u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{7u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - - {{8u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{8u, 1u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{8u, 2u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{8u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{8u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{8u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{8u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{8u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{8u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{8u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - - {{9u, 0u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{9u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{9u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{9u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{9u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{9u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{9u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{9u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{9u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{9u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - - {{10u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{10u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{10u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{10u, 3u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{10u, 4u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{10u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{10u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{10u, 7u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{10u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{10u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - - {{11u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{11u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{11u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{11u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{11u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{11u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{11u, 6u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{11u, 7u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{11u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{11u, 9u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - - {{12u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{12u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{12u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{12u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{12u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{12u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{12u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{12u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{12u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{12u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - - {{13u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{13u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{13u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{13u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{13u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{13u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{13u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{13u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{13u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{13u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - - {{14u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{14u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{14u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{14u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{14u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{14u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{14u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{14u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{14u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{14u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - - {{15u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{15u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{15u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{15u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{15u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{15u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{15u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{15u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{15u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{15u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - - {{16u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{16u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{16u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{16u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{16u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{16u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{16u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{16u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{16u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{16u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - - {{17u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{17u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{17u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{17u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{17u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{17u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{17u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{17u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{17u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{17u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - - {{18u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{18u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{18u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{18u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{18u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{18u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{18u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{18u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{18u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{18u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - - {{19u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{19u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{19u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{19u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{19u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{19u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{19u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{19u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{19u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{19u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - - {{20u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{20u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{20u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{20u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{20u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{20u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{20u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{20u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{20u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{20u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - - {{21u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{21u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{21u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{21u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{21u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{21u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{21u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{21u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{21u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{21u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - - {{22u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{22u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{22u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{22u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{22u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{22u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{22u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{22u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{22u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{22u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - - {{23u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{23u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{23u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{23u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{23u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{23u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{23u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{23u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{23u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{23u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - - {{24u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{24u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{24u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{24u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{24u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{24u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{24u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{24u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{24u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{24u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - - {{25u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{25u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{25u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{25u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{25u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{25u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{25u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{25u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{25u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{25u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - - {{26u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{26u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{26u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{26u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{26u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{26u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{26u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{26u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{26u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{26u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - - {{27u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{27u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{27u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{27u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{27u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{27u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{27u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{27u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{27u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{27u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - - {{28u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{28u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{28u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{28u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{28u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{28u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{28u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{28u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{28u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{28u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - - {{29u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{29u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{29u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{29u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{29u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{29u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{29u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{29u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{29u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{29u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - - {{30u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{30u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{30u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{30u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{30u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{30u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{30u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{30u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{30u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{30u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}}; - - using namespace std::placeholders; - - RunSubtest( - asciiInputBuffer_, - sizeof(asciiInputBuffer_), - asciiOutput, - std::bind(&LineMutations::DuplicateLine, this, _1, _2, _3, _4, _5)); - - RunSubtest( - utf8InputBuffer_, - sizeof(utf8InputBuffer_), - utf8Output, - std::bind(&LineMutations::DuplicateLine, this, _1, _2, _3, _4, _5)); -} - -TEST_F(LineMutationTest, TestCopyLineCloseBy) -{ - // Test the CopyLineCloseBy() method in the LineMutations class. - // The method accepts a character buffer, size, and character index. - // If the original character buffer is UTF-8, the internal algorithm selects two random lines (source and destination), - // duplicates the source at destination, shifts the contents, and copies the contents to a null-terminated character buffer. - // If the original character buffer is ASCII, no lines are removed and the - // original contents are copied to a null-terminated character buffer. - - // The expected output data was gathered during a previous run using the default random seed. - // If the random seed is changed, the output data will also change and the unit tests will fail. - - const std::map, std::pair> asciiOutput{ - {{0u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{0u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{0u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{0u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{0u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{0u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{0u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{0u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{0u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{0u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{1u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{1u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{1u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{1u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{1u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{1u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{1u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{1u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{1u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{1u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{2u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{2u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{2u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{2u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{2u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{2u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{2u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{2u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{2u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{2u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{3u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{3u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{3u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{3u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{3u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{3u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{3u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{3u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{3u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{3u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{4u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{4u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{4u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{4u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{4u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{4u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{4u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{4u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{4u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{4u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{5u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{5u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{5u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{5u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{5u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{5u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{5u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{5u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{5u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{5u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{6u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{6u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{6u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{6u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{6u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{6u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{6u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{6u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{6u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{6u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{7u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{7u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{7u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{7u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{7u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{7u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{7u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{7u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{7u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{7u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{8u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{8u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{8u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{8u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{8u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{8u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{8u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{8u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{8u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{8u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{9u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{9u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{9u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{9u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{9u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{9u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{9u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{9u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{9u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{9u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{10u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{10u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{10u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{10u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{10u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{10u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{10u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{10u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{10u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{10u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{11u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{11u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{11u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{11u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{11u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{11u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{11u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{11u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{11u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{11u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{12u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{12u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{12u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{12u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{12u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{12u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{12u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{12u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{12u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{12u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{13u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{13u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{13u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{13u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{13u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{13u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{13u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{13u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{13u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{13u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{14u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{14u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{14u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{14u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{14u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{14u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{14u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{14u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{14u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{14u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{15u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{15u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{15u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{15u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{15u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{15u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{15u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{15u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{15u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{15u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{16u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{16u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{16u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{16u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{16u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{16u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{16u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{16u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{16u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{16u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{17u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{17u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{17u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{17u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{17u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{17u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{17u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{17u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{17u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{17u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{18u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{18u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{18u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{18u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{18u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{18u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{18u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{18u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{18u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{18u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{19u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{19u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{19u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{19u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{19u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{19u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{19u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{19u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{19u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{19u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{20u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{20u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{20u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{20u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{20u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{20u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{20u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{20u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{20u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{20u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{21u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{21u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{21u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{21u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{21u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{21u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{21u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{21u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{21u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{21u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{22u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{22u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{22u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{22u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{22u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{22u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{22u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{22u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{22u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{22u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{23u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{23u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{23u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{23u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{23u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{23u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{23u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{23u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{23u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{23u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{24u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{24u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{24u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{24u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{24u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{24u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{24u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{24u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{24u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{24u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{25u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{25u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{25u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{25u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{25u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{25u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{25u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{25u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{25u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{25u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{26u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{26u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{26u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{26u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{26u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{26u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{26u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{26u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{26u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{26u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{27u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{27u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{27u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{27u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{27u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{27u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{27u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{27u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{27u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{27u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{28u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{28u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{28u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{28u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{28u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{28u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{28u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{28u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{28u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{28u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{29u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{29u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{29u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{29u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{29u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{29u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{29u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{29u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{29u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{29u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{30u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{30u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{30u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{30u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{30u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{30u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{30u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{30u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{30u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{30u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}}; - - const std::map, std::pair> utf8Output{ - {{0u, 0u}, {u8"🤣0\n🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{0u, 1u}, {u8"🤣0\n🤣1\n🤣3\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{0u, 2u}, {u8"🤣0\n🤣2\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{0u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣0\n🤣3\n🤣4\0\0", 38}}, - {{0u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{0u, 5u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{0u, 6u}, {u8"🤣4\0\0🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 39}}, - {{0u, 7u}, {u8"🤣0\n🤣1\n🤣0\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{0u, 8u}, {u8"🤣3\n🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{0u, 9u}, {u8"🤣1\n🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - - {{1u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{1u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣2\n🤣4\0\0", 38}}, - {{1u, 2u}, {u8"🤣0\n🤣1\n🤣4\0\0🤣2\n🤣3\n🤣4\0\0", 39}}, - {{1u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣0\n🤣3\n🤣4\0\0", 38}}, - {{1u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{1u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣4\0\0🤣3\n🤣4\0\0", 39}}, - {{1u, 6u}, {u8"🤣1\n🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{1u, 7u}, {u8"🤣0\n🤣3\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{1u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{1u, 9u}, {u8"🤣0\n🤣4\0\0🤣1\n🤣2\n🤣3\n🤣4\0\0", 39}}, - - {{2u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣1\n🤣4\0\0", 38}}, - {{2u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{2u, 2u}, {u8"🤣3\n🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{2u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{2u, 4u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{2u, 5u}, {u8"🤣0\n🤣1\n🤣3\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{2u, 6u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{2u, 7u}, {u8"🤣1\n🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{2u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣2\n🤣4\0\0", 38}}, - {{2u, 9u}, {u8"🤣4\0\0🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 39}}, - - {{3u, 0u}, {u8"🤣0\n🤣1\n🤣4\0\0🤣2\n🤣3\n🤣4\0\0", 39}}, - {{3u, 1u}, {u8"🤣0\n🤣2\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{3u, 2u}, {u8"🤣0\n🤣1\n🤣4\0\0🤣2\n🤣3\n🤣4\0\0", 39}}, - {{3u, 3u}, {u8"🤣1\n🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{3u, 4u}, {u8"🤣4\0\0🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 39}}, - {{3u, 5u}, {u8"🤣0\n🤣2\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{3u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣1\n🤣4\0\0", 38}}, - {{3u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{3u, 8u}, {u8"🤣4\0\0🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 39}}, - {{3u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - - {{4u, 0u}, {u8"🤣4\0\0🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 39}}, - {{4u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣0\n🤣3\n🤣4\0\0", 38}}, - {{4u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣4\0\0🤣3\n🤣4\0\0", 39}}, - {{4u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{4u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{4u, 5u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{4u, 6u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{4u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣2\n🤣4\0\0", 38}}, - {{4u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣2\n🤣4\0\0", 38}}, - {{4u, 9u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - - {{5u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{5u, 1u}, {u8"🤣1\n🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{5u, 2u}, {u8"🤣0\n🤣1\n🤣0\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{5u, 3u}, {u8"🤣4\0\0🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 39}}, - {{5u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{5u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣4\0\0🤣3\n🤣4\0\0", 39}}, - {{5u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣2\n🤣4\0\0", 38}}, - {{5u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{5u, 8u}, {u8"🤣0\n🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{5u, 9u}, {u8"🤣3\n🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - - {{6u, 0u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{6u, 1u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{6u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣1\n🤣3\n🤣4\0\0", 38}}, - {{6u, 3u}, {u8"🤣0\n🤣4\0\0🤣1\n🤣2\n🤣3\n🤣4\0\0", 39}}, - {{6u, 4u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{6u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣4\0\0🤣3\n🤣4\0\0", 39}}, - {{6u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣1\n🤣3\n🤣4\0\0", 38}}, - {{6u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{6u, 8u}, {u8"🤣0\n🤣2\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{6u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - - {{7u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{7u, 1u}, {u8"🤣0\n🤣3\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{7u, 2u}, {u8"🤣0\n🤣1\n🤣4\0\0🤣2\n🤣3\n🤣4\0\0", 39}}, - {{7u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣1\n🤣3\n🤣4\0\0", 38}}, - {{7u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{7u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣2\n🤣4\0\0", 38}}, - {{7u, 6u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{7u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{7u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣1\n🤣3\n🤣4\0\0", 38}}, - {{7u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - - {{8u, 0u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{8u, 1u}, {u8"🤣0\n🤣2\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{8u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣1\n🤣4\0\0", 38}}, - {{8u, 3u}, {u8"🤣0\n🤣2\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{8u, 4u}, {u8"🤣0\n🤣1\n🤣4\0\0🤣2\n🤣3\n🤣4\0\0", 39}}, - {{8u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣1\n🤣4\0\0", 38}}, - {{8u, 6u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{8u, 7u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{8u, 8u}, {u8"🤣0\n🤣2\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{8u, 9u}, {u8"🤣0\n🤣1\n🤣4\0\0🤣2\n🤣3\n🤣4\0\0", 39}}, - - {{9u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{9u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{9u, 2u}, {u8"🤣0\n🤣3\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{9u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{9u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣2\n🤣4\0\0", 38}}, - {{9u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{9u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{9u, 7u}, {u8"🤣0\n🤣1\n🤣4\0\0🤣2\n🤣3\n🤣4\0\0", 39}}, - {{9u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣4\0\0🤣3\n🤣4\0\0", 39}}, - {{9u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣2\n🤣4\0\0", 38}}, - - {{10u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{10u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{10u, 2u}, {u8"🤣0\n🤣1\n🤣4\0\0🤣2\n🤣3\n🤣4\0\0", 39}}, - {{10u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{10u, 4u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{10u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{10u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{10u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣4\0\0🤣3\n🤣4\0\0", 39}}, - {{10u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣4\0\0🤣3\n🤣4\0\0", 39}}, - {{10u, 9u}, {u8"🤣0\n🤣3\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - - {{11u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣4\0\0🤣3\n🤣4\0\0", 39}}, - {{11u, 1u}, {u8"🤣0\n🤣2\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{11u, 2u}, {u8"🤣0\n🤣1\n🤣3\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{11u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{11u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣1\n🤣4\0\0", 38}}, - {{11u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{11u, 6u}, {u8"🤣0\n🤣3\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{11u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣2\n🤣4\0\0", 38}}, - {{11u, 8u}, {u8"🤣0\n🤣1\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{11u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - - {{12u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣4\0\0🤣3\n🤣4\0\0", 39}}, - {{12u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{12u, 2u}, {u8"🤣0\n🤣1\n🤣3\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{12u, 3u}, {u8"🤣0\n🤣1\n🤣4\0\0🤣2\n🤣3\n🤣4\0\0", 39}}, - {{12u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{12u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{12u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{12u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{12u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{12u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣2\n🤣4\0\0", 38}}, - - {{13u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{13u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{13u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣4\0\0🤣3\n🤣4\0\0", 39}}, - {{13u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{13u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{13u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{13u, 6u}, {u8"🤣0\n🤣1\n🤣3\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{13u, 7u}, {u8"🤣0\n🤣1\n🤣4\0\0🤣2\n🤣3\n🤣4\0\0", 39}}, - {{13u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{13u, 9u}, {u8"🤣0\n🤣1\n🤣3\n🤣2\n🤣3\n🤣4\0\0", 38}}, - - {{14u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{14u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣2\n🤣4\0\0", 38}}, - {{14u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣2\n🤣4\0\0", 38}}, - {{14u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{14u, 4u}, {u8"🤣0\n🤣1\n🤣3\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{14u, 5u}, {u8"🤣0\n🤣1\n🤣4\0\0🤣2\n🤣3\n🤣4\0\0", 39}}, - {{14u, 6u}, {u8"🤣0\n🤣1\n🤣4\0\0🤣2\n🤣3\n🤣4\0\0", 39}}, - {{14u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{14u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{14u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - - {{15u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{15u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣4\0\0🤣3\n🤣4\0\0", 39}}, - {{15u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{15u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{15u, 4u}, {u8"🤣0\n🤣1\n🤣4\0\0🤣2\n🤣3\n🤣4\0\0", 39}}, - {{15u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣4\0\0🤣3\n🤣4\0\0", 39}}, - {{15u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{15u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣2\n🤣4\0\0", 38}}, - {{15u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{15u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - - {{16u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣4\0\0🤣3\n🤣4\0\0", 39}}, - {{16u, 1u}, {u8"🤣0\n🤣1\n🤣4\0\0🤣2\n🤣3\n🤣4\0\0", 39}}, - {{16u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{16u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{16u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{16u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{16u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{16u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{16u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{16u, 9u}, {u8"🤣0\n🤣1\n🤣3\n🤣2\n🤣3\n🤣4\0\0", 38}}, - - {{17u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{17u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{17u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{17u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{17u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣2\n🤣3\n🤣4\0\0", 38}}, - {{17u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{17u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{17u, 7u}, {u8"🤣0\n🤣1\n🤣4\0\0🤣2\n🤣3\n🤣4\0\0", 39}}, - {{17u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣4\0\0🤣3\n🤣4\0\0", 39}}, - {{17u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - - {{18u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣4\0\0🤣3\n🤣4\0\0", 39}}, - {{18u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{18u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{18u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{18u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{18u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣4\0\0🤣3\n🤣4\0\0", 39}}, - {{18u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣4\0\0🤣3\n🤣4\0\0", 39}}, - {{18u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{18u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣4\0\0🤣3\n🤣4\0\0", 39}}, - {{18u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - - {{19u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{19u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{19u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{19u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{19u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{19u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{19u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{19u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{19u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{19u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - - {{20u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{20u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{20u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣4\0\0🤣3\n🤣4\0\0", 39}}, - {{20u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣4\0\0🤣3\n🤣4\0\0", 39}}, - {{20u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣4\0\0🤣3\n🤣4\0\0", 39}}, - {{20u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{20u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{20u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{20u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{20u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣4\0\0🤣3\n🤣4\0\0", 39}}, - - {{21u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{21u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{21u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{21u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{21u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{21u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣4\0\0🤣3\n🤣4\0\0", 39}}, - {{21u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{21u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣4\0\0🤣3\n🤣4\0\0", 39}}, - {{21u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣4\0\0🤣3\n🤣4\0\0", 39}}, - {{21u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - - {{22u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{22u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{22u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{22u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣4\0\0🤣3\n🤣4\0\0", 39}}, - {{22u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{22u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣4\0\0🤣3\n🤣4\0\0", 39}}, - {{22u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{22u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{22u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣4\0\0🤣3\n🤣4\0\0", 39}}, - {{22u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - - {{23u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{23u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{23u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣4\0\0🤣3\n🤣4\0\0", 39}}, - {{23u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{23u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{23u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{23u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{23u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣4\0\0🤣3\n🤣4\0\0", 39}}, - {{23u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - {{23u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣3\n🤣4\0\0", 38}}, - - {{24u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{24u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{24u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{24u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{24u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{24u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{24u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{24u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{24u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{24u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - - {{25u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{25u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{25u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{25u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{25u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{25u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{25u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{25u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{25u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{25u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - - {{26u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{26u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{26u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{26u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{26u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{26u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{26u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{26u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{26u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{26u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - - {{27u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{27u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{27u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{27u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{27u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{27u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{27u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{27u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{27u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{27u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - - {{28u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{28u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{28u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{28u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{28u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{28u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{28u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{28u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{28u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{28u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - - {{29u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{29u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{29u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{29u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{29u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{29u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{29u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{29u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{29u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{29u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - - {{30u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{30u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{30u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{30u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{30u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{30u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{30u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{30u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{30u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}, - {{30u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0🤣4\0\0", 39}}}; - - using namespace std::placeholders; - - RunSubtest( - asciiInputBuffer_, - sizeof(asciiInputBuffer_), - asciiOutput, - std::bind(&LineMutations::CopyLineCloseBy, this, _1, _2, _3, _4, _5)); - - RunSubtest( - utf8InputBuffer_, - sizeof(utf8InputBuffer_), - utf8Output, - std::bind(&LineMutations::CopyLineCloseBy, this, _1, _2, _3, _4, _5)); -} - -TEST_F(LineMutationTest, TestRepeatLine) -{ - // Test the RepeatLine() method in the LineMutations class. - // The method accepts a character buffer, size, and character index. - // If the original character buffer is UTF-8, the internal algorithm selects a selects a random line, - // duplicates it a random number of times, and copies the contents to a null-terminated character buffer. - // If the original character buffer is ASCII, no lines are removed and the - // original contents are copied to a null-terminated character buffer. - - // The expected output data was gathered during a previous run using the default random seed. - // If the random seed is changed, the output data will also change and the unit tests will fail. - - // NOTE: - // The RepeatLine() method is capable of duplicating the random line a variable number of times. - // The range is defined as [1, 2097153]. - // Since the number of line repetitions is random and can vary greatly, it is not feasible to write a subtest which - // exercises the cases where the original character buffer is UTF-8. - // Any modifications that are made to the RepeatLine() method should therefore be tested manually - // in order to verify correct behavior. - // As of 06/29/23, the RepeatLine() method was verified to work for UTF-8 character buffers. - - const std::map, std::pair> asciiOutput{ - {{0u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{0u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{0u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{0u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{0u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{0u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{0u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{0u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{0u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{0u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{1u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{1u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{1u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{1u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{1u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{1u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{1u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{1u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{1u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{1u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{2u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{2u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{2u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{2u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{2u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{2u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{2u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{2u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{2u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{2u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{3u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{3u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{3u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{3u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{3u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{3u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{3u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{3u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{3u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{3u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{4u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{4u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{4u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{4u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{4u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{4u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{4u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{4u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{4u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{4u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{5u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{5u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{5u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{5u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{5u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{5u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{5u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{5u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{5u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{5u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{6u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{6u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{6u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{6u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{6u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{6u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{6u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{6u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{6u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{6u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{7u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{7u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{7u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{7u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{7u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{7u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{7u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{7u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{7u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{7u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{8u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{8u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{8u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{8u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{8u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{8u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{8u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{8u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{8u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{8u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{9u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{9u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{9u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{9u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{9u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{9u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{9u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{9u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{9u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{9u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{10u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{10u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{10u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{10u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{10u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{10u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{10u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{10u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{10u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{10u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{11u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{11u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{11u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{11u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{11u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{11u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{11u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{11u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{11u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{11u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{12u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{12u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{12u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{12u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{12u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{12u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{12u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{12u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{12u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{12u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{13u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{13u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{13u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{13u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{13u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{13u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{13u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{13u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{13u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{13u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{14u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{14u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{14u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{14u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{14u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{14u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{14u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{14u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{14u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{14u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{15u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{15u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{15u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{15u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{15u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{15u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{15u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{15u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{15u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{15u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{16u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{16u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{16u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{16u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{16u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{16u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{16u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{16u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{16u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{16u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{17u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{17u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{17u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{17u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{17u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{17u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{17u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{17u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{17u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{17u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{18u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{18u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{18u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{18u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{18u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{18u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{18u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{18u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{18u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{18u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{19u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{19u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{19u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{19u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{19u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{19u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{19u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{19u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{19u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{19u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{20u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{20u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{20u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{20u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{20u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{20u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{20u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{20u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{20u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{20u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{21u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{21u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{21u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{21u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{21u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{21u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{21u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{21u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{21u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{21u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{22u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{22u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{22u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{22u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{22u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{22u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{22u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{22u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{22u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{22u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{23u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{23u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{23u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{23u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{23u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{23u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{23u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{23u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{23u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{23u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{24u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{24u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{24u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{24u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{24u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{24u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{24u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{24u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{24u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{24u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{25u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{25u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{25u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{25u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{25u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{25u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{25u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{25u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{25u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{25u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{26u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{26u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{26u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{26u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{26u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{26u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{26u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{26u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{26u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{26u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{27u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{27u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{27u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{27u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{27u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{27u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{27u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{27u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{27u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{27u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{28u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{28u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{28u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{28u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{28u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{28u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{28u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{28u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{28u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{28u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{29u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{29u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{29u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{29u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{29u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{29u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{29u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{29u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{29u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{29u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - - {{30u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{30u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{30u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{30u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{30u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{30u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{30u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{30u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{30u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}, - {{30u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0", 32}}}; - - using namespace std::placeholders; - - RunSubtest( - asciiInputBuffer_, - sizeof(asciiInputBuffer_), - asciiOutput, - std::bind(&LineMutations::RepeatLine, this, _1, _2, _3, _4, _5)); -} - -TEST_F(LineMutationTest, TestSwapLine) -{ - // Test the TestSwapLine() method in the LineMutations class. - // The method accepts a character buffer, size, and character index. - // If the original character buffer is ASCII, the internal algorithm selects a selects sequential random lines, - // swaps them, and copies the contents to a null-terminated character buffer. - // If the original character buffer is UTF-8, no lines are swapped and the - // original contents are copied to a null-terminated character buffer. - - // The expected output data was gathered during a previous run using the default random seed. - // If the random seed is changed, the output data will also change and the unit tests will fail. - - const std::map, std::pair> asciiOutput{ - {{0u, 0u}, {"Line1\nLine0\nLine2\nLine3\nLine4\0\0", 32}}, - {{0u, 1u}, {"Line1\nLine0\nLine2\nLine3\nLine4\0\0", 32}}, - {{0u, 2u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{0u, 3u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{0u, 4u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{0u, 5u}, {"Line0\nLine2\nLine1\nLine3\nLine4\0\0", 32}}, - {{0u, 6u}, {"Line1\nLine0\nLine2\nLine3\nLine4\0\0", 32}}, - {{0u, 7u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{0u, 8u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{0u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - - {{1u, 0u}, {"Line0\nLine2\nLine1\nLine3\nLine4\0\0", 32}}, - {{1u, 1u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{1u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{1u, 3u}, {"Line1\nLine0\nLine2\nLine3\nLine4\0\0", 32}}, - {{1u, 4u}, {"Line1\nLine0\nLine2\nLine3\nLine4\0\0", 32}}, - {{1u, 5u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{1u, 6u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{1u, 7u}, {"Line1\nLine0\nLine2\nLine3\nLine4\0\0", 32}}, - {{1u, 8u}, {"Line0\nLine2\nLine1\nLine3\nLine4\0\0", 32}}, - {{1u, 9u}, {"Line1\nLine0\nLine2\nLine3\nLine4\0\0", 32}}, - - {{2u, 0u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{2u, 1u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{2u, 2u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{2u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{2u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{2u, 5u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{2u, 6u}, {"Line1\nLine0\nLine2\nLine3\nLine4\0\0", 32}}, - {{2u, 7u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{2u, 8u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{2u, 9u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - - {{3u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{3u, 1u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{3u, 2u}, {"Line0\nLine2\nLine1\nLine3\nLine4\0\0", 32}}, - {{3u, 3u}, {"Line1\nLine0\nLine2\nLine3\nLine4\0\0", 32}}, - {{3u, 4u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{3u, 5u}, {"Line0\nLine2\nLine1\nLine3\nLine4\0\0", 32}}, - {{3u, 6u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{3u, 7u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{3u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{3u, 9u}, {"Line0\nLine2\nLine1\nLine3\nLine4\0\0", 32}}, - - {{4u, 0u}, {"Line0\nLine2\nLine1\nLine3\nLine4\0\0", 32}}, - {{4u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{4u, 2u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{4u, 3u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{4u, 4u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{4u, 5u}, {"Line1\nLine0\nLine2\nLine3\nLine4\0\0", 32}}, - {{4u, 6u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{4u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{4u, 8u}, {"Line0\nLine2\nLine1\nLine3\nLine4\0\0", 32}}, - {{4u, 9u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - - {{5u, 0u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{5u, 1u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{5u, 2u}, {"Line0\nLine2\nLine1\nLine3\nLine4\0\0", 32}}, - {{5u, 3u}, {"Line0\nLine2\nLine1\nLine3\nLine4\0\0", 32}}, - {{5u, 4u}, {"Line0\nLine2\nLine1\nLine3\nLine4\0\0", 32}}, - {{5u, 5u}, {"Line1\nLine0\nLine2\nLine3\nLine4\0\0", 32}}, - {{5u, 6u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{5u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{5u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{5u, 9u}, {"Line1\nLine0\nLine2\nLine3\nLine4\0\0", 32}}, - - {{6u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{6u, 1u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{6u, 2u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{6u, 3u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{6u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{6u, 5u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{6u, 6u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{6u, 7u}, {"Line0\nLine2\nLine1\nLine3\nLine4\0\0", 32}}, - {{6u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{6u, 9u}, {"Line0\nLine2\nLine1\nLine3\nLine4\0\0", 32}}, - - {{7u, 0u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{7u, 1u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{7u, 2u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{7u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{7u, 4u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{7u, 5u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{7u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{7u, 7u}, {"Line0\nLine2\nLine1\nLine3\nLine4\0\0", 32}}, - {{7u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{7u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - - {{8u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{8u, 1u}, {"Line0\nLine2\nLine1\nLine3\nLine4\0\0", 32}}, - {{8u, 2u}, {"Line0\nLine2\nLine1\nLine3\nLine4\0\0", 32}}, - {{8u, 3u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{8u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{8u, 5u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{8u, 6u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{8u, 7u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{8u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{8u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - - {{9u, 0u}, {"Line0\nLine2\nLine1\nLine3\nLine4\0\0", 32}}, - {{9u, 1u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{9u, 2u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{9u, 3u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{9u, 4u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{9u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{9u, 6u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{9u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{9u, 8u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{9u, 9u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - - {{10u, 0u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{10u, 1u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{10u, 2u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{10u, 3u}, {"Line0\nLine2\nLine1\nLine3\nLine4\0\0", 32}}, - {{10u, 4u}, {"Line0\nLine2\nLine1\nLine3\nLine4\0\0", 32}}, - {{10u, 5u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{10u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{10u, 7u}, {"Line0\nLine2\nLine1\nLine3\nLine4\0\0", 32}}, - {{10u, 8u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{10u, 9u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - - {{11u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{11u, 1u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{11u, 2u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{11u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{11u, 4u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{11u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{11u, 6u}, {"Line0\nLine2\nLine1\nLine3\nLine4\0\0", 32}}, - {{11u, 7u}, {"Line0\nLine2\nLine1\nLine3\nLine4\0\0", 32}}, - {{11u, 8u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{11u, 9u}, {"Line0\nLine2\nLine1\nLine3\nLine4\0\0", 32}}, - - {{12u, 0u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{12u, 1u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{12u, 2u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{12u, 3u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{12u, 4u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{12u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{12u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{12u, 7u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{12u, 8u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{12u, 9u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - - {{13u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{13u, 1u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{13u, 2u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{13u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{13u, 4u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{13u, 5u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{13u, 6u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{13u, 7u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{13u, 8u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{13u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - - {{14u, 0u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{14u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{14u, 2u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{14u, 3u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{14u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{14u, 5u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{14u, 6u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{14u, 7u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{14u, 8u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{14u, 9u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - - {{15u, 0u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{15u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{15u, 2u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{15u, 3u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{15u, 4u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{15u, 5u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{15u, 6u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{15u, 7u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{15u, 8u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{15u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - - {{16u, 0u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{16u, 1u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{16u, 2u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{16u, 3u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{16u, 4u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{16u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{16u, 6u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{16u, 7u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{16u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{16u, 9u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - - {{17u, 0u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{17u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{17u, 2u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{17u, 3u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{17u, 4u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{17u, 5u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{17u, 6u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{17u, 7u}, {"Line0\nLine1\nLine3\nLine2\nLine4\0\0", 32}}, - {{17u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{17u, 9u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - - {{18u, 0u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{18u, 1u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{18u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{18u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{18u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{18u, 5u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{18u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{18u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{18u, 8u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{18u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - - {{19u, 0u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{19u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{19u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{19u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{19u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{19u, 5u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{19u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{19u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{19u, 8u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{19u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - - {{20u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{20u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{20u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{20u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{20u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{20u, 5u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{20u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{20u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{20u, 8u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{20u, 9u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - - {{21u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{21u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{21u, 2u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{21u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{21u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{21u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{21u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{21u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{21u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{21u, 9u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - - {{22u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{22u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{22u, 2u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{22u, 3u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{22u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{22u, 5u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{22u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{22u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{22u, 8u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{22u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - - {{23u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{23u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{23u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{23u, 3u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{23u, 4u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{23u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{23u, 6u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{23u, 7u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{23u, 8u}, {"Line0\nLine1\nLine2\nLine4\0\0Line3\n", 32}}, - {{23u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - - {{24u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{24u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{24u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{24u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{24u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{24u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{24u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{24u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{24u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{24u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - - {{25u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{25u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{25u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{25u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{25u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{25u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{25u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{25u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{25u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{25u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - - {{26u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{26u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{26u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{26u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{26u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{26u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{26u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{26u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{26u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{26u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - - {{27u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{27u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{27u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{27u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{27u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{27u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{27u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{27u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{27u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{27u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - - {{28u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{28u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{28u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{28u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{28u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{28u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{28u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{28u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{28u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{28u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - - {{29u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{29u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{29u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{29u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{29u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{29u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{29u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{29u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{29u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{29u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - - {{30u, 0u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{30u, 1u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{30u, 2u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{30u, 3u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{30u, 4u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{30u, 5u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{30u, 6u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{30u, 7u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{30u, 8u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}, - {{30u, 9u}, {"Line0\nLine1\nLine2\nLine3\nLine4\0\0", 32}}}; - - const std::map, std::pair> utf8Output{ - {{0u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{0u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{0u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{0u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{0u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{0u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{0u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{0u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{0u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{0u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{1u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{1u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{1u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{1u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{1u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{1u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{1u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{1u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{1u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{1u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{2u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{2u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{2u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{2u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{2u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{2u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{2u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{2u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{2u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{2u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{3u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{3u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{3u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{3u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{3u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{3u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{3u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{3u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{3u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{3u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{4u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{4u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{4u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{4u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{4u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{4u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{4u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{4u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{4u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{4u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{5u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{5u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{5u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{5u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{5u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{5u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{5u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{5u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{5u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{5u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{6u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{6u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{6u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{6u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{6u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{6u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{6u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{6u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{6u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{6u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{7u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{7u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{7u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{7u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{7u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{7u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{7u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{7u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{7u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{7u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{8u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{8u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{8u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{8u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{8u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{8u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{8u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{8u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{8u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{8u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{9u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{9u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{9u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{9u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{9u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{9u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{9u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{9u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{9u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{9u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{10u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{10u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{10u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{10u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{10u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{10u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{10u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{10u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{10u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{10u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{11u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{11u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{11u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{11u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{11u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{11u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{11u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{11u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{11u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{11u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{12u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{12u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{12u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{12u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{12u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{12u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{12u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{12u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{12u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{12u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{13u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{13u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{13u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{13u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{13u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{13u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{13u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{13u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{13u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{13u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{14u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{14u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{14u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{14u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{14u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{14u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{14u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{14u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{14u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{14u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{15u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{15u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{15u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{15u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{15u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{15u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{15u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{15u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{15u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{15u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{16u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{16u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{16u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{16u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{16u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{16u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{16u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{16u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{16u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{16u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{17u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{17u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{17u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{17u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{17u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{17u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{17u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{17u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{17u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{17u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{18u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{18u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{18u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{18u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{18u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{18u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{18u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{18u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{18u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{18u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{19u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{19u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{19u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{19u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{19u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{19u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{19u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{19u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{19u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{19u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{20u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{20u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{20u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{20u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{20u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{20u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{20u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{20u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{20u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{20u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{21u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{21u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{21u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{21u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{21u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{21u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{21u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{21u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{21u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{21u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{22u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{22u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{22u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{22u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{22u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{22u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{22u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{22u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{22u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{22u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{23u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{23u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{23u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{23u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{23u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{23u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{23u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{23u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{23u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{23u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{24u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{24u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{24u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{24u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{24u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{24u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{24u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{24u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{24u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{24u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{25u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{25u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{25u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{25u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{25u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{25u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{25u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{25u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{25u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{25u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{26u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{26u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{26u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{26u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{26u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{26u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{26u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{26u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{26u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{26u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{27u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{27u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{27u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{27u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{27u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{27u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{27u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{27u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{27u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{27u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{28u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{28u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{28u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{28u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{28u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{28u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{28u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{28u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{28u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{28u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{29u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{29u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{29u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{29u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{29u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{29u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{29u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{29u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{29u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{29u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - - {{30u, 0u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{30u, 1u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{30u, 2u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{30u, 3u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{30u, 4u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{30u, 5u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{30u, 6u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{30u, 7u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{30u, 8u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}, - {{30u, 9u}, {u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0\0", 32}}}; - - using namespace std::placeholders; - - RunSubtest( - asciiInputBuffer_, - sizeof(asciiInputBuffer_), - asciiOutput, - std::bind(&LineMutations::SwapLine, this, _1, _2, _3, _4, _5)); - - RunSubtest( - utf8InputBuffer_, - sizeof(utf8InputBuffer_), - utf8Output, - std::bind(&LineMutations::SwapLine, this, _1, _2, _3, _4, _5)); -} - -TEST_F(LineMutationTest, TestLineStructure) -{ - Line lhs; - - // Test default constructor - - EXPECT_FALSE(lhs.IsValid); - EXPECT_EQ(lhs.StartIndex, 0u); - EXPECT_EQ(lhs.Size, 0u); - - // Test inequality operator - - Line rhs; - - rhs.IsValid = true; - rhs.StartIndex = 1u; - rhs.Size = 2u; - - EXPECT_NE(lhs, rhs); - - // Test equality operator - - rhs.IsValid = false; - rhs.StartIndex = 0u; - rhs.Size = 0u; - - EXPECT_EQ(lhs, rhs); -} - -TEST_F(LineMutationTest, TestLineVectorStructure) -{ - auto fillLineVector{ - [&](LineVector& lineVector) - { - lineVector.Data = std::make_unique(10u); - lineVector.Size = 10u; - - for (size_t it{0u}; it < lineVector.Size; ++it) - lineVector.Data[it] = it; - }}; - - { - // Test default constructor - - LineVector lineVector; - - EXPECT_EQ(lineVector.Data.get(), nullptr); - EXPECT_EQ(lineVector.Size, 0u); - } - - { - // Test parameterized constructor - - constexpr size_t validCharacterIndex{0u}; - - const size_t numberOfLinesAfterIndex{ - GetNumberOfLinesAfterIndex( - asciiInputBuffer_, - sizeof(asciiInputBuffer_), - validCharacterIndex)}; - - constexpr size_t validLineIndex{0u}; - - const Line lineData{ - GetLineData( - asciiInputBuffer_, - sizeof(asciiInputBuffer_), - validLineIndex, - numberOfLinesAfterIndex)}; - - const auto lineVector{ - LineVector{ - asciiInputBuffer_, - lineData}}; - - EXPECT_EQ(lineVector.Size, lineData.Size); - EXPECT_EQ(memcmp(lineVector.Data.get(), asciiInputBuffer_, lineData.Size), 0); - } - - { - // Test inequality operator - - LineVector rhs; - - fillLineVector(rhs); - - EXPECT_NE(LineVector{}, rhs); - } - - { - // Test equality operator - - LineVector lhs; - - EXPECT_EQ(lhs, LineVector{}); - } - - { - // Test copy constructor - - LineVector original; - - fillLineVector(original); - - EXPECT_EQ(original, LineVector{original}); - } - - { - // Test move constructor - - LineVector original; - - fillLineVector(original); - - auto copy{LineVector{original}}; - - LineVector moved{std::move(original)}; - - EXPECT_NE(original, moved); - EXPECT_EQ(original.Data.get(), nullptr); - EXPECT_EQ(original.Size, 0u); - EXPECT_EQ(copy, moved); - } - - { - // Test copy assignment operator - - LineVector original; - - fillLineVector(original); - - LineVector copied = original; - - EXPECT_EQ(original, copied); - } - - { - // Test move assignment operator - - LineVector original; - - fillLineVector(original); - - auto copy{LineVector{original}}; - - LineVector moved = std::move(original); - - EXPECT_NE(original, moved); - EXPECT_EQ(original.Data.get(), nullptr); - EXPECT_EQ(original.Size, 0u); - EXPECT_EQ(copy, moved); - } -} - -TEST_F(LineMutationTest, TestLineListStructure) -{ - auto fillLineList{ - [&](LineList& lineList) - { - LineVector lineVector; - - lineVector.Data = std::make_unique(10u); - lineVector.Size = 10u; - - for (size_t it{0u}; it < lineVector.Size; ++it) - lineVector.Data[it] = it; - - lineList.Data = std::make_unique(10u); - lineList.NumberOfElements = 10u; - - for (size_t it{0u}; it < lineList.NumberOfElements; ++it) - { - lineList.Data[it] = lineVector; - lineList.Capacity += lineVector.Size; - } - }}; - - { - // Test default constructor - - LineList lineList; - - EXPECT_EQ(lineList.Data.get(), nullptr); - EXPECT_EQ(lineList.NumberOfElements, 0u); - EXPECT_EQ(lineList.Capacity, 0u); - } - - { - // Test parameterized constructor - - auto compareLineVectors{ - [&](const LineVector* const lhs, const LineVector* const rhs) -> bool - { - if (lhs != nullptr && rhs != nullptr) - { - for (size_t it{0u}; it < lhs->Size; ++it) - if (lhs->Data[it] != rhs->Data[it]) - return false; - - return true; - } - else if (lhs == nullptr && rhs == nullptr) - { - return true; - } - else - { - return false; - } - }}; - - constexpr size_t validCharacterIndex{0u}; - - const size_t numberOfLinesAfterIndex{ - GetNumberOfLinesAfterIndex( - asciiInputBuffer_, - sizeof(asciiInputBuffer_), - validCharacterIndex)}; - - constexpr size_t validLineIndex{0u}; - - const std::vector lineData{ - GetLineData( - asciiInputBuffer_, - sizeof(asciiInputBuffer_), - validLineIndex, - numberOfLinesAfterIndex)}; - - const auto lineList{ - LineList{ - asciiInputBuffer_, - lineData}}; - - EXPECT_EQ(lineList.NumberOfElements, 1u); - - const bool retVal{ - compareLineVectors( - lineList.Data.get(), - std::make_unique( - asciiInputBuffer_, - lineData.front()).get())}; - - EXPECT_TRUE(retVal); - } - - { - // Test inequality operator - - LineList rhs; - - fillLineList(rhs); - - EXPECT_NE(LineList{}, rhs); - } - - { - // Test equality operator - - LineList lhs; - - EXPECT_EQ(lhs, LineList{}); - } - - { - // Test copy constructor - - LineList original; - - fillLineList(original); - - EXPECT_EQ(original, LineList{original}); - } - - { - // Test move constructor - - LineList original; - - fillLineList(original); - - auto copy{LineList{original}}; - - LineList moved{std::move(original)}; - - EXPECT_NE(original, moved); - EXPECT_EQ(original.Data.get(), nullptr); - EXPECT_EQ(original.Capacity, 0u); - EXPECT_EQ(original.NumberOfElements, 0u); - EXPECT_EQ(copy, moved); - } - - { - // Test copy assignment operator - - LineList original; - - fillLineList(original); - - LineList copied = original; - - EXPECT_EQ(original, copied); - } - - { - // Test move assignment operator - - LineList original; - - fillLineList(original); - - auto copy{LineList{original}}; - - LineList moved = std::move(original); - - EXPECT_NE(original, moved); - EXPECT_EQ(original.Data.get(), nullptr); - EXPECT_EQ(original.Capacity, 0u); - EXPECT_EQ(original.NumberOfElements, 0u); - EXPECT_EQ(copy, moved); - } -} -} \ No newline at end of file diff --git a/Radamsa/test/lineMutationTest.h b/Radamsa/test/lineMutationTest.h deleted file mode 100644 index 74bb4ee..0000000 --- a/Radamsa/test/lineMutationTest.h +++ /dev/null @@ -1,220 +0,0 @@ -/* ============================================================================= -* Vader Modular Fuzzer -* Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. -* -* -* Effort sponsored by the U.S. Government under Other Transaction number -* W9124P-19-9-0001 between AMTC and the Government. The U.S. Government -* is authorized to reproduce and distribute reprints for Governmental purposes -* notwithstanding any copyright notation thereon. -* -* The views and conclusions contained herein are those of the authors and -* should not be interpreted as necessarily representing the official policies -* or endorsements, either expressed or implied, of the U.S. Government. -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -* -* @license GPL-3.0-or-later -* ===========================================================================*/ - -#pragma once - -#ifndef GTEST_DECORATOR -#define GTEST_DECORATOR std::cout << "\033[32m[ ] \033[37m[ INFO ] " -#endif - -// C/C++ Includes -#include -#include -#include - -// Google Test Includes -#include "gtest/gtest.h" - -// VMF Includes -#include "SimpleStorage.hpp" -#include "lineMutations.hpp" - -namespace vader::test::modules::radamsa::mutations -{ -class LineMutationTest : public ::testing::Test, - public ::vader::radamsa::mutations::LineMutations -{ -public: - virtual ~LineMutationTest() = default; - - LineMutationTest() : ::vader::radamsa::mutations::LineMutations{randomNumberGenerator_} {} - -protected: - typedef size_t character_index, random_draw_index, expected_buffer_size; - - typedef std::function Line_Mutation_Callback; - - std::tuple, unsigned long> RunLineMutationCallback( - const char* inputBuffer, - const int size, - const int characterIndex, - const Line_Mutation_Callback& callback) const - { - // Subtest prologue - Get testcase key and storage entry - - std::unique_ptr storage{std::make_unique("storage")}; - std::unique_ptr registry{ - std::make_unique( - "TEST_INT", - vader::StorageRegistry::INT, - vader::StorageRegistry::ASCENDING)}; - std::unique_ptr metadata{std::make_unique()}; - - const int testCaseKey{ - registry->registerKey( - "TEST_CASE", - vader::StorageRegistry::BUFFER, - vader::StorageRegistry::READ_WRITE)}; - - storage->configure(registry.get(), metadata.get()); - - vader::StorageEntry* storageEntryPtr{storage->createNewEntry()}; - - storage->saveEntry(storageEntryPtr); - - // Execute the subtest against the desired callback. - - callback( - storageEntryPtr, - size, - inputBuffer, - characterIndex, - testCaseKey); - - return std::make_tuple(testCaseKey, std::move(storage), storageEntryPtr->getID()); - } - - void RunSubtest( - const char* const inputBuffer, - const size_t inputBufferSize, - const std::map, std::pair>& expectedOutput, - const Line_Mutation_Callback& lineMutationCallback) const - { - try - { - // Execute the callback 10 times per valid character index. - - for (const auto& characterIndex : characterIndices_) - { - constexpr size_t numberOfRandomDraws{10u}; - - for (size_t randomDrawIndex{0u}; randomDrawIndex < numberOfRandomDraws; ++randomDrawIndex) - { - std::tuple, unsigned long> testCaseStorageTuple{ - RunLineMutationCallback( - inputBuffer, - inputBufferSize, - characterIndex, - lineMutationCallback)}; - - const int testCaseKey{std::get<0u>(testCaseStorageTuple)}; - const unsigned long entryId{std::get<2u>(testCaseStorageTuple)}; - StorageEntry* storageEntryPtr{std::get<1u>(testCaseStorageTuple)->getEntryByID(entryId)}; - - const int outputBufferSize{storageEntryPtr->getBufferSize(testCaseKey)}; - const char* const outputBuffer{storageEntryPtr->getBufferPointer(testCaseKey)}; - - std::pair expectedBufferData{ - expectedOutput.at( - std::make_pair( - characterIndex, - randomDrawIndex))}; - - const char* const expectedBuffer{expectedBufferData.first}; - const size_t expectedBufferSize{expectedBufferData.second}; - - ASSERT_EQ(outputBufferSize, expectedBufferSize); - ASSERT_EQ(outputBuffer[outputBufferSize - 1u], 0u); - ASSERT_EQ(memcmp(outputBuffer, expectedBuffer, outputBufferSize), 0); - } - } - - { - // Execute callback with an invalid character index. - - EXPECT_THROW( - RunLineMutationCallback( - inputBuffer, - inputBufferSize, - inputBufferSize, // This character index is invalid - lineMutationCallback), - RuntimeException); - } - - { - // Execute callback with an invalid buffer size. - - constexpr int characterIndex{0u}; - - EXPECT_THROW( - RunLineMutationCallback( - inputBuffer, - 0u, // This size is invalid - characterIndex, - lineMutationCallback), - RuntimeException); - } - - { - // Execute callback with an invalid buffer. - - constexpr int characterIndex{0u}; - - EXPECT_THROW( - RunLineMutationCallback( - nullptr, // This pointer is invalid - inputBufferSize, - characterIndex, - lineMutationCallback), - RuntimeException); - } - } - catch(const RuntimeException& e) - { - GTEST_DECORATOR << "\n" << e.getReason(); - EXPECT_TRUE(false); - } - catch(const std::exception& e) - { - GTEST_DECORATOR << "\n" << e.what(); - EXPECT_TRUE(false); - } - catch(...) - { - GTEST_DECORATOR << "Unknown Error occurred" << std::endl; - EXPECT_TRUE(false); - } - } - - static constexpr char asciiInputBuffer_[]{"Line0\nLine1\nLine2\nLine3\nLine4\0"}; - static constexpr char utf8InputBuffer_[]{u8"🤣0\n🤣1\n🤣2\n🤣3\n🤣4\0"}; - - static constexpr std::array characterIndices_{ - 0u, 1u, 2u, 3u, 4u, 5u, - 6u, 7u, 8u, 9u, 10u, - 11u, 12u, 13u, 14u, 15u, - 16u, 17u, 18u, 19u, 20u, - 21u, 22u, 23u, 24u, 25u, - 26u, 27u, 28u, 29u, 30u}; - -private: - std::default_random_engine randomNumberGenerator_; -}; -} \ No newline at end of file diff --git a/Radamsa/test/mutationBaseTest.cpp b/Radamsa/test/mutationBaseTest.cpp deleted file mode 100644 index a46e892..0000000 --- a/Radamsa/test/mutationBaseTest.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* ============================================================================= -* Vader Modular Fuzzer -* Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. -* -* -* Effort sponsored by the U.S. Government under Other Transaction number -* W9124P-19-9-0001 between AMTC and the Government. The U.S. Government -* is authorized to reproduce and distribute reprints for Governmental purposes -* notwithstanding any copyright notation thereon. -* -* The views and conclusions contained herein are those of the authors and -* should not be interpreted as necessarily representing the official policies -* or endorsements, either expressed or implied, of the U.S. Government. -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -* -* @license GPL-3.0-or-later -* ===========================================================================*/ - -// VMF Includes -#include "mutationBaseTest.h" - -namespace vader::test::modules::radamsa::mutations -{ -TEST_F(MutationBaseTest, TestDefaultConstructor) -{ - ASSERT_EQ(RANDOM_NUMBER_GENERATOR_, std::default_random_engine{}); -} - -TEST_F(MutationBaseTest, TestGetRandomValueWithinBounds) -{ - constexpr size_t maximumSize{5u}; - constexpr std::array lowerValues{0u, 1u, 2u, 3u, 4u}; - - // The expected output data was gathered during a previous run using the default random seed. - // If the random seed is changed, the output data will also change and the unit tests will fail. - - const std::map, const std::array> expectedOutput{ - {{0u, 4u}, {0u, 0u, 3u, 2u, 2u}}, - {{1u, 4u}, {1u, 1u, 3u, 3u, 4u}}, - {{2u, 4u}, {3u, 3u, 4u, 2u, 2u}}, - {{3u, 4u}, {4u, 4u, 3u, 3u, 3u}}, - {{4u, 4u}, {4u, 4u, 4u, 4u, 4u}}}; - - for (const auto& lower : lowerValues) - { - constexpr size_t numberOfRandomDraws{5u}; - - for (size_t it{0u}; it < numberOfRandomDraws; ++it) - { - constexpr size_t upper{maximumSize - 1u}; - - const std::array& expectedData{expectedOutput.at(std::make_pair(lower, upper))}; - - const size_t randomValue{GetRandomValueWithinBounds(lower, upper)}; - - ASSERT_GE(randomValue, lower); - ASSERT_LE(randomValue, upper); - ASSERT_EQ(randomValue, expectedData[it]); - } - } - - ASSERT_EQ(GetRandomValueWithinBounds(std::numeric_limits::min(), std::numeric_limits::min()), std::numeric_limits::min()); - ASSERT_EQ(GetRandomValueWithinBounds(std::numeric_limits::max(), std::numeric_limits::max()), std::numeric_limits::max()); -} - -TEST_F(MutationBaseTest, TestGetRandomByteRepetitionLength) -{ - // The expected output data was gathered during a previous run using the default random seed. - // If the random seed is changed, the output data will also change and the unit tests will fail. - - constexpr size_t maximumSize{25u}; - - const std::array expectedOutput{ - 1u, 1u, 7u, 4u, 2u, - 43u, 2u, 4u, 17u, 11u, - 3u, 3u, 3u, 9u, 9u, - 1u, 3u, 5u, 13u, 1u, - 79u, 54u, 2u, 2u, 3u}; - - for (const auto& it : expectedOutput) - { - constexpr size_t MINIMUM_LENGTH{0x01}; - constexpr size_t MAXIMUM_LENGTH{0x20000u + MINIMUM_LENGTH}; - - const size_t randomValue{GetRandomByteRepetitionLength()}; - - ASSERT_GE(randomValue, MINIMUM_LENGTH); - ASSERT_LE(randomValue, MAXIMUM_LENGTH); - ASSERT_EQ(randomValue, it); - } -} -} \ No newline at end of file diff --git a/Radamsa/test/mutationBaseTest.h b/Radamsa/test/mutationBaseTest.h deleted file mode 100644 index 34fa20d..0000000 --- a/Radamsa/test/mutationBaseTest.h +++ /dev/null @@ -1,58 +0,0 @@ -/* ============================================================================= -* Vader Modular Fuzzer -* Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. -* -* -* Effort sponsored by the U.S. Government under Other Transaction number -* W9124P-19-9-0001 between AMTC and the Government. The U.S. Government -* is authorized to reproduce and distribute reprints for Governmental purposes -* notwithstanding any copyright notation thereon. -* -* The views and conclusions contained herein are those of the authors and -* should not be interpreted as necessarily representing the official policies -* or endorsements, either expressed or implied, of the U.S. Government. -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see . -* -* @license GPL-3.0-or-later -* ===========================================================================*/ - -#pragma once - -#ifndef GTEST_DECORATOR -#define GTEST_DECORATOR std::cout << "\033[32m[ ] \033[37m[ INFO ] " -#endif - -// Google Test Includes -#include "gtest/gtest.h" - -// VMF Includes -#include "mutationBase.hpp" - -namespace vader::test::modules::radamsa::mutations -{ -class MutationBaseTest : public ::testing::Test, - public ::vader::radamsa::mutations::MutationBase -{ -public: - virtual ~MutationBaseTest() = default; - - MutationBaseTest() : ::vader::radamsa::mutations::MutationBase{randomNumberGenerator_} {} - -protected: - -private: - std::default_random_engine randomNumberGenerator_; -}; -} \ No newline at end of file diff --git a/Radamsa/test/radamsaMutatorTest.cpp b/Radamsa/test/radamsaMutatorTest.cpp deleted file mode 100644 index 886c7ff..0000000 --- a/Radamsa/test/radamsaMutatorTest.cpp +++ /dev/null @@ -1,493 +0,0 @@ -/* ============================================================================= - * Vader Modular Fuzzer - * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. - * - * - * Effort sponsored by the U.S. Government under Other Transaction number - * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government - * is authorized to reproduce and distribute reprints for Governmental purposes - * notwithstanding any copyright notation thereon. - * - * The views and conclusions contained herein are those of the authors and - * should not be interpreted as necessarily representing the official policies - * or endorsements, either expressed or implied, of the U.S. Government. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * @license GPL-3.0-or-later - * ===========================================================================*/ - -// Google Test Includes -#include "gtest/gtest.h" - -// VMF Includes -#include "radamsaMutatorTest.hpp" - -namespace vader::test::modules::radamsa -{ -TEST_F(UninitializedRadamsaMutatorTest, TestDefaultConstructor) -{ - ASSERT_EQ(RANDOM_NUMBER_GENERATOR_, std::default_random_engine{}); - ASSERT_EQ(algorithmType_, AlgorithmType::ByteMutations_DropByte); - ASSERT_EQ(testCaseKey_, INVALID_TEST_CASE_KEY_); - ASSERT_EQ(normalTag_, INVALID_NORMAL_TAG_); -} - -TEST_F(UninitializedRadamsaMutatorTest, TestInit) -{ - auto runInitMethod{ - [&](std::string&& fileStream, const AlgorithmType expectedAlgorithmType) - { - std::vector configurationFiles; - - configurationFiles.emplace_back(std::move(fileStream)); - - std::unique_ptr configurationManager{std::make_unique(configurationFiles)}; - - init(*configurationManager.get()); - - ASSERT_EQ(algorithmType_, expectedAlgorithmType); - }}; - - // Valid Input - This subtest should update the algorithm type to ByteMutations_DropByte and execute successfuly. - - runInitMethod( - std::string{ - std::move( - std::string{"modules:\n"} + - std::move(" - name: TestMutator\n") + - std::move(" className: \"vader::modules::radamsa::RadamsaMutator\"\n") + - std::move("TestMutator:\n") + - std::move(" algType: ByteMutations_DropByte"))}, - AlgorithmType::ByteMutations_DropByte); - - // Valid Input - This subtest should update the algorithm type to ByteMutations_FlipByte and execute successfuly. - - runInitMethod( - std::string{ - std::move( - std::string{"modules:\n"} + - std::move(" - name: TestMutator\n") + - std::move(" className: \"vader::modules::radamsa::RadamsaMutator\"\n") + - std::move("TestMutator:\n") + - std::move(" algType: ByteMutations_FlipByte"))}, - AlgorithmType::ByteMutations_FlipByte); - - // Valid Input - This subtest should update the algorithm type to ByteMutations_InsertByte and execute successfuly. - - runInitMethod( - std::string{ - std::move( - std::string{"modules:\n"} + - std::move(" - name: TestMutator\n") + - std::move(" className: \"vader::modules::radamsa::RadamsaMutator\"\n") + - std::move("TestMutator:\n") + - std::move(" algType: ByteMutations_InsertByte"))}, - AlgorithmType::ByteMutations_InsertByte); - - // Valid Input - This subtest should update the algorithm type to ByteMutations_RepeatByte and execute successfuly. - - runInitMethod( - std::string{ - std::move( - std::string{"modules:\n"} + - std::move(" - name: TestMutator\n") + - std::move(" className: \"vader::modules::radamsa::RadamsaMutator\"\n") + - std::move("TestMutator:\n") + - std::move(" algType: ByteMutations_RepeatByte"))}, - AlgorithmType::ByteMutations_RepeatByte); - - // Valid Input - This subtest should update the algorithm type to ByteMutations_PermuteByte and execute successfuly. - - runInitMethod( - std::string{ - std::move( - std::string{"modules:\n"} + - std::move(" - name: TestMutator\n") + - std::move(" className: \"vader::modules::radamsa::RadamsaMutator\"\n") + - std::move("TestMutator:\n") + - std::move(" algType: ByteMutations_PermuteByte"))}, - AlgorithmType::ByteMutations_PermuteByte); - - // Valid Input - This subtest should update the algorithm type to ByteMutations_IncrementByte and execute successfuly. - - runInitMethod( - std::string{ - std::move( - std::string{"modules:\n"} + - std::move(" - name: TestMutator\n") + - std::move(" className: \"vader::modules::radamsa::RadamsaMutator\"\n") + - std::move("TestMutator:\n") + - std::move(" algType: ByteMutations_IncrementByte"))}, - AlgorithmType::ByteMutations_IncrementByte); - - // Valid Input - This subtest should update the algorithm type to ByteMutations_DecrementByte and execute successfuly. - - runInitMethod( - std::string{ - std::move( - std::string{"modules:\n"} + - std::move(" - name: TestMutator\n") + - std::move(" className: \"vader::modules::radamsa::RadamsaMutator\"\n") + - std::move("TestMutator:\n") + - std::move(" algType: ByteMutations_DecrementByte"))}, - AlgorithmType::ByteMutations_DecrementByte); - - // Valid Input - This subtest should update the algorithm type to LineMutations_DeleteLine and execute successfuly. - - runInitMethod( - std::string{ - std::move( - std::string{"modules:\n"} + - std::move(" - name: TestMutator\n") + - std::move(" className: \"vader::modules::radamsa::RadamsaMutator\"\n") + - std::move("TestMutator:\n") + - std::move(" algType: LineMutations_DeleteLine"))}, - AlgorithmType::LineMutations_DeleteLine); - - runInitMethod( - std::string{ - std::move( - std::string{"modules:\n"} + - std::move(" - name: TestMutator\n") + - std::move(" className: \"vader::modules::radamsa::RadamsaMutator\"\n") + - std::move("TestMutator:\n") + - std::move(" algType: LineMutations_DeleteSequentialLines"))}, - AlgorithmType::LineMutations_DeleteSequentialLines); - - runInitMethod( - std::string{ - std::move( - std::string{"modules:\n"} + - std::move(" - name: TestMutator\n") + - std::move(" className: \"vader::modules::radamsa::RadamsaMutator\"\n") + - std::move("TestMutator:\n") + - std::move(" algType: LineMutations_DuplicateLine"))}, - AlgorithmType::LineMutations_DuplicateLine); - - runInitMethod( - std::string{ - std::move( - std::string{"modules:\n"} + - std::move(" - name: TestMutator\n") + - std::move(" className: \"vader::modules::radamsa::RadamsaMutator\"\n") + - std::move("TestMutator:\n") + - std::move(" algType: LineMutations_CopyLineCloseBy"))}, - AlgorithmType::LineMutations_CopyLineCloseBy); - - runInitMethod( - std::string{ - std::move( - std::string{"modules:\n"} + - std::move(" - name: TestMutator\n") + - std::move(" className: \"vader::modules::radamsa::RadamsaMutator\"\n") + - std::move("TestMutator:\n") + - std::move(" algType: LineMutations_RepeatLine"))}, - AlgorithmType::LineMutations_RepeatLine); - - runInitMethod( - std::string{ - std::move( - std::string{"modules:\n"} + - std::move(" - name: TestMutator\n") + - std::move(" className: \"vader::modules::radamsa::RadamsaMutator\"\n") + - std::move("TestMutator:\n") + - std::move(" algType: LineMutations_SwapLine"))}, - AlgorithmType::LineMutations_SwapLine); - - // Erroneous Input - This subtest should trigger a runtime exception since the algorithm type is Unknown. - - EXPECT_THROW( - runInitMethod( - std::string{ - std::move( - std::string{"modules:\n"} + - std::move(" - name: TestMutator\n") + - std::move(" className: \"vader::modules::radamsa::RadamsaMutator\"\n") + - std::move("TestMutator:\n") + - std::move(" algType: Unknown"))}, - AlgorithmType::Unknown), - RuntimeException); - - // Erroneous Input - This subtest should trigger a runtime exception since the algorithm type is Unmapped. - - EXPECT_THROW( - runInitMethod( - std::string{ - std::move( - std::string{"modules:\n"} + - std::move(" - name: TestMutator\n") + - std::move(" className: \"vader::modules::radamsa::RadamsaMutator\"\n") + - std::move("TestMutator:\n") + - std::move(" algType: Unmapped"))}, - AlgorithmType::Unknown), - RuntimeException); -} - -TEST_F(UninitializedRadamsaMutatorTest, TestRegisterStorageNeeds) -{ - StorageRegistry storageRegistry{ - "TEST_FLOAT", - StorageRegistry::storageTypes::FLOAT, - StorageRegistry::sortOrder::DESCENDING}; - - registerStorageNeeds(storageRegistry); - - ASSERT_NE(testCaseKey_, INVALID_TEST_CASE_KEY_); - ASSERT_NE(normalTag_, INVALID_NORMAL_TAG_); -} - -TEST_F(UninitializedRadamsaMutatorTest, TestBuild) -{ - std::unique_ptr module{build("TestMutator")}; - - ASSERT_EQ(module->getModuleName(), "TestMutator"); - ASSERT_EQ(module->getModuleType(), MUTATOR); -} - -TEST_F(UninitializedRadamsaMutatorTest, TestGetAlgorithmType) -{ - auto runGetAlgorithmTypeMethod{ - [&](const AlgorithmType expectedAlgorithmType) - { - algorithmType_ = expectedAlgorithmType; - - ASSERT_EQ(GetAlgorithmType(), expectedAlgorithmType); - }}; - - runGetAlgorithmTypeMethod(AlgorithmType::ByteMutations_DropByte); - runGetAlgorithmTypeMethod(AlgorithmType::ByteMutations_FlipByte); - runGetAlgorithmTypeMethod(AlgorithmType::ByteMutations_InsertByte); - runGetAlgorithmTypeMethod(AlgorithmType::ByteMutations_RepeatByte); - runGetAlgorithmTypeMethod(AlgorithmType::ByteMutations_PermuteByte); - runGetAlgorithmTypeMethod(AlgorithmType::ByteMutations_IncrementByte); - runGetAlgorithmTypeMethod(AlgorithmType::ByteMutations_DecrementByte); - runGetAlgorithmTypeMethod(AlgorithmType::ByteMutations_RandomizeByte); - runGetAlgorithmTypeMethod(AlgorithmType::LineMutations_DeleteLine); - runGetAlgorithmTypeMethod(AlgorithmType::LineMutations_DeleteSequentialLines); - runGetAlgorithmTypeMethod(AlgorithmType::LineMutations_DuplicateLine); - runGetAlgorithmTypeMethod(AlgorithmType::LineMutations_CopyLineCloseBy); - runGetAlgorithmTypeMethod(AlgorithmType::LineMutations_RepeatLine); - runGetAlgorithmTypeMethod(AlgorithmType::LineMutations_SwapLine); - runGetAlgorithmTypeMethod(AlgorithmType::Unknown); -} - -TEST_F(InitializedRadamsaMutatorTest, TestCreateTestCase_ByteMutations) -{ - { - StorageEntry* baseEntry{GetBaseEntry(asciiInput_, sizeof(asciiInput_))}; - - { - // Valid Input - This subtest should update the algorithm type to ByteMutations_DropByte and execute successfuly. - - constexpr int expectedBufferSize{sizeof(asciiInput_)}; - - RunSetTestCaseMethod(AlgorithmType::ByteMutations_DropByte, expectedBufferSize, baseEntry); - } - - { - // Valid Input - This subtest should update the algorithm type to ByteMutations_FlipByte and execute successfuly. - - constexpr int expectedBufferSize{sizeof(asciiInput_) + 1}; - - RunSetTestCaseMethod(AlgorithmType::ByteMutations_FlipByte, expectedBufferSize, baseEntry); - } - - { - // Valid Input - This subtest should update the algorithm type to ByteMutations_InsertByte and execute successfuly. - - constexpr int expectedBufferSize{sizeof(asciiInput_) + 2}; - - RunSetTestCaseMethod(AlgorithmType::ByteMutations_InsertByte, expectedBufferSize, baseEntry); - } - - { - // Valid Input - This subtest should update the algorithm type to ByteMutations_RepeatByte and execute successfuly. - - // The expected output size for this subtest was gathered during a previous run using the default random seed. - // If the random seed is changed or new calls to the subtests are added prior to this statement, - // the output size will also change and the unit tests will fail. - - constexpr int expectedBufferSize{sizeof(asciiInput_) + 2}; - - RunSetTestCaseMethod(AlgorithmType::ByteMutations_RepeatByte, expectedBufferSize, baseEntry); - } - - { - // Valid Input - This subtest should update the algorithm type to ByteMutations_PermuteByte and execute successfuly. - - constexpr int expectedBufferSize{sizeof(asciiInput_) + 1}; - - RunSetTestCaseMethod(AlgorithmType::ByteMutations_PermuteByte, expectedBufferSize, baseEntry); - } - - { - // Valid Input - This subtest should update the algorithm type to ByteMutations_IncrementByte and execute successfuly. - - constexpr int expectedBufferSize{sizeof(asciiInput_) + 1}; - - RunSetTestCaseMethod(AlgorithmType::ByteMutations_IncrementByte, expectedBufferSize, baseEntry); - } - - { - // Valid Input - This subtest should update the algorithm type to ByteMutations_DecrementByte and execute successfuly. - - constexpr int expectedBufferSize{sizeof(asciiInput_) + 1}; - - RunSetTestCaseMethod(AlgorithmType::ByteMutations_DecrementByte, expectedBufferSize, baseEntry); - } - - { - // Valid Input - This subtest should update the algorithm type to ByteMutations_RandomizeByte and execute successfuly. - - constexpr int expectedBufferSize{sizeof(asciiInput_) + 1}; - - RunSetTestCaseMethod(AlgorithmType::ByteMutations_RandomizeByte, expectedBufferSize, baseEntry); - } - } -} - -TEST_F(InitializedRadamsaMutatorTest, TestCreateTestCase_LineMutations_AsciiInput) -{ - { - StorageEntry* baseEntry{GetBaseEntry(asciiInput_, sizeof(asciiInput_))}; - - { - // Valid Input - This subtest should update the algorithm type to LineMutations_DeleteLine and execute successfuly. - - constexpr int expectedBufferSize{1}; - - RunSetTestCaseMethod(AlgorithmType::LineMutations_DeleteLine, expectedBufferSize, baseEntry); - } - - { - // Valid Input - This subtest should update the algorithm type to LineMutations_DeleteSequentialLines and execute successfuly. - - constexpr int expectedBufferSize{1}; - - RunSetTestCaseMethod(AlgorithmType::LineMutations_DeleteSequentialLines, expectedBufferSize, baseEntry); - } - - { - // Valid Input - This subtest should update the algorithm type to LineMutations_DuplicateLine and execute successfuly. - - constexpr int expectedBufferSize{sizeof(asciiInput_) + 1}; - - RunSetTestCaseMethod(AlgorithmType::LineMutations_DuplicateLine, expectedBufferSize, baseEntry); - } - - { - // Valid Input - This subtest should update the algorithm type to LineMutations_CopyLineCloseBy and execute successfuly. - - constexpr int expectedBufferSize{sizeof(asciiInput_) + 1}; - - RunSetTestCaseMethod(AlgorithmType::LineMutations_CopyLineCloseBy, expectedBufferSize, baseEntry); - } - - { - // Valid Input - This subtest should update the algorithm type to LineMutations_RepeatLine and execute successfuly. - - constexpr int expectedBufferSize{sizeof(asciiInput_) + 1}; - - RunSetTestCaseMethod(AlgorithmType::LineMutations_RepeatLine, expectedBufferSize, baseEntry); - } - - { - // Valid Input - This subtest should update the algorithm type to LineMutations_SwapLine and execute successfuly. - - constexpr int expectedBufferSize{sizeof(asciiInput_) + 1}; - - RunSetTestCaseMethod(AlgorithmType::LineMutations_SwapLine, expectedBufferSize, baseEntry); - } - } -} - -TEST_F(InitializedRadamsaMutatorTest, TestCreateTestCase_LineMutations_Utf8Input) -{ - { - StorageEntry* baseEntry{GetBaseEntry(utf8Input_, sizeof(utf8Input_))}; - - { - // Valid Input - This subtest should update the algorithm type to LineMutations_DeleteLine and execute successfuly. - - constexpr int expectedBufferSize{sizeof(utf8Input_) + 1}; - - RunSetTestCaseMethod(AlgorithmType::LineMutations_DeleteLine, expectedBufferSize, baseEntry); - } - - { - // Valid Input - This subtest should update the algorithm type to LineMutations_DeleteSequentialLines and execute successfuly. - - constexpr int expectedBufferSize{sizeof(utf8Input_) + 1}; - - RunSetTestCaseMethod(AlgorithmType::LineMutations_DeleteSequentialLines, expectedBufferSize, baseEntry); - } - - { - // Valid Input - This subtest should update the algorithm type to LineMutations_DuplicateLine and execute successfuly. - - constexpr int expectedBufferSize{sizeof(utf8Input_) * 2 + 1}; - - RunSetTestCaseMethod(AlgorithmType::LineMutations_DuplicateLine, expectedBufferSize, baseEntry); - } - - { - // Valid Input - This subtest should update the algorithm type to LineMutations_CopyLineCloseBy and execute successfuly. - - constexpr int expectedBufferSize{sizeof(utf8Input_) * 2 + 1}; - - RunSetTestCaseMethod(AlgorithmType::LineMutations_CopyLineCloseBy, expectedBufferSize, baseEntry); - } - - { - // Valid Input - This subtest should update the algorithm type to LineMutations_RepeatLine and execute successfuly. - - // The expected output size for this subtest was gathered during a previous run using the default random seed. - // If the random seed is changed or new calls to the subtests are added prior to this statement, - // the output size will also change and the unit tests will fail. - - constexpr int expectedBufferSize{sizeof(utf8Input_) * 2 + 1}; - - RunSetTestCaseMethod(AlgorithmType::LineMutations_RepeatLine, expectedBufferSize, baseEntry); - } - - { - // Valid Input - This subtest should update the algorithm type to LineMutations_SwapLine and execute successfuly. - - constexpr int expectedBufferSize{sizeof(utf8Input_) + 1}; - - RunSetTestCaseMethod(AlgorithmType::LineMutations_SwapLine, expectedBufferSize, baseEntry); - } - } -} - -TEST_F(InitializedRadamsaMutatorTest, TestCreateTestCase_ErroneousInputs) -{ - { - // Erroneous Input - This subtest should trigger a runtime exception since the base entry is null. - - EXPECT_THROW(createTestCase(storage_, nullptr), RuntimeException); - } - - { - // Erroneous Input - This subtest should trigger a runtime exception since the algorithm type is Unknown. - - StorageEntry* baseEntry{GetBaseEntry(asciiInput_, sizeof(asciiInput_))}; - - constexpr int expectedBufferSize_noop{0}; - - EXPECT_THROW(RunSetTestCaseMethod(AlgorithmType::Unknown, expectedBufferSize_noop, baseEntry), RuntimeException); - } -} -} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/CMakeLists.txt b/Radamsa/vmf/src/modules/CMakeLists.txt index 4a17cb6..bc05680 100644 --- a/Radamsa/vmf/src/modules/CMakeLists.txt +++ b/Radamsa/vmf/src/modules/CMakeLists.txt @@ -40,6 +40,12 @@ add_library(Radamsa SHARED common/mutator/RadamsaIncrementByteMutator.cpp common/mutator/RadamsaDecrementByteMutator.cpp common/mutator/RadamsaRandomizeByteMutator.cpp + common/mutator/RadamsaDeleteLineMutator.cpp + common/mutator/RadamsaDeleteSequentialLinesMutator.cpp + common/mutator/RadamsaDuplicateLineMutator.cpp + common/mutator/RadamsaCopyLineCloseByMutator.cpp + common/mutator/RadamsaRepeatLineMutator.cpp + common/mutator/RadamsaSwapLineMutator.cpp ) # Build-time dependencies for Radamsa diff --git a/Radamsa/vmf/src/modules/common/mutator/.byteMutations.hpp.swp b/Radamsa/vmf/src/modules/common/mutator/.byteMutations.hpp.swp deleted file mode 100644 index b463aec5e70344c939c65bc0133902532d847033..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16384 zcmeHNUu+yl8DB~%6cRwt0^)&wI1o9BeP=s`l8YUDvCpxE?O10!Y51csw>x_`cz0*n zoxSrVO7g-(C3rwo(5HfEB!mP~kq{yhLX{}uk=H(e=o6>{@qk48z(4W(X7}Pd<2I?( zhm!8fKb`kx=G*W4&G%<^Zdy|pR@UfLW!k~@e#d$FLpS}SUurnsiN~BB5h(upPS@S` zyUrb}8;NcwA`Dg3u69GedLi^1yRl4EC?g|+YEyV3OoeSr6So>_FAHQ^b#)l(s2XNQ z7@bsGeIwWSf2E_e(uw0cX<4?H47}ADIP9F9nVw=6j*NYrKKOy{w>lxE{Urk>10@3` z10@3`10@3`10@4*DF#e@pK}8i-&a`uh2ryV`##@Z+|LxBU)=)_>;lU`18{&_?{=J@0Xx7) zfy2Nd;9n0q&Od<{f#-mmz%#)2fg8XzpbvZocog_E4EQPV6F>q2_z3V2@TYe=&M$!{ zffhi(A0BX=9|2zls=!~~;W$44`oJ>q0Px)X-~@OASOOM-S>R*9E7%Nq8F(J}4)AT@ zae#nFfJ4Ab*iiWe@FdUy7J&s|3OEG32)=&~Fz;Vy?s3u3<>FL>p;TRwmkr^pgbK58 zQ%Y|o^5pKs0bSjWNRE?ER9i(NIGg#tOb+T-h#c*>iRX-V-ozOT(Uy(KB>m$Q$)5c$ z@6*-FqoqK_XK@B&{2;wmWXQ z%mG%6 z533nxtw6ao=c?ldB28&TP>u3t!Wo}hEy)k{)N1zl4j*kuWvexnFdSzz?2{K2X+Yi{!2=V?&UDGg5J&MC3~9DbpF2 zlXJD2tKw0HJd)VXb=+s94N1rUe{A}C4YOvYHzG{#|!DO!M%NHZNnGgH&2CTFH* zrkI~N$WjL3fY(=~YbsO^0{6$5oG__yMcQ7Zq;>kk7y6$13kre@WO{))e6PK1HPvmUa znGZXYsdV=SoGBs;3&cuRCxI9UrWaCud>h1faLw`$J-=7;_&E<~|36~!4G zj9kp4ky}Nj8ALBLO@l;3p)?(xJKi>e(5hQx23WvPOidq-cYA;c+Nh4E1Iu*&EeD$% zWE~spti*gPQPKxZh{ODlA}in}qL(t0U4_ZZVnh-T4yha@9oDn7@MF7fI zOOsd@94V-$v4M)5G5N^j*ic(DiwurXHf%0H{O)fbF6eoiQ?1g4wIz-?JF|FFjG7+` zBs`ZhGR?hlSDxPIi&RMGHdZH3R;DI(G8te75xAT>**VhK+a1lC`}=ZOvvwlT@XI34 zfq7H~K3H0z6`znKCn$x_S-C|@Zb#Xu)Uir zMyUM(ZP>~;$eD#cuinAdqfjRj%LAlk`&(w6wCd-q_rv zrSnay(?-3ywX(3iT5r!(Ow=zQ)SGJbVZ*Nh3{SsZQH=7W5>9plU zqg8g1H`x0WmjzhV6G?)q$2Eo}Sl2CRv%afRlPJhVSA-Cc>|nKne^7!I3aCOx&r6@5 z1)LmN$~YQPoDwW>_%QA<5)m?soz-q$ODxSSZ7IQ&Y--;?5!`81A$x##f+PYCZcq%M zll!XR1lZwcL5aP}1-}W?LC4o%U%)qb!qN`xYV{AY+-JqoLa`c~W6OLZz1x)Vvr#Cj zm?lKK@>vdx!o7?An-1fB~R5Wy+aR3w~KkY2f-BHrQuOsn>>%2DvkSR=rcOmh>FR1^vYYmJ1>QO<>( zGx(qofpWEbrePxRzfR|wAA1$yL`eN^J*nu2%y!@BWsgLBp+4) zA(_juOEctB)*FYpk?dHbA!fM&_U7xhJyzJDEI}#B4Z3)0dgjrMNh~=|O-@ZsO@k%V zlko8R+SY;<$z1FWuhmn-Dv6hUe0F%R9>weYm_Y!huEZc^d0gHx1+ zEn6m8*euq!^GN!5DX>ch{%&u5GwvS4>Skt|S4k(WJ_~qH!*O=n#G-VE7VSV<6)mhq zxL{6jI=1v(;95*;eEMA=GuV|as>U0cl;`Fge*gaz-k~4HdpE!T4}RbOJ>K_!2mA(j z2FQRlU<~*V-uwRzyafCjcnZ+KB0#_+z=Oaau^(^?_$DBMIxr861NQ?jU~k}A;A_B_ zfy=--;0W*v_6L3o+yrg_*8v|m3p@<`75e@P_%84?@GamIz!8A=57H z9;N(t-L8@I_hqbWk5P?=_j|7%*y|cyy@uy%gY84<6;B@QzU71L_Fgp*uV?qRfg9LW!4A;9I)6 + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-3.0-or-later + * ===========================================================================*/ + +#pragma once + +#include "RadamsaMutatorBase.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaByteMutatorBase: public RadamsaMutatorBase +{ +public: + static size_t GetRandomByteRepetitionLength(VmfRand* rand) noexcept + { + constexpr size_t MINIMUM_UPPER_LIMIT{0x2u}; + constexpr size_t MAXIMUM_UPPER_LIMIT{0x20000u}; + + size_t randomStop{rand->randBetween(0u, MINIMUM_UPPER_LIMIT)}; + size_t randomUpperLimit{MINIMUM_UPPER_LIMIT}; + + while(randomStop != 0u) + { + if(randomUpperLimit == MAXIMUM_UPPER_LIMIT) + break; + + randomUpperLimit <<= 1u; + randomStop = rand->randBetween(0u, MINIMUM_UPPER_LIMIT); + } + + return rand->randBetween(0u, randomUpperLimit) + 1u; // We add one to the return value in order to account for the case where the random upper value is zero. + } +}; +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaCopyLineCloseByMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaCopyLineCloseByMutator.cpp new file mode 100644 index 0000000..57fe1a1 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaCopyLineCloseByMutator.cpp @@ -0,0 +1,171 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaCopyLineCloseByMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaCopyLineCloseByMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaCopyLineCloseByMutator::build(std::string name) +{ + return new RadamsaCopyLineCloseByMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaCopyLineCloseByMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaCopyLineCloseByMutator::RadamsaCopyLineCloseByMutator object + * + * @param name The of the name module + */ +RadamsaCopyLineCloseByMutator::RadamsaCopyLineCloseByMutator(std::string name) : MutatorModule(name) +{ + // rand.randInit(); +} + +/** + * @brief Destroy the RadamsaCopyLineCloseByMutator::RadamsaCopyLineCloseByMutator object + * + */ +RadamsaCopyLineCloseByMutator::~RadamsaCopyLineCloseByMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaCopyLineCloseByMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +void RadamsaCopyLineCloseByMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + // Consume the original buffer by copying a line to a random location and appending a null-terminator to the end. + + constexpr size_t minimumSize{1u}; + const size_t minimumSeedIndex{0u}; + const size_t characterIndex{0u}; + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); + + if (originalSize < minimumSize) + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; + + if (characterIndex > originalSize - 1u) + throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + + if (originalBuffer == nullptr) + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + + const size_t numberOfLinesAfterIndex{ + GetNumberOfLinesAfterIndex( + originalBuffer, + originalSize, + characterIndex)}; + + // Select random line to copy from/to. + + const size_t minimumRandomLineOffset{0u}; + + const size_t randomLineIndexSource{ + rand->randBetween( + minimumRandomLineOffset, + numberOfLinesAfterIndex - 1u)}; + + const size_t randomLineIndexDestination{ + rand->randBetween( + minimumRandomLineOffset, + numberOfLinesAfterIndex - 1u)}; + + const Line lineDataSource{ + GetLineData( + originalBuffer, + originalSize, + randomLineIndexSource, + numberOfLinesAfterIndex)}; + + const Line lineDataDestination{ + GetLineData( + originalBuffer, + originalSize, + randomLineIndexDestination, + numberOfLinesAfterIndex)}; + + // The new buffer will be one line larger than the original buffer; + // additionally, it will contain one additional byte since a null-terminator will be appended to the end. + + const size_t newBufferSize{originalSize + lineDataSource.Size + 1u}; + + // Allocate the new buffer and set it's elements to zero. + + char* newBuffer{newEntry->allocateBuffer(testCaseKey, newBufferSize)}; + memset(newBuffer, 0u, newBufferSize); + + // Copy data from the original buffer into the new buffer, but copy the random line. + // The last element in the new buffer is skipped since it was implicitly set to zero during allocation. + + for(size_t sourceIndex{0u}, destinationIndex{0u}; sourceIndex < originalSize; ++sourceIndex) + { + if(sourceIndex == lineDataDestination.StartIndex) + { + memcpy(&newBuffer[destinationIndex], &originalBuffer[lineDataSource.StartIndex], lineDataSource.Size); + + destinationIndex += lineDataSource.Size; + } + + newBuffer[destinationIndex] = originalBuffer[sourceIndex]; + + ++destinationIndex; + } +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaCopyLineCloseByMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaCopyLineCloseByMutator.hpp new file mode 100644 index 0000000..f438c88 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaCopyLineCloseByMutator.hpp @@ -0,0 +1,57 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "RadamsaLineMutatorBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaCopyLineCloseByMutator: public MutatorModule, public RadamsaLineMutatorBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaCopyLineCloseByMutator(std::string name); + virtual ~RadamsaCopyLineCloseByMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand* rand = VmfRand::getInstance(); +}; +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaDecrementByteMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaDecrementByteMutator.cpp index 30cbd04..cc01b52 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaDecrementByteMutator.cpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaDecrementByteMutator.cpp @@ -66,7 +66,7 @@ void RadamsaDecrementByteMutator::init(ConfigInterface& config) */ RadamsaDecrementByteMutator::RadamsaDecrementByteMutator(std::string name) : MutatorModule(name) { - rand.randInit(); + // rand->randInit(); } /** @@ -125,7 +125,7 @@ void RadamsaDecrementByteMutator::mutateTestCase(StorageModule& storage, Storage const size_t maximumRandomIndexValue{originalSize - minimumSeedIndex}; const size_t randomIndexToDecrement{ std::clamp( - rand.randBetween( + rand->randBetween( lower, maximumRandomIndexValue) + minimumSeedIndex, lower, diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaDecrementByteMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaDecrementByteMutator.hpp index b8be538..0cd9c6b 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaDecrementByteMutator.hpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaDecrementByteMutator.hpp @@ -31,7 +31,7 @@ #include "MutatorModule.hpp" #include "StorageEntry.hpp" #include "RuntimeException.hpp" -#include "mutationBase.hpp" +#include "RadamsaByteMutatorBase.hpp" #include "VmfRand.hpp" namespace vmf @@ -39,7 +39,7 @@ namespace vmf /** * */ -class RadamsaDecrementByteMutator: public MutatorModule, public MutationBase +class RadamsaDecrementByteMutator: public MutatorModule, public RadamsaByteMutatorBase { public: @@ -52,6 +52,6 @@ class RadamsaDecrementByteMutator: public MutatorModule, public MutationBase virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); private: - VmfRand rand; + VmfRand* rand = VmfRand::getInstance(); }; } \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteLineMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteLineMutator.cpp new file mode 100644 index 0000000..357e28a --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteLineMutator.cpp @@ -0,0 +1,158 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaDeleteLineMutator.hpp" +#include "RuntimeException.hpp" + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaDeleteLineMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaDeleteLineMutator::build(std::string name) +{ + return new RadamsaDeleteLineMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaDeleteLineMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaDeleteLineMutator::RadamsaDeleteLineMutator object + * + * @param name The of the name module + */ +RadamsaDeleteLineMutator::RadamsaDeleteLineMutator(std::string name) : MutatorModule(name) +{ + // rand.randInit(); +} + +/** + * @brief Destroy the RadamsaDeleteLineMutator::RadamsaDeleteLineMutator object + * + */ +RadamsaDeleteLineMutator::~RadamsaDeleteLineMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaDeleteLineMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +void RadamsaDeleteLineMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + // Consume the original buffer by deleting a line from it and appending a null-terminator to the end. + + constexpr size_t minimumSize{1u}; + const size_t minimumSeedIndex{0u}; + const size_t characterIndex{0u}; + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); + + if (originalSize < minimumSize) + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; + + if (characterIndex > originalSize - 1u) + throw RuntimeException{"Character index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + + if (originalBuffer == nullptr) + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + + const size_t numberOfLinesAfterIndex{ + GetNumberOfLinesAfterIndex( + originalBuffer, + originalSize, + characterIndex)}; + + // Select a random line to delete. + + constexpr size_t minimumRandomLineIndex{0u}; + const size_t maximumRandomLineIndex{numberOfLinesAfterIndex - 1u}; + + const size_t randomLineIndex{ + rand->randBetween( + minimumRandomLineIndex, + maximumRandomLineIndex)}; + + const Line lineData{ + GetLineData( + originalBuffer, + originalSize, + randomLineIndex, + numberOfLinesAfterIndex)}; + + // The new buffer will be one line smaller than the original buffer; + // additionally, it will contain one additional byte since a null-terminator will be appended to the end. + + const size_t newBufferSize{originalSize - lineData.Size + 1u}; + // const std::string message = ("numberOfLinesAfterIndex = " + std::to_string(numberOfLinesAfterIndex)); //deleteme + // throw RuntimeException(message.c_str()); //deleteme + + // Allocate the new buffer and set it's elements to zero. + + char* newBuffer{newEntry->allocateBuffer(testCaseKey, newBufferSize)}; + memset(newBuffer, 0u, newBufferSize); + + // Copy data from the original buffer into the new buffer, but skip the elements in the random line that is to be deleted. + // The last element in the new buffer is skipped since it was implicitly set to zero during allocation. + + for(size_t sourceIndex{0u}, destinationIndex{0u}; sourceIndex < originalSize; ++sourceIndex) + { + const size_t lineStartIndex{lineData.StartIndex}; + const size_t lineEndIndex{lineStartIndex + lineData.Size}; + + if(sourceIndex < lineStartIndex || sourceIndex >= lineEndIndex) + { + newBuffer[destinationIndex] = originalBuffer[sourceIndex]; + ++destinationIndex; + } + } +} diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteLineMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteLineMutator.hpp new file mode 100644 index 0000000..b1a828f --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteLineMutator.hpp @@ -0,0 +1,57 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "RadamsaLineMutatorBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaDeleteLineMutator: public MutatorModule, public RadamsaLineMutatorBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaDeleteLineMutator(std::string name); + virtual ~RadamsaDeleteLineMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand* rand = VmfRand::getInstance(); +}; +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteSequentialLinesMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteSequentialLinesMutator.cpp new file mode 100644 index 0000000..9bafe5d --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteSequentialLinesMutator.cpp @@ -0,0 +1,170 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaDeleteSequentialLinesMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaDeleteSequentialLinesMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaDeleteSequentialLinesMutator::build(std::string name) +{ + return new RadamsaDeleteSequentialLinesMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaDeleteSequentialLinesMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaDeleteSequentialLinesMutator::RadamsaDeleteSequentialLinesMutator object + * + * @param name The of the name module + */ +RadamsaDeleteSequentialLinesMutator::RadamsaDeleteSequentialLinesMutator(std::string name) : MutatorModule(name) +{ + // rand.randInit(); +} + +/** + * @brief Destroy the RadamsaDeleteSequentialLinesMutator::RadamsaDeleteSequentialLinesMutator object + * + */ +RadamsaDeleteSequentialLinesMutator::~RadamsaDeleteSequentialLinesMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaDeleteSequentialLinesMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +void RadamsaDeleteSequentialLinesMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + // Consume the original buffer by deleting sequential lines from it and appending a null-terminator to the end. + + constexpr size_t minimumSize{1u}; + const size_t minimumSeedIndex{0u}; + const size_t characterIndex{0u}; + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); + + if (originalSize < minimumSize) + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; + + if (characterIndex > originalSize - 1u) + throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + + if (originalBuffer == nullptr) + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + + + const size_t numberOfLinesAfterIndex{ + GetNumberOfLinesAfterIndex( + originalBuffer, + originalSize, + characterIndex)}; + + // Select a random line to delete. + + const size_t minimumRandomLineOffset{0u}; + + const size_t randomLineIndexStart{ + rand->randBetween( + minimumRandomLineOffset, + numberOfLinesAfterIndex - 1u)}; + + const size_t randomLineIndexEnd{ + rand->randBetween( + minimumRandomLineOffset, + (numberOfLinesAfterIndex - 1u) - randomLineIndexStart) + randomLineIndexStart}; + + const Line startLineData{ + GetLineData( + originalBuffer, + originalSize, + randomLineIndexStart, + numberOfLinesAfterIndex)}; + + const Line endLineData{ + GetLineData( + originalBuffer, + originalSize, + randomLineIndexEnd, + numberOfLinesAfterIndex)}; + + // The new buffer will be multiple lines smaller than the original buffer; + // additionally, it will contain one additional byte since a null-terminator will be appended to the end. + + const size_t newBufferSize{(originalSize - ((endLineData.StartIndex + endLineData.Size) - startLineData.StartIndex)) + 1u}; + + // Allocate the new buffer and set it's elements to zero. + + char* newBuffer{newEntry->allocateBuffer(testCaseKey, newBufferSize)}; + memset(newBuffer, 0u, newBufferSize); + + // Copy data from the original buffer into the new buffer, but skip the elements in the random lines that are to be deleted. + // The last element in the new buffer is skipped since it was implicitly set to zero during allocation. + + for(size_t sourceIndex{0u}, destinationIndex{0u}; sourceIndex < originalSize; ++sourceIndex) + { + const size_t lineStartIndex{startLineData.StartIndex}; + const size_t lineEndIndex{endLineData.StartIndex + endLineData.Size}; + + if(sourceIndex < lineStartIndex || sourceIndex >= lineEndIndex) + { + newBuffer[destinationIndex] = originalBuffer[sourceIndex]; + ++destinationIndex; + } + } +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteSequentialLinesMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteSequentialLinesMutator.hpp new file mode 100644 index 0000000..3bee1f4 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteSequentialLinesMutator.hpp @@ -0,0 +1,57 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "RadamsaLineMutatorBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaDeleteSequentialLinesMutator: public MutatorModule, public RadamsaLineMutatorBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaDeleteSequentialLinesMutator(std::string name); + virtual ~RadamsaDeleteSequentialLinesMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand* rand = VmfRand::getInstance(); +}; +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaDropByteMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaDropByteMutator.cpp index 2651460..56131e9 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaDropByteMutator.cpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaDropByteMutator.cpp @@ -66,7 +66,7 @@ void RadamsaDropByteMutator::init(ConfigInterface& config) */ RadamsaDropByteMutator::RadamsaDropByteMutator(std::string name) : MutatorModule(name) { - rand.randInit(); + // rand->randInit(); } /** @@ -123,7 +123,7 @@ void RadamsaDropByteMutator::mutateTestCase(StorageModule& storage, StorageEntry const size_t maximumRandomIndexValue{originalSize - minimumSeedIndex}; const size_t randomIndexToDrop{ std::clamp( - rand.randBetween( + rand->randBetween( lower, maximumRandomIndexValue) + minimumSeedIndex, lower, diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaDropByteMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaDropByteMutator.hpp index 456a257..9d5fe92 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaDropByteMutator.hpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaDropByteMutator.hpp @@ -31,7 +31,7 @@ #include "MutatorModule.hpp" #include "StorageEntry.hpp" #include "RuntimeException.hpp" -#include "mutationBase.hpp" +#include "RadamsaByteMutatorBase.hpp" #include "VmfRand.hpp" namespace vmf @@ -39,7 +39,7 @@ namespace vmf /** * */ -class RadamsaDropByteMutator: public MutatorModule, public MutationBase +class RadamsaDropByteMutator: public MutatorModule, public RadamsaByteMutatorBase { public: @@ -52,6 +52,6 @@ class RadamsaDropByteMutator: public MutatorModule, public MutationBase virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); private: - VmfRand rand; + VmfRand* rand = VmfRand::getInstance(); }; } \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaDuplicateLineMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaDuplicateLineMutator.cpp new file mode 100644 index 0000000..0a0e5bc --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaDuplicateLineMutator.cpp @@ -0,0 +1,179 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaDuplicateLineMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaDuplicateLineMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaDuplicateLineMutator::build(std::string name) +{ + return new RadamsaDuplicateLineMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaDuplicateLineMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaDuplicateLineMutator::RadamsaDuplicateLineMutator object + * + * @param name The of the name module + */ +RadamsaDuplicateLineMutator::RadamsaDuplicateLineMutator(std::string name) : MutatorModule(name) +{ + // rand.randInit(); +} + +/** + * @brief Destroy the RadamsaDuplicateLineMutator::RadamsaDuplicateLineMutator object + * + */ +RadamsaDuplicateLineMutator::~RadamsaDuplicateLineMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaDuplicateLineMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +void RadamsaDuplicateLineMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + // Consume the original buffer by duplicating a line from it and appending a null-terminator to the end. + + constexpr size_t minimumSize{1u}; + const size_t minimumSeedIndex{0u}; + const size_t characterIndex{0u}; + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); + + if (originalSize < minimumSize) + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; + + if (characterIndex > originalSize - 1u) + throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + + if (originalBuffer == nullptr) + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + + const size_t numberOfLinesAfterIndex{ + GetNumberOfLinesAfterIndex( + originalBuffer, + originalSize, + characterIndex)}; + + // Select a random line to duplicate. + + constexpr size_t minimumRandomLineIndex{0u}; + const size_t maximumRandomLineIndex{numberOfLinesAfterIndex - 1u}; + + const size_t randomLineIndex{ + rand->randBetween( + minimumRandomLineIndex, + maximumRandomLineIndex)}; + + const Line lineData{ + GetLineData( + originalBuffer, + originalSize, + randomLineIndex, + numberOfLinesAfterIndex)}; + + // The new buffer will be one line larger than the original buffer; + // additionally, it will contain one additional byte since a null-terminator will be appended to the end. + + const size_t newBufferSize{originalSize + lineData.Size + 1u}; + + // Allocate the new buffer and set it's elements to zero. + + char* newBuffer{newEntry->allocateBuffer(testCaseKey, newBufferSize)}; + memset(newBuffer, 0u, newBufferSize); + + // Copy data from the original buffer into the new buffer, but duplicate the random line. + // The last element in the new buffer is skipped since it was implicitly set to zero during allocation. + + { + // Copy all of the elements including the line that is to be duplicated. + + const size_t numberOfBytes{lineData.StartIndex + lineData.Size}; + + char* destination{newBuffer}; + const char* source{originalBuffer}; + + memcpy(destination, source, numberOfBytes); + } + + { + // Duplicate the line. + + const size_t numberOfBytes{lineData.Size}; + + char* destination{newBuffer + lineData.StartIndex + lineData.Size}; + const char* source{originalBuffer + lineData.StartIndex}; + + memcpy(destination, source, numberOfBytes); + } + + { + // Copy all of the elements after the line that was duplicated. + + const size_t numberOfBytes{originalSize - (lineData.StartIndex + lineData.Size)}; + + char* destination{newBuffer + lineData.StartIndex + 2 * lineData.Size}; + const char* source{originalBuffer + lineData.StartIndex + lineData.Size}; + + memcpy(destination, source, numberOfBytes); + } +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaDuplicateLineMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaDuplicateLineMutator.hpp new file mode 100644 index 0000000..75ec46e --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaDuplicateLineMutator.hpp @@ -0,0 +1,57 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "RadamsaLineMutatorBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaDuplicateLineMutator: public MutatorModule, public RadamsaLineMutatorBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaDuplicateLineMutator(std::string name); + virtual ~RadamsaDuplicateLineMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand* rand = VmfRand::getInstance(); +}; +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp index d56ba99..078327a 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp @@ -66,7 +66,7 @@ void RadamsaFlipByteMutator::init(ConfigInterface& config) */ RadamsaFlipByteMutator::RadamsaFlipByteMutator(std::string name) : MutatorModule(name) { - rand.randInit(); + // rand->randInit(); } /** @@ -124,7 +124,7 @@ void RadamsaFlipByteMutator::mutateTestCase(StorageModule& storage, StorageEntry const size_t maximumRandomIndexValue{originalSize - minimumSeedIndex}; const size_t randomIndexToFlip{ std::clamp( - rand.randBetween( + rand->randBetween( lower, maximumRandomIndexValue ) + minimumSeedIndex, @@ -135,7 +135,7 @@ void RadamsaFlipByteMutator::mutateTestCase(StorageModule& storage, StorageEntry // When computing the random bit shift, // we add 1 so that a maximum number of 8 bit shift operations can be performed against a char containing the value 0x01. - const size_t randomBitShift{rand.randBetween(0u, std::numeric_limits::digits + 1u)}; + const size_t randomBitShift{rand->randBetween(0u, std::numeric_limits::digits + 1u)}; const char randomMaskedBit{static_cast(0x01u << randomBitShift)}; // Flip the random byte by performing an XOR operation with a random masked bit. diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp index 4b98924..a9da1b2 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.hpp @@ -31,7 +31,7 @@ #include "MutatorModule.hpp" #include "StorageEntry.hpp" #include "RuntimeException.hpp" -#include "mutationBase.hpp" +#include "RadamsaByteMutatorBase.hpp" #include "VmfRand.hpp" namespace vmf @@ -39,7 +39,7 @@ namespace vmf /** * */ -class RadamsaFlipByteMutator: public MutatorModule, public MutationBase +class RadamsaFlipByteMutator: public MutatorModule, public RadamsaByteMutatorBase { public: @@ -52,6 +52,6 @@ class RadamsaFlipByteMutator: public MutatorModule, public MutationBase virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); private: - VmfRand rand; + VmfRand* rand = VmfRand::getInstance(); }; } \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaIncrementByteMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaIncrementByteMutator.cpp index c4be505..577b4b8 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaIncrementByteMutator.cpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaIncrementByteMutator.cpp @@ -66,7 +66,7 @@ void RadamsaIncrementByteMutator::init(ConfigInterface& config) */ RadamsaIncrementByteMutator::RadamsaIncrementByteMutator(std::string name) : MutatorModule(name) { - rand.randInit(); + // rand->randInit(); } /** @@ -124,7 +124,7 @@ void RadamsaIncrementByteMutator::mutateTestCase(StorageModule& storage, Storage const size_t maximumRandomIndexValue{originalSize - minimumSeedIndex}; const size_t randomIndexToIncrement{ std::clamp( - rand.randBetween( + rand->randBetween( lower, maximumRandomIndexValue) + minimumSeedIndex, lower, diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaIncrementByteMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaIncrementByteMutator.hpp index 91b365e..2de3830 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaIncrementByteMutator.hpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaIncrementByteMutator.hpp @@ -31,7 +31,7 @@ #include "MutatorModule.hpp" #include "StorageEntry.hpp" #include "RuntimeException.hpp" -#include "mutationBase.hpp" +#include "RadamsaByteMutatorBase.hpp" #include "VmfRand.hpp" namespace vmf @@ -39,7 +39,7 @@ namespace vmf /** * */ -class RadamsaIncrementByteMutator: public MutatorModule, public MutationBase +class RadamsaIncrementByteMutator: public MutatorModule, public RadamsaByteMutatorBase { public: @@ -52,6 +52,6 @@ class RadamsaIncrementByteMutator: public MutatorModule, public MutationBase virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); private: - VmfRand rand; + VmfRand* rand = VmfRand::getInstance(); }; } \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaInsertByteMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaInsertByteMutator.cpp index 3596238..12e8efe 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaInsertByteMutator.cpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaInsertByteMutator.cpp @@ -66,7 +66,7 @@ void RadamsaInsertByteMutator::init(ConfigInterface& config) */ RadamsaInsertByteMutator::RadamsaInsertByteMutator(std::string name) : MutatorModule(name) { - rand.randInit(); + // rand->randInit(); } /** @@ -124,7 +124,7 @@ void RadamsaInsertByteMutator::mutateTestCase(StorageModule& storage, StorageEnt const size_t maximumRandomIndexValue{originalSize - minimumSeedIndex}; const size_t randomInsertionIndex{ std::clamp( - rand.randBetween( + rand->randBetween( lower, maximumRandomIndexValue ) + minimumSeedIndex, @@ -141,7 +141,7 @@ void RadamsaInsertByteMutator::mutateTestCase(StorageModule& storage, StorageEnt newBuffer[destinationIndex] = originalBuffer[sourceIndex]; if (sourceIndex == randomInsertionIndex) - newBuffer[++destinationIndex] = static_cast(rand.randBetween(0u, std::numeric_limits::max())); + newBuffer[++destinationIndex] = static_cast(rand->randBetween(0u, std::numeric_limits::max())); ++destinationIndex; } diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaInsertByteMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaInsertByteMutator.hpp index c279895..43d2f7f 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaInsertByteMutator.hpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaInsertByteMutator.hpp @@ -31,7 +31,7 @@ #include "MutatorModule.hpp" #include "StorageEntry.hpp" #include "RuntimeException.hpp" -#include "mutationBase.hpp" +#include "RadamsaByteMutatorBase.hpp" #include "VmfRand.hpp" namespace vmf @@ -39,7 +39,7 @@ namespace vmf /** * */ -class RadamsaInsertByteMutator: public MutatorModule, public MutationBase +class RadamsaInsertByteMutator: public MutatorModule, public RadamsaByteMutatorBase { public: @@ -52,6 +52,6 @@ class RadamsaInsertByteMutator: public MutatorModule, public MutationBase virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); private: - VmfRand rand; + VmfRand* rand = VmfRand::getInstance(); }; } \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/lineMutations.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaLineMutatorBase.hpp similarity index 52% rename from Radamsa/vmf/src/modules/common/mutator/lineMutations.hpp rename to Radamsa/vmf/src/modules/common/mutator/RadamsaLineMutatorBase.hpp index 4b42c79..45ad5f4 100644 --- a/Radamsa/vmf/src/modules/common/mutator/lineMutations.hpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaLineMutatorBase.hpp @@ -27,52 +27,18 @@ * * @license GPL-3.0-or-later * ===========================================================================*/ -#pragma once - -// C/C++ Includes -#include -#include - -// Module Includes - -#include "mutationBase.hpp" -// Common Includes - -#include "StorageEntry.hpp" -#include "RuntimeException.hpp" +#pragma once +#include "RadamsaMutatorBase.hpp" +#include "VmfRand.hpp" -namespace vmf::radamsa::mutations +namespace vmf { /** - * @brief This module is draws heavily upon the libAFL mutator.c - * - * Uses the specified AFL-style mutation algorithm to mutate the provided - * input. createTestCase is the main mutation method. * - * See https://github.com/AFLplusplus/LibAFL-legacy/blob/dev/src/mutator.c - * - * The following includes code copied from the LibAFL_Legacy repository. - * - * american fuzzy lop++ - fuzzer header - * ------------------------------------ - * Originally written by Michal Zalewski - * Now maintained by Marc Heuse , - * Heiko Eißfeldt , - * Andrea Fioraldi , - * Dominik Maier - * Copyright 2016, 2017 Google Inc. All rights reserved. - * Copyright 2019-2020 AFLplusplus Project. All rights reserved. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * http://www.apache.org/licenses/LICENSE-2.0 - * This is the Library based on AFL++ which can be used to build - * customized fuzzers for a specific target while taking advantage of - * a lot of features that AFL++ already provides. */ -class LineMutations: public vmf::radamsa::mutations::MutationBase +class RadamsaLineMutatorBase: public RadamsaMutatorBase { public: struct Line @@ -86,8 +52,12 @@ class LineMutations: public vmf::radamsa::mutations::MutationBase Line& operator=(Line&&) = default; Line& operator=(const Line&) = default; - bool operator==(const Line &other) const { return (IsValid == other.IsValid && StartIndex == other.StartIndex && Size == other.Size); } - bool operator!=(const Line &other) const { return !(*this == other); } + bool operator==(const Line &other) const { + return (IsValid == other.IsValid && + StartIndex == other.StartIndex && + Size == other.Size); + } + bool operator!=(const Line &other) const { return !(*this == other); } // we may want to change this to test for equality instead of identity bool IsValid{false}; size_t StartIndex{0u}; @@ -171,9 +141,12 @@ class LineMutations: public vmf::radamsa::mutations::MutationBase return *this; } - bool operator==(const LineVector &other) const { return (Size == other.Size && (memcmp(Data.get(), other.Data.get(), other.Size) == 0)); } + bool operator==(const LineVector &other) const { + return (Size == other.Size && + (memcmp(Data.get(), other.Data.get(), other.Size) == 0)); + } - bool operator!=(const LineVector &other) const { return !(*this == other); } + bool operator!=(const LineVector &other) const { return !(*this == other); } // we may want to change this to test for equality instead of identity std::unique_ptr Data{nullptr}; size_t Size{0u}; @@ -196,10 +169,7 @@ class LineMutations: public vmf::radamsa::mutations::MutationBase { const Line& line{lineData.at(it)}; - data[it] = std::move( - LineVector{ - buffer, - line}); + data[it] = std::move(LineVector{buffer,line}); Capacity += line.Size; } @@ -220,7 +190,9 @@ class LineMutations: public vmf::radamsa::mutations::MutationBase Data = std::make_unique(numberOfElements); for (size_t it{0u}; it < numberOfElements; ++it) + { Data[it] = other.Data[it]; + } } LineList(LineList&& other) noexcept @@ -297,25 +269,26 @@ class LineMutations: public vmf::radamsa::mutations::MutationBase bool operator==(const LineList& other) const { auto compareLineVectors{ - [&](const LineVector* const lhs, const LineVector* const rhs) -> bool - { - if (lhs != nullptr && rhs != nullptr) - { - for (size_t it{0u}; it < lhs->Size; ++it) - if (lhs->Data[it] != rhs->Data[it]) - return false; - - return true; - } - else if (lhs == nullptr && rhs == nullptr) - { - return true; - } - else - { - return false; - } - }}; + [&](const LineVector* const lhs, const LineVector* const rhs) -> bool + { + if (lhs != nullptr && rhs != nullptr) + { + for (size_t it{0u}; it < lhs->Size; ++it) + if (lhs->Data[it] != rhs->Data[it]) + return false; + + return true; + } + else if (lhs == nullptr && rhs == nullptr) + { + return true; + } + else + { + return false; + } + } + }; return ((NumberOfElements == other.NumberOfElements) && (Capacity == other.Capacity) && @@ -329,85 +302,173 @@ class LineMutations: public vmf::radamsa::mutations::MutationBase size_t Capacity{0u}; }; - LineMutations() = delete; - virtual ~LineMutations() = default; - - void DeleteLine( - StorageEntry* newEntry, - const size_t originalSize, - const char* originalBuffer, - const size_t characterIndex, - const int testCaseKey); - - void DeleteSequentialLines( - StorageEntry* newEntry, - const size_t originalSize, - const char* originalBuffer, - const size_t characterIndex, - const int testCaseKey); - - void DuplicateLine( - StorageEntry* newEntry, - const size_t originalSize, - const char* originalBuffer, - const size_t characterIndex, - const int testCaseKey); - - void CopyLineCloseBy( - StorageEntry* newEntry, - const size_t originalSize, - const char* originalBuffer, - const size_t characterIndex, - const int testCaseKey); - - void RepeatLine( - StorageEntry* newEntry, - const size_t originalSize, - const char* originalBuffer, - const size_t characterIndex, - const int testCaseKey); - - void SwapLine( - StorageEntry* newEntry, - const size_t originalSize, - const char* originalBuffer, - const size_t characterIndex, - const int testCaseKey); - -protected: - LineMutations(std::default_random_engine& randomNumberGenerator) : MutationBase{randomNumberGenerator} {} + RadamsaLineMutatorBase() = default; + virtual ~RadamsaLineMutatorBase() = default; Line GetLineData( - const char* const buffer, - const size_t size, - const size_t lineIndex, - const size_t numberOfLinesAfterIndex); + const char* const buffer, + const size_t size, + const size_t lineIndex, + const size_t numberOfLinesAfterIndex) + { + constexpr size_t minimumSize{1u}; - bool IsBinarish( - const char* const buffer, - const size_t size); + if (size < minimumSize) + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; + + if (buffer == nullptr) + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + + const size_t totalNumberOfLines{ + GetNumberOfLinesAfterIndex( + buffer, + size, + 0u)}; + + if (lineIndex > totalNumberOfLines - 1u) + throw RuntimeException{"Line index exceeds the maximum number of lines", RuntimeException::UNEXPECTED_ERROR}; + + if (numberOfLinesAfterIndex > totalNumberOfLines) + throw RuntimeException{"Number of lines after index exceeds the maximum number of lines", RuntimeException::UNEXPECTED_ERROR}; + + const size_t lineOffset{totalNumberOfLines - numberOfLinesAfterIndex}; + + constexpr size_t lower{0u}; + const size_t upper{totalNumberOfLines - 1u}; + const size_t maximumLineIndex{ + std::clamp( + lineIndex + lineOffset, + lower, + upper)}; + + Line lineData; + + for(size_t it{0u}, reverseLineIndex{maximumLineIndex}; it < size; ++it) + { + if(reverseLineIndex == 0u) + { + if(!lineData.IsValid) + { + lineData.StartIndex = it; + lineData.IsValid = true; + } + + ++lineData.Size; + + if(buffer[it] == '\n') + break; + } + else + { + if(buffer[it] == '\n') + --reverseLineIndex; + } + } + + return lineData; + } size_t GetNumberOfLinesAfterIndex( - const char* const buffer, - const size_t size, - const size_t index); + const char* const buffer, + const size_t size, + const size_t index) + { + constexpr size_t minimumSize{1u}; - size_t GetRandomLogValue(const size_t maximumValue); + if (size < minimumSize) + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; - size_t GetRandomN_Bit(const size_t n); + if (index > size - 1u) + throw RuntimeException{"Index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; -private: - // Experimental and to be implemented in the next release cycle. + if (buffer == nullptr) + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; - void PermuteLine( - StorageEntry* newEntry, - const size_t originalSize, - const char* originalBuffer, - const size_t characterIndex, - const int testCaseKey); + size_t numberOfLines{0u}; - bool Rad_LineInsElsewhere(const size_t index); + for(size_t it{index}; it < size; ++it) + if(buffer[it] == '\n') + ++numberOfLines; - bool Rad_LineReplaceElsewhere(const size_t index); + return numberOfLines; + } + + + size_t GetRandomRepetitionLength(VmfRand* rand) noexcept + { + constexpr size_t MINIMUM_UPPER_LIMIT{0x2u}; + constexpr size_t MAXIMUM_UPPER_LIMIT{0x20000u}; + + size_t randomStop{rand->randBetween(0u, MINIMUM_UPPER_LIMIT)}; + size_t randomUpperLimit{MINIMUM_UPPER_LIMIT}; + + while(randomStop != 0u) + { + if(randomUpperLimit == MAXIMUM_UPPER_LIMIT) + break; + + randomUpperLimit <<= 1u; + randomStop = rand->randBetween(0u, MINIMUM_UPPER_LIMIT); + } + + return rand->randBetween(0u, randomUpperLimit) + 1u; // We add one to the return value in order to account for the case where the random upper value is zero. + } + + bool IsBinarish( + const char* const buffer, + const size_t size) +{ + constexpr size_t minimumSize{1u}; + + if (size < minimumSize) + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; + + if (buffer == nullptr) + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + + constexpr size_t binarishPeekSize{8u}; + + for(size_t it{0}; it < binarishPeekSize; ++it) + { + // Peek into the data and return true if it contains UTF-8 or \0. + + if(it == size) + break; + + if(buffer[it] == '\0') + return true; + + if((buffer[it] & (std::numeric_limits::max() + 0x01)) != 0u) + return true; + } + + return false; +} + + size_t GetRandomLogValue(const size_t maximumValue, VmfRand* rand) + { + constexpr size_t minimumValue{2u}; + + if(maximumValue <= minimumValue) + return 0u; + + return GetRandomN_Bit( + rand->randBetween(0u, maximumValue - minimumValue) + minimumValue, + rand); + } + + size_t GetRandomN_Bit(const size_t n, VmfRand* rand) + { + const size_t highValue{(n - 1u) << 1u}; + const size_t randomValue{rand->randBetween(0u, highValue)}; + const size_t nBitValue{randomValue | highValue}; + + return nBitValue; + } + + void PermuteLine() + { + //TODO + } }; } \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaMutatorBase.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaMutatorBase.hpp new file mode 100644 index 0000000..5dd2599 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaMutatorBase.hpp @@ -0,0 +1,45 @@ +/* ============================================================================= + * Vader Modular Fuzzer + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-3.0-or-later + * ===========================================================================*/ +#pragma once + +// C++ Includes +#include +#include +#include +#include "VmfRand.hpp" + +namespace vmf +{ +class RadamsaMutatorBase +{ +public: + // universal helper functions go here +}; +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaPermuteByteMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaPermuteByteMutator.cpp index c6f3493..b90085d 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaPermuteByteMutator.cpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaPermuteByteMutator.cpp @@ -66,7 +66,7 @@ void RadamsaPermuteByteMutator::init(ConfigInterface& config) */ RadamsaPermuteByteMutator::RadamsaPermuteByteMutator(std::string name) : MutatorModule(name) { - rand.randInit(); + // rand->randInit(); } /** @@ -129,7 +129,7 @@ void RadamsaPermuteByteMutator::mutateTestCase(StorageModule& storage, StorageEn const size_t maximumRandomIndexValue{originalSize - minimumSeedIndex}; const size_t randomIndexToSwap{ std::clamp( - rand.randBetween( + rand->randBetween( lower, maximumRandomIndexValue) + minimumSeedIndex, lower, diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaPermuteByteMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaPermuteByteMutator.hpp index 03714a6..695fcf7 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaPermuteByteMutator.hpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaPermuteByteMutator.hpp @@ -31,7 +31,7 @@ #include "MutatorModule.hpp" #include "StorageEntry.hpp" #include "RuntimeException.hpp" -#include "mutationBase.hpp" +#include "RadamsaByteMutatorBase.hpp" #include "VmfRand.hpp" namespace vmf @@ -39,7 +39,7 @@ namespace vmf /** * */ -class RadamsaPermuteByteMutator: public MutatorModule, public MutationBase +class RadamsaPermuteByteMutator: public MutatorModule, public RadamsaByteMutatorBase { public: @@ -52,6 +52,6 @@ class RadamsaPermuteByteMutator: public MutatorModule, public MutationBase virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); private: - VmfRand rand; + VmfRand* rand = VmfRand::getInstance(); }; } \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaRandomizeByteMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaRandomizeByteMutator.cpp index c230bd4..2f7f111 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaRandomizeByteMutator.cpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaRandomizeByteMutator.cpp @@ -66,7 +66,7 @@ void RadamsaRandomizeByteMutator::init(ConfigInterface& config) */ RadamsaRandomizeByteMutator::RadamsaRandomizeByteMutator(std::string name) : MutatorModule(name) { - rand.randInit(); + // rand->randInit(); } /** @@ -124,7 +124,7 @@ void RadamsaRandomizeByteMutator::mutateTestCase(StorageModule& storage, Storage const size_t maximumRandomIndexValue{originalSize - minimumSeedIndex}; const size_t randomIndexToRandomize{ std::clamp( - rand.randBetween( + rand->randBetween( lower, maximumRandomIndexValue) + minimumSeedIndex, lower, @@ -132,5 +132,5 @@ void RadamsaRandomizeByteMutator::mutateTestCase(StorageModule& storage, Storage ) }; - newBuffer[randomIndexToRandomize] = static_cast(rand.randBetween(0u, std::numeric_limits::max())); + newBuffer[randomIndexToRandomize] = static_cast(rand->randBetween(0u, std::numeric_limits::max())); } \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaRandomizeByteMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaRandomizeByteMutator.hpp index c8b64b4..bd84588 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaRandomizeByteMutator.hpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaRandomizeByteMutator.hpp @@ -31,7 +31,7 @@ #include "MutatorModule.hpp" #include "StorageEntry.hpp" #include "RuntimeException.hpp" -#include "mutationBase.hpp" +#include "RadamsaByteMutatorBase.hpp" #include "VmfRand.hpp" namespace vmf @@ -39,7 +39,7 @@ namespace vmf /** * */ -class RadamsaRandomizeByteMutator: public MutatorModule, public MutationBase +class RadamsaRandomizeByteMutator: public MutatorModule, public RadamsaByteMutatorBase { public: @@ -52,6 +52,6 @@ class RadamsaRandomizeByteMutator: public MutatorModule, public MutationBase virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); private: - VmfRand rand; + VmfRand* rand = VmfRand::getInstance(); }; } \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteMutator.cpp index 10868e5..0250340 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteMutator.cpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteMutator.cpp @@ -66,7 +66,7 @@ void RadamsaRepeatByteMutator::init(ConfigInterface& config) */ RadamsaRepeatByteMutator::RadamsaRepeatByteMutator(std::string name) : MutatorModule(name) { - rand.randInit(); + // rand->randInit(); } /** @@ -125,7 +125,7 @@ void RadamsaRepeatByteMutator::mutateTestCase(StorageModule& storage, StorageEnt const size_t maximumRandomIndexValue{originalSize - minimumSeedIndex}; const size_t randomByteRepetitionIndex{ std::clamp( - rand.randBetween( + rand->randBetween( lower, maximumRandomIndexValue) + minimumSeedIndex, lower, diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteMutator.hpp index 25b9b7f..25ffcdc 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteMutator.hpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteMutator.hpp @@ -31,7 +31,7 @@ #include "MutatorModule.hpp" #include "StorageEntry.hpp" #include "RuntimeException.hpp" -#include "mutationBase.hpp" +#include "RadamsaByteMutatorBase.hpp" #include "VmfRand.hpp" namespace vmf @@ -39,7 +39,7 @@ namespace vmf /** * */ -class RadamsaRepeatByteMutator: public MutatorModule, public MutationBase +class RadamsaRepeatByteMutator: public MutatorModule, public RadamsaByteMutatorBase { public: @@ -52,6 +52,6 @@ class RadamsaRepeatByteMutator: public MutatorModule, public MutationBase virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); private: - VmfRand rand; + VmfRand* rand = VmfRand::getInstance(); }; } \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatLineMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatLineMutator.cpp new file mode 100644 index 0000000..6cd9a37 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatLineMutator.cpp @@ -0,0 +1,167 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaRepeatLineMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaRepeatLineMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaRepeatLineMutator::build(std::string name) +{ + return new RadamsaRepeatLineMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaRepeatLineMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaRepeatLineMutator::RadamsaRepeatLineMutator object + * + * @param name The of the name module + */ +RadamsaRepeatLineMutator::RadamsaRepeatLineMutator(std::string name) : MutatorModule(name) +{ + // rand.randInit(); +} + +/** + * @brief Destroy the RadamsaRepeatLineMutator::RadamsaRepeatLineMutator object + * + */ +RadamsaRepeatLineMutator::~RadamsaRepeatLineMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaRepeatLineMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +void RadamsaRepeatLineMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + // Consume the original buffer by repeating a random line multiple times and appending a null-terminator to the end. + + constexpr size_t minimumSize{1u}; + const size_t minimumSeedIndex{0u}; + const size_t characterIndex{0u}; + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); + + if (originalSize < minimumSize) + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; + + if (characterIndex > originalSize - 1u) + throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + + if (originalBuffer == nullptr) + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + + const size_t numberOfLinesAfterIndex{ + GetNumberOfLinesAfterIndex( + originalBuffer, + originalSize, + characterIndex)}; + + // Select a random line to duplicate. + + constexpr size_t minimumRandomLineIndex{0u}; + const size_t maximumRandomLineIndex{numberOfLinesAfterIndex - 1u}; + + const size_t randomLineIndex{ + rand->randBetween( + minimumRandomLineIndex, + maximumRandomLineIndex)}; + + const Line lineData{ + GetLineData( + originalBuffer, + originalSize, + randomLineIndex, + numberOfLinesAfterIndex)}; + + const size_t numberOfRandomLineRepetitions{GetRandomRepetitionLength(this->rand)}; + + // The new buffer will be multiple lines larger than the original buffer; + // additionally, it will contain one additional byte since a null-terminator will be appended to the end. + + const size_t newBufferSize{originalSize + (lineData.Size * numberOfRandomLineRepetitions) + 1u}; + + // Allocate the new buffer and set it's elements to zero. + + char* newBuffer{newEntry->allocateBuffer(testCaseKey, newBufferSize)}; + memset(newBuffer, 0u, newBufferSize); + + // Copy data from the original buffer into the new buffer, but repeat the random line. + // The last element in the new buffer is skipped since it was implicitly set to zero during allocation. + + for(size_t sourceIndex{0u}, destinationIndex{0u}; sourceIndex < originalSize; ++sourceIndex) + { + if(sourceIndex == lineData.StartIndex) + { + for (size_t k{0u}; k < (numberOfRandomLineRepetitions + 1u); ++k) + { + memcpy(&newBuffer[destinationIndex], &originalBuffer[sourceIndex], lineData.Size); + + destinationIndex += lineData.Size; + } + + sourceIndex += lineData.Size; + } + + newBuffer[destinationIndex] = originalBuffer[sourceIndex]; + + ++destinationIndex; + } +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatLineMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatLineMutator.hpp new file mode 100644 index 0000000..c46f3eb --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatLineMutator.hpp @@ -0,0 +1,57 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "RadamsaLineMutatorBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaRepeatLineMutator: public MutatorModule, public RadamsaLineMutatorBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaRepeatLineMutator(std::string name); + virtual ~RadamsaRepeatLineMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand* rand = VmfRand::getInstance(); +}; +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaSwapLineMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaSwapLineMutator.cpp new file mode 100644 index 0000000..110fdc8 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaSwapLineMutator.cpp @@ -0,0 +1,207 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaSwapLineMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaSwapLineMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaSwapLineMutator::build(std::string name) +{ + return new RadamsaSwapLineMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaSwapLineMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaSwapLineMutator::RadamsaSwapLineMutator object + * + * @param name The of the name module + */ +RadamsaSwapLineMutator::RadamsaSwapLineMutator(std::string name) : MutatorModule(name) +{ + // rand.randInit(); +} + +/** + * @brief Destroy the RadamsaSwapLineMutator::RadamsaSwapLineMutator object + * + */ +RadamsaSwapLineMutator::~RadamsaSwapLineMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaSwapLineMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +void RadamsaSwapLineMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + // Consume the original buffer by copying a line to a random location and appending a null-terminator to the end. + + constexpr size_t minimumSize{1u}; + const size_t minimumSeedIndex{0u}; + const size_t characterIndex{0u}; + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); + + if (originalSize < minimumSize) + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; + + if (characterIndex > originalSize - 1u) + throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + + if (originalBuffer == nullptr) + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + + const size_t numberOfLinesAfterIndex{ + GetNumberOfLinesAfterIndex( + originalBuffer, + originalSize, + characterIndex)}; + + if (numberOfLinesAfterIndex < 2) { + throw RuntimeException{"The buffer's minimum number of lines must be greater than or equal to 2", RuntimeException::USAGE_ERROR}; + } + + // Select random line to copy from/to. + + const size_t minimumRandomLineOffset{0u}; + + const size_t firstRandomLineIndex{ + rand->randBetween( + minimumRandomLineOffset, + numberOfLinesAfterIndex - 1u)}; + + const size_t totalNumberOfLines{ + GetNumberOfLinesAfterIndex( + originalBuffer, + originalSize, + 0u)}; + + constexpr size_t lower{0u}; + const size_t upper{totalNumberOfLines - 1u}; + const size_t secondRandomLineIndex{ + std::clamp( + firstRandomLineIndex + 1u, + lower, + upper)}; + + const Line firstRandomLineData{ + GetLineData( + originalBuffer, + originalSize, + firstRandomLineIndex, + numberOfLinesAfterIndex)}; + + const Line secondRandomLineData{ + GetLineData( + originalBuffer, + originalSize, + secondRandomLineIndex, + numberOfLinesAfterIndex)}; + + // The new buffer will be one line larger than the original buffer; + // additionally, it will contain one additional byte since a null-terminator will be appended to the end. + + const size_t newBufferSize{originalSize + 1u}; + + // Allocate the new buffer and set it's elements to zero. + + char* newBuffer{newEntry->allocateBuffer(testCaseKey, newBufferSize)}; + memset(newBuffer, 0u, newBufferSize); + + // Copy data from the original buffer into the new buffer, but duplicate the random line. + // The last element in the new buffer is skipped since it was implicitly set to zero during allocation. + + { + // Copy all of the elements including the line that is to be duplicated. + + const size_t numberOfBytes{originalSize}; + + char* destination{newBuffer}; + const char* source{originalBuffer}; + + memcpy(destination, source, numberOfBytes); + } + + { + // Duplicate the line. + + const size_t numberOfBytes{secondRandomLineData.Size}; + + char* destination{newBuffer + firstRandomLineData.StartIndex}; + const char* source{originalBuffer + secondRandomLineData.StartIndex}; + + memcpy(destination, source, numberOfBytes); + } + + { + // Copy all of the elements after the line that was duplicated. + + const size_t numberOfBytes{firstRandomLineData.Size}; + + char* destination{ + (firstRandomLineData == secondRandomLineData) ? + (newBuffer + firstRandomLineData.StartIndex) : + (newBuffer + firstRandomLineData.StartIndex + secondRandomLineData.Size)}; + + const char* source{originalBuffer + firstRandomLineData.StartIndex}; + + memcpy(destination, source, numberOfBytes); + } +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaSwapLineMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaSwapLineMutator.hpp new file mode 100644 index 0000000..6c15430 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaSwapLineMutator.hpp @@ -0,0 +1,57 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "RadamsaLineMutatorBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaSwapLineMutator: public MutatorModule, public RadamsaLineMutatorBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaSwapLineMutator(std::string name); + virtual ~RadamsaSwapLineMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand* rand = VmfRand::getInstance(); +}; +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/byteMutations.cpp b/Radamsa/vmf/src/modules/common/mutator/byteMutations.cpp deleted file mode 100644 index 885730d..0000000 --- a/Radamsa/vmf/src/modules/common/mutator/byteMutations.cpp +++ /dev/null @@ -1,476 +0,0 @@ -/* ============================================================================= - * Vader Modular Fuzzer - * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. - * - * - * Effort sponsored by the U.S. Government under Other Transaction number - * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government - * is authorized to reproduce and distribute reprints for Governmental purposes - * notwithstanding any copyright notation thereon. - * - * The views and conclusions contained herein are those of the authors and - * should not be interpreted as necessarily representing the official policies - * or endorsements, either expressed or implied, of the U.S. Government. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * @license GPL-3.0-or-later - * ===========================================================================*/ -/***** - * The following includes code copied from the LibAFL_Legacy repository. - * - * american fuzzy lop++ - fuzzer header - * ------------------------------------ - * Originally written by Michal Zalewski - * Now maintained by Marc Heuse , - * Heiko Eißfeldt , - * Andrea Fioraldi , - * Dominik Maier - * Copyright 2016, 2017 Google Inc. All rights reserved. - * Copyright 2019-2020 AFLplusplus Project. All rights reserved. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * http://www.apache.org/licenses/LICENSE-2.0 - * This is the Library based on AFL++ which can be used to build - * customized fuzzers for a specific target while taking advantage of - * a lot of features that AFL++ already provides. - */ - -#include "byteMutations.hpp" - -void vmf::radamsa::mutations::ByteMutations::DropByte( - StorageEntry* newEntry, - const size_t originalSize, - const char* originalBuffer, - const size_t minimumSeedIndex, - const int testCaseKey) -{ - // Consume the original buffer by dropping a byte and appending a null-terminator to the end. - - constexpr size_t minimumSize{1u}; - - if (originalSize < minimumSize) - throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; - - if (minimumSeedIndex > originalSize - 1u) - throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; - - if (originalBuffer == nullptr) - throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; - - // The new buffer will contain one less byte, but a null-terminator will be appended to the end; therefore, the sizes will be equal. - - const size_t newBufferSize{originalSize}; - - // Allocate the new buffer and set it's elements to zero. - - char* newBuffer{newEntry->allocateBuffer(testCaseKey, newBufferSize)}; - memset(newBuffer, 0u, newBufferSize); - - // Select a random byte to drop from the original buffer. - - const size_t lower{0u}; - const size_t upper{originalSize - 1u}; - const size_t maximumRandomIndexValue{originalSize - minimumSeedIndex}; - const size_t randomIndexToDrop{ - std::clamp( - GetRandomValueWithinBounds( - lower, - maximumRandomIndexValue) + minimumSeedIndex, - lower, - upper)}; - - // Copy data from the original buffer into the new buffer, but exclude the random byte. - // The last element in the new buffer is skipped since it was implicitly set to zero during allocation. - - for (size_t sourceIndex{0u}, destinationIndex{0u}; sourceIndex < originalSize; ++sourceIndex) - { - if (sourceIndex != randomIndexToDrop) - { - newBuffer[destinationIndex] = originalBuffer[sourceIndex]; - - ++destinationIndex; - } - } -} - -void vmf::radamsa::mutations::ByteMutations::FlipByte( - StorageEntry* newEntry, - const size_t originalSize, - const char* originalBuffer, - const size_t minimumSeedIndex, - const int testCaseKey) -{ - // Consume the original buffer by flipping a byte and appending a null-terminator to the end. - - constexpr size_t minimumSize{1u}; - - if (originalSize < minimumSize) - throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; - - if (minimumSeedIndex > originalSize - 1u) - throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; - - if (originalBuffer == nullptr) - throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; - - // The new buffer size will contain one additional element since we are appending a null-terminator to the end. - - const size_t newBufferSize{originalSize + 1u}; - - // Allocate the new buffer, set it's elements to those of the original buffer, and append a null-terminator to the end. - - char* newBuffer{newEntry->allocateBuffer(testCaseKey, static_cast(newBufferSize))}; - memset(newBuffer, 0u, newBufferSize); - memcpy(newBuffer, originalBuffer, originalSize); - - // Select a random byte to drop from the original buffer. - - const size_t lower{0u}; - const size_t upper{originalSize - 1u}; - const size_t maximumRandomIndexValue{originalSize - minimumSeedIndex}; - const size_t randomIndexToFlip{ - std::clamp( - GetRandomValueWithinBounds( - lower, - maximumRandomIndexValue) + minimumSeedIndex, - lower, - upper)}; - - // Select a random bit to flip from the random byte. - // When computing the random bit shift, - // we add 1 so that a maximum number of 8 bit shift operations can be performed against a char containing the value 0x01. - - const size_t randomBitShift{GetRandomValueWithinBounds(0u, std::numeric_limits::digits + 1u)}; - const char randomMaskedBit{static_cast(0x01u << randomBitShift)}; - - // Flip the random byte by performing an XOR operation with a random masked bit. - - newBuffer[randomIndexToFlip] ^= randomMaskedBit; -} - -void vmf::radamsa::mutations::ByteMutations::InsertByte( - StorageEntry* newEntry, - const size_t originalSize, - const char* originalBuffer, - const size_t minimumSeedIndex, - const int testCaseKey) -{ - // Consume the original buffer by inserting a byte and appending a null-terminator to the end. - - constexpr size_t minimumSize{1u}; - - if (originalSize < minimumSize) - throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; - - if (minimumSeedIndex > originalSize - 1u) - throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; - - if (originalBuffer == nullptr) - throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; - - // The new buffer size will contain two additional elements since we are inserting a random byte and appending a null-terminator to the end. - - const size_t newBufferSize{originalSize + 2u}; - - // Allocate the new buffer and set it's elements to zero. - - char* newBuffer{newEntry->allocateBuffer(testCaseKey, static_cast(newBufferSize))}; - memset(newBuffer, 0u, newBufferSize); - - // Select a random index from which the new byte will be inserted. - - const size_t lower{0u}; - const size_t upper{originalSize - 1u}; - const size_t maximumRandomIndexValue{originalSize - minimumSeedIndex}; - const size_t randomInsertionIndex{ - std::clamp( - GetRandomValueWithinBounds( - lower, - maximumRandomIndexValue) + minimumSeedIndex, - lower, - upper)}; - - // Copy data from the original buffer into the new buffer, but insert a random byte. - // The last element in the new buffer is skipped since it was implicitly set to zero during allocation. - - for (size_t sourceIndex{0u}, destinationIndex{0u}; sourceIndex < originalSize; ++sourceIndex) - { - newBuffer[destinationIndex] = originalBuffer[sourceIndex]; - - if (sourceIndex == randomInsertionIndex) - newBuffer[++destinationIndex] = static_cast(GetRandomValueWithinBounds(0u, std::numeric_limits::max())); - - ++destinationIndex; - } -} - -void vmf::radamsa::mutations::ByteMutations::RepeatByte( - StorageEntry* newEntry, - const size_t originalSize, - const char* originalBuffer, - const size_t minimumSeedIndex, - const int testCaseKey) -{ - // Consume the original buffer by repeating a byte a random number of times and appending a null-terminator to the end. - - constexpr size_t minimumSize{1u}; - - if (originalSize < minimumSize) - throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; - - if (minimumSeedIndex > originalSize - 1u) - throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; - - if (originalBuffer == nullptr) - throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; - - // The new buffer size will contain a random number of additional elements since we are repeating a random byte. - // Furthermore, it will contain one more element since we are appending a null-terminator to the end. - - const size_t numberOfRandomByteRepetitions{GetRandomByteRepetitionLength()}; - const size_t newBufferSize{originalSize + numberOfRandomByteRepetitions + 1u}; - - // Allocate the new buffer and set it's elements to zero. - - char* newBuffer{newEntry->allocateBuffer(testCaseKey, static_cast(newBufferSize))}; - memset(newBuffer, 0u, newBufferSize); - - // Select a random index from which the new bytes will be repeated. - - const size_t lower{0u}; - const size_t upper{originalSize - 1u}; - const size_t maximumRandomIndexValue{originalSize - minimumSeedIndex}; - const size_t randomByteRepetitionIndex{ - std::clamp( - GetRandomValueWithinBounds( - lower, - maximumRandomIndexValue) + minimumSeedIndex, - lower, - upper)}; - - // Copy data from the original buffer into the new buffer, but repeat the target byte. - // The last element in the new buffer is skipped since it was implicitly set to zero during allocation. - - for (size_t sourceIndex{0u}, destinationIndex{0u}; sourceIndex < originalSize; ++sourceIndex) - { - if (sourceIndex == randomByteRepetitionIndex) - { - memset(&newBuffer[destinationIndex], originalBuffer[sourceIndex], numberOfRandomByteRepetitions + 1u); - - ++destinationIndex += numberOfRandomByteRepetitions; - } - else - { - newBuffer[destinationIndex] = originalBuffer[sourceIndex]; - - ++destinationIndex; - } - } -} - -void vmf::radamsa::mutations::ByteMutations::PermuteByte( - StorageEntry* newEntry, - const size_t originalSize, - const char* originalBuffer, - const size_t minimumSeedIndex, - const int testCaseKey) -{ - // Consume the original buffer by rearranging a random number of bytes and appending a null-terminator to the end. - - constexpr size_t minimumSize{1u}; - - if (originalSize < minimumSize) - throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; - - if (minimumSeedIndex > originalSize - 1u) - throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; - - if (originalBuffer == nullptr) - throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; - - // The new buffer size will contain one additional element since we are appending a null-terminator to the end. - - const size_t newBufferSize{originalSize + 1u}; - - // Allocate the new buffer, set it's elements to those of the original buffer, and append a null-terminator to the end. - - char* newBuffer{newEntry->allocateBuffer(testCaseKey, static_cast(newBufferSize))}; - memset(newBuffer, 0u, newBufferSize); - memcpy(newBuffer, originalBuffer, originalSize); - - // Copy data from the original buffer into the new buffer, but swap random bytes. - // The last element in the new buffer is skipped since it was implicitly set to zero during allocation. - - for (size_t sourceIndex{minimumSeedIndex}; sourceIndex < originalSize; ++sourceIndex) - { - // Select a random index and swap the two bytes. - - const size_t lower{0u}; - const size_t upper{originalSize - 1u}; - const size_t maximumRandomIndexValue{originalSize - minimumSeedIndex}; - const size_t randomIndexToSwap{ - std::clamp( - GetRandomValueWithinBounds( - lower, - maximumRandomIndexValue) + minimumSeedIndex, - lower, - upper)}; - - const char sourceByte{newBuffer[sourceIndex]}; - const char swappedByte{newBuffer[randomIndexToSwap]}; - - newBuffer[sourceIndex] = swappedByte; - newBuffer[randomIndexToSwap] = sourceByte; - } -} - -void vmf::radamsa::mutations::ByteMutations::IncrementByte( - StorageEntry* newEntry, - const size_t originalSize, - const char* originalBuffer, - const size_t minimumSeedIndex, - const int testCaseKey) -{ - // Consume the original buffer by incrementing a random byte and appending a null-terminator to the end. - - constexpr size_t minimumSize{1u}; - - if (originalSize < minimumSize) - throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; - - if (minimumSeedIndex > originalSize - 1u) - throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; - - if (originalBuffer == nullptr) - throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; - - // The new buffer size will contain one additional element since we are appending a null-terminator to the end. - - const size_t newBufferSize{originalSize + 1u}; - - // Allocate the new buffer, set it's elements to those of the original buffer, and append a null-terminator to the end. - - char* newBuffer{newEntry->allocateBuffer(testCaseKey, static_cast(newBufferSize))}; - memset(newBuffer, 0u, newBufferSize); - memcpy(newBuffer, originalBuffer, originalSize); - - // Select a random byte to circularly increment. - - const size_t lower{0u}; - const size_t upper{originalSize - 1u}; - const size_t maximumRandomIndexValue{originalSize - minimumSeedIndex}; - const size_t randomIndexToIncrement{ - std::clamp( - GetRandomValueWithinBounds( - lower, - maximumRandomIndexValue) + minimumSeedIndex, - lower, - upper)}; - - newBuffer[randomIndexToIncrement] = static_cast((originalBuffer[randomIndexToIncrement] + 0x01u) % std::numeric_limits::max()); -} - -void vmf::radamsa::mutations::ByteMutations::DecrementByte( - StorageEntry* newEntry, - const size_t originalSize, - const char* originalBuffer, - const size_t minimumSeedIndex, - const int testCaseKey) -{ - // Consume the original buffer by decrementing a random byte and appending a null-terminator to the end. - - constexpr size_t minimumSize{1u}; - - if (originalSize < minimumSize) - throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; - - if (minimumSeedIndex > originalSize - 1u) - throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; - - if (originalBuffer == nullptr) - throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; - - // The new buffer size will contain one additional element since we are appending a null-terminator to the end. - - const size_t newBufferSize{originalSize + 1u}; - - // Allocate the new buffer, set it's elements to those of the original buffer, and append a null-terminator to the end. - - char* newBuffer{newEntry->allocateBuffer(testCaseKey, static_cast(newBufferSize))}; - memset(newBuffer, 0u, newBufferSize); - memcpy(newBuffer, originalBuffer, originalSize); - - // Select a random byte to circularly decrement. - - const size_t lower{0u}; - const size_t upper{originalSize - 1u}; - const size_t maximumRandomIndexValue{originalSize - minimumSeedIndex}; - const size_t randomIndexToDecrement{ - std::clamp( - GetRandomValueWithinBounds( - lower, - maximumRandomIndexValue) + minimumSeedIndex, - lower, - upper)}; - - newBuffer[randomIndexToDecrement] = static_cast((originalBuffer[randomIndexToDecrement] - 0x01u) % std::numeric_limits::max()); -} - -void vmf::radamsa::mutations::ByteMutations::RandomizeByte( - StorageEntry* newEntry, - const size_t originalSize, - const char* originalBuffer, - const size_t minimumSeedIndex, - const int testCaseKey) -{ - // Consume the original buffer by randomizing a random byte and appending a null-terminator to the end. - - constexpr size_t minimumSize{1u}; - - if (originalSize < minimumSize) - throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; - - if (minimumSeedIndex > originalSize - 1u) - throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; - - if (originalBuffer == nullptr) - throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; - - // The new buffer size will contain one additional element since we are appending a null-terminator to the end. - - const size_t newBufferSize{originalSize + 1u}; - - // Allocate the new buffer, set it's elements to those of the original buffer, and append a null-terminator to the end. - - char* newBuffer{newEntry->allocateBuffer(testCaseKey, static_cast(newBufferSize))}; - memset(newBuffer, 0u, newBufferSize); - memcpy(newBuffer, originalBuffer, originalSize); - - // Select a random byte to randomize - - const size_t lower{0u}; - const size_t upper{originalSize - 1u}; - const size_t maximumRandomIndexValue{originalSize - minimumSeedIndex}; - const size_t randomIndexToRandomize{ - std::clamp( - GetRandomValueWithinBounds( - lower, - maximumRandomIndexValue) + minimumSeedIndex, - lower, - upper)}; - - newBuffer[randomIndexToRandomize] = static_cast(GetRandomValueWithinBounds(0u, std::numeric_limits::max())); -} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/byteMutations.hpp b/Radamsa/vmf/src/modules/common/mutator/byteMutations.hpp deleted file mode 100644 index da2e501..0000000 --- a/Radamsa/vmf/src/modules/common/mutator/byteMutations.hpp +++ /dev/null @@ -1,141 +0,0 @@ -/* ============================================================================= - * Vader Modular Fuzzer - * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. - * - * - * Effort sponsored by the U.S. Government under Other Transaction number - * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government - * is authorized to reproduce and distribute reprints for Governmental purposes - * notwithstanding any copyright notation thereon. - * - * The views and conclusions contained herein are those of the authors and - * should not be interpreted as necessarily representing the official policies - * or endorsements, either expressed or implied, of the U.S. Government. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * @license GPL-3.0-or-later - * ===========================================================================*/ -#pragma once - -// VMF Includes - -#include "StorageEntry.hpp" -#include "RuntimeException.hpp" -#include "mutationBase.hpp" - - -namespace vmf::radamsa::mutations -{ -/** - * @brief This module is draws heavily upon the libAFL mutator.c - * - * Uses the specified AFL-style mutation algorithm to mutate the provided - * input. createTestCase is the main mutation method. - * - * See https://github.com/AFLplusplus/LibAFL-legacy/blob/dev/src/mutator.c - * - * The following includes code copied from the LibAFL_Legacy repository. - * - * american fuzzy lop++ - fuzzer header - * ------------------------------------ - * Originally written by Michal Zalewski - * Now maintained by Marc Heuse , - * Heiko Eißfeldt , - * Andrea Fioraldi , - * Dominik Maier - * Copyright 2016, 2017 Google Inc. All rights reserved. - * Copyright 2019-2020 AFLplusplus Project. All rights reserved. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * http://www.apache.org/licenses/LICENSE-2.0 - * This is the Library based on AFL++ which can be used to build - * customized fuzzers for a specific target while taking advantage of - * a lot of features that AFL++ already provides. - */ -class ByteMutations: public vmf::radamsa::mutations::MutationBase -{ -public: - ByteMutations() = delete; - virtual ~ByteMutations() = default; - - ByteMutations(const ByteMutations&) = delete; - ByteMutations(ByteMutations&&) = delete; - - ByteMutations& operator=(const ByteMutations&) = delete; - ByteMutations& operator=(ByteMutations&&) = delete; - - void DropByte( - StorageEntry* newEntry, - const size_t originalBufferSize, - const char* originalBuffer, - const size_t minimumSeedIndex, - const int testCaseKey); - - void FlipByte( - StorageEntry* newEntry, - const size_t originalBufferSize, - const char* originalBuffer, - const size_t minimumSeedIndex, - const int testCaseKey); - - void InsertByte( - StorageEntry* newEntry, - const size_t originalBufferSize, - const char* originalBuffer, - const size_t minimumSeedIndex, - const int testCaseKey); - - void RepeatByte( - StorageEntry* newEntry, - const size_t originalBufferSize, - const char* originalBuffer, - const size_t minimumSeedIndex, - const int testCaseKey); - - void PermuteByte( - StorageEntry* newEntry, - const size_t originalBufferSize, - const char* originalBuffer, - const size_t minimumSeedIndex, - const int testCaseKey); - - void IncrementByte( - StorageEntry* newEntry, - const size_t originalBufferSize, - const char* originalBuffer, - const size_t minimumSeedIndex, - const int testCaseKey); - - void DecrementByte( - StorageEntry* newEntry, - const size_t originalBufferSize, - const char* originalBuffer, - const size_t minimumSeedIndex, - const int testCaseKey); - - void RandomizeByte( - StorageEntry* newEntry, - const size_t originalBufferSize, - const char* originalBuffer, - const size_t minimumSeedIndex, - const int testCaseKey); - -protected: - ByteMutations(std::default_random_engine& randomNumberGenerator) : MutationBase{randomNumberGenerator} {} - -private: -}; -} diff --git a/Radamsa/vmf/src/modules/common/mutator/lineMutations.cpp b/Radamsa/vmf/src/modules/common/mutator/lineMutations.cpp deleted file mode 100644 index 1daa36e..0000000 --- a/Radamsa/vmf/src/modules/common/mutator/lineMutations.cpp +++ /dev/null @@ -1,930 +0,0 @@ -/* ============================================================================= - * Vader Modular Fuzzer - * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. - * - * - * Effort sponsored by the U.S. Government under Other Transaction number - * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government - * is authorized to reproduce and distribute reprints for Governmental purposes - * notwithstanding any copyright notation thereon. - * - * The views and conclusions contained herein are those of the authors and - * should not be interpreted as necessarily representing the official policies - * or endorsements, either expressed or implied, of the U.S. Government. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * @license GPL-3.0-or-later - * ===========================================================================*/ -/***** - * The following includes code copied from the LibAFL_Legacy repository. - * - * american fuzzy lop++ - fuzzer header - * ------------------------------------ - * Originally written by Michal Zalewski - * Now maintained by Marc Heuse , - * Heiko Eißfeldt , - * Andrea Fioraldi , - * Dominik Maier - * Copyright 2016, 2017 Google Inc. All rights reserved. - * Copyright 2019-2020 AFLplusplus Project. All rights reserved. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * http://www.apache.org/licenses/LICENSE-2.0 - * This is the Library based on AFL++ which can be used to build - * customized fuzzers for a specific target while taking advantage of - * a lot of features that AFL++ already provides. - */ - -// C/C++ Includes -#include - -// VMF Includes -#include "lineMutations.hpp" -#include "Logging.hpp" - -vmf::radamsa::mutations::LineMutations::Line vmf::radamsa::mutations::LineMutations::GetLineData( - const char* const buffer, - const size_t size, - const size_t lineIndex, - const size_t numberOfLinesAfterIndex) -{ - constexpr size_t minimumSize{1u}; - - if (size < minimumSize) - throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; - - if (buffer == nullptr) - throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; - - const size_t totalNumberOfLines{ - GetNumberOfLinesAfterIndex( - buffer, - size, - 0u)}; - - if (lineIndex > totalNumberOfLines - 1u) - throw RuntimeException{"Line index exceeds the maximum number of lines", RuntimeException::UNEXPECTED_ERROR}; - - if (numberOfLinesAfterIndex > totalNumberOfLines) - throw RuntimeException{"Number of lines after index exceeds the maximum number of lines", RuntimeException::UNEXPECTED_ERROR}; - - const size_t lineOffset{totalNumberOfLines - numberOfLinesAfterIndex}; - - constexpr size_t lower{0u}; - const size_t upper{totalNumberOfLines - 1u}; - const size_t maximumLineIndex{ - std::clamp( - lineIndex + lineOffset, - lower, - upper)}; - - Line lineData; - - for(size_t it{0u}, reverseLineIndex{maximumLineIndex}; it < size; ++it) - { - if(reverseLineIndex == 0u) - { - if(!lineData.IsValid) - { - lineData.StartIndex = it; - lineData.IsValid = true; - } - - ++lineData.Size; - - if(buffer[it] == '\n') - break; - } - else - { - if(buffer[it] == '\n') - --reverseLineIndex; - } - } - - return lineData; -} - -size_t vmf::radamsa::mutations::LineMutations::GetNumberOfLinesAfterIndex( - const char* const buffer, - const size_t size, - const size_t index) -{ - constexpr size_t minimumSize{1u}; - - if (size < minimumSize) - throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; - - if (index > size - 1u) - throw RuntimeException{"Index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; - - if (buffer == nullptr) - throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; - - size_t numberOfLines{0u}; - - for(size_t it{index}; it < size; ++it) - if(buffer[it] == '\n') - ++numberOfLines; - - return ++numberOfLines; -} - -bool vmf::radamsa::mutations::LineMutations::IsBinarish( - const char* const buffer, - const size_t size) -{ - constexpr size_t minimumSize{1u}; - - if (size < minimumSize) - throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; - - if (buffer == nullptr) - throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; - - constexpr size_t binarishPeekSize{8u}; - - for(size_t it{0}; it < binarishPeekSize; ++it) - { - // Peek into the data and return true if it contains UTF-8 or \0. - - if(it == size) - break; - - if(buffer[it] == '\0') - return true; - - if((buffer[it] & (std::numeric_limits::max() + 0x01)) != 0u) - return true; - } - - return false; -} - -void vmf::radamsa::mutations::LineMutations::DeleteLine( - StorageEntry* newEntry, - const size_t originalSize, - const char* originalBuffer, - const size_t characterIndex, - const int testCaseKey) -{ - // Consume the original buffer by deleting a line from it and appending a null-terminator to the end. - - constexpr size_t minimumSize{1u}; - - if (originalSize < minimumSize) - throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; - - if (characterIndex > originalSize - 1u) - throw RuntimeException{"Character index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; - - if (originalBuffer == nullptr) - throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; - - if (IsBinarish(originalBuffer, originalSize)) - { - // The new buffer will contain one additional byte since a null-terminator will be appended to the end. - - const size_t newBufferSize{originalSize + 1u}; - - // Allocate the new buffer, set it's elements to those of the original buffer, and append a null-terminator to the end. - - char* newBuffer{newEntry->allocateBuffer(testCaseKey, static_cast(newBufferSize))}; - memset(newBuffer, 0u, newBufferSize); - memcpy(newBuffer, originalBuffer, originalSize); - } - else - { - const size_t numberOfLinesAfterIndex{ - GetNumberOfLinesAfterIndex( - originalBuffer, - originalSize, - characterIndex)}; - - // Select a random line to delete. - - constexpr size_t minimumRandomLineIndex{0u}; - const size_t maximumRandomLineIndex{numberOfLinesAfterIndex - 1u}; - - const size_t randomLineIndex{ - GetRandomValueWithinBounds( - minimumRandomLineIndex, - maximumRandomLineIndex)}; - - const Line lineData{ - GetLineData( - originalBuffer, - originalSize, - randomLineIndex, - numberOfLinesAfterIndex)}; - - // The new buffer will be one line smaller than the original buffer; - // additionally, it will contain one additional byte since a null-terminator will be appended to the end. - - const size_t newBufferSize{originalSize - lineData.Size + 1u}; - - // Allocate the new buffer and set it's elements to zero. - - char* newBuffer{newEntry->allocateBuffer(testCaseKey, newBufferSize)}; - memset(newBuffer, 0u, newBufferSize); - - // Copy data from the original buffer into the new buffer, but skip the elements in the random line that is to be deleted. - // The last element in the new buffer is skipped since it was implicitly set to zero during allocation. - - for(size_t sourceIndex{0u}, destinationIndex{0u}; sourceIndex < originalSize; ++sourceIndex) - { - const size_t lineStartIndex{lineData.StartIndex}; - const size_t lineEndIndex{lineStartIndex + lineData.Size}; - - if(sourceIndex < lineStartIndex || sourceIndex >= lineEndIndex) - { - newBuffer[destinationIndex] = originalBuffer[sourceIndex]; - ++destinationIndex; - } - } - } -} - -void vmf::radamsa::mutations::LineMutations::DeleteSequentialLines( - StorageEntry* newEntry, - const size_t originalSize, - const char* originalBuffer, - const size_t characterIndex, - const int testCaseKey) -{ - // Consume the original buffer by deleting sequential lines from it and appending a null-terminator to the end. - - constexpr size_t minimumSize{1u}; - - if (originalSize < minimumSize) - throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; - - if (characterIndex > originalSize - 1u) - throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; - - if (originalBuffer == nullptr) - throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; - - if (IsBinarish(originalBuffer, originalSize)) - { - // The new buffer will contain one additional byte since a null-terminator will be appended to the end. - - const size_t newBufferSize{originalSize + 1u}; - - // Allocate the new buffer, set it's elements to those of the original buffer, and append a null-terminator to the end. - - char* newBuffer{newEntry->allocateBuffer(testCaseKey, static_cast(newBufferSize))}; - memset(newBuffer, 0u, newBufferSize); - memcpy(newBuffer, originalBuffer, originalSize); - } - else - { - const size_t numberOfLinesAfterIndex{ - GetNumberOfLinesAfterIndex( - originalBuffer, - originalSize, - characterIndex)}; - - // Select a random line to delete. - - const size_t minimumRandomLineOffset{0u}; - - const size_t randomLineIndexStart{ - GetRandomValueWithinBounds( - minimumRandomLineOffset, - numberOfLinesAfterIndex - 1u)}; - - const size_t randomLineIndexEnd{ - GetRandomValueWithinBounds( - minimumRandomLineOffset, - (numberOfLinesAfterIndex - 1u) - randomLineIndexStart) + randomLineIndexStart}; - - const Line startLineData{ - GetLineData( - originalBuffer, - originalSize, - randomLineIndexStart, - numberOfLinesAfterIndex)}; - - const Line endLineData{ - GetLineData( - originalBuffer, - originalSize, - randomLineIndexEnd, - numberOfLinesAfterIndex)}; - - // The new buffer will be multiple lines smaller than the original buffer; - // additionally, it will contain one additional byte since a null-terminator will be appended to the end. - - const size_t newBufferSize{(originalSize - ((endLineData.StartIndex + endLineData.Size) - startLineData.StartIndex)) + 1u}; - - // Allocate the new buffer and set it's elements to zero. - - char* newBuffer{newEntry->allocateBuffer(testCaseKey, newBufferSize)}; - memset(newBuffer, 0u, newBufferSize); - - // Copy data from the original buffer into the new buffer, but skip the elements in the random lines that are to be deleted. - // The last element in the new buffer is skipped since it was implicitly set to zero during allocation. - - for(size_t sourceIndex{0u}, destinationIndex{0u}; sourceIndex < originalSize; ++sourceIndex) - { - const size_t lineStartIndex{startLineData.StartIndex}; - const size_t lineEndIndex{endLineData.StartIndex + endLineData.Size}; - - if(sourceIndex < lineStartIndex || sourceIndex >= lineEndIndex) - { - newBuffer[destinationIndex] = originalBuffer[sourceIndex]; - ++destinationIndex; - } - } - } -} - -void vmf::radamsa::mutations::LineMutations::DuplicateLine( - StorageEntry* newEntry, - const size_t originalSize, - const char* originalBuffer, - const size_t characterIndex, - const int testCaseKey) -{ - // Consume the original buffer by duplicating a line from it and appending a null-terminator to the end. - - constexpr size_t minimumSize{1u}; - - if (originalSize < minimumSize) - throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; - - if (characterIndex > originalSize - 1u) - throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; - - if (originalBuffer == nullptr) - throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; - - const size_t numberOfLinesAfterIndex{ - GetNumberOfLinesAfterIndex( - originalBuffer, - originalSize, - characterIndex)}; - - if (!IsBinarish(originalBuffer, originalSize)) - { - // The new buffer will contain one additional byte since a null-terminator will be appended to the end. - - const size_t newBufferSize{originalSize + 1u}; - - // Allocate the new buffer, set it's elements to those of the original buffer, and append a null-terminator to the end. - - char* newBuffer{newEntry->allocateBuffer(testCaseKey, static_cast(newBufferSize))}; - memset(newBuffer, 0u, newBufferSize); - memcpy(newBuffer, originalBuffer, originalSize); - } - else - { - // Select a random line to duplicate. - - constexpr size_t minimumRandomLineIndex{0u}; - const size_t maximumRandomLineIndex{numberOfLinesAfterIndex - 1u}; - - const size_t randomLineIndex{ - GetRandomValueWithinBounds( - minimumRandomLineIndex, - maximumRandomLineIndex)}; - - const Line lineData{ - GetLineData( - originalBuffer, - originalSize, - randomLineIndex, - numberOfLinesAfterIndex)}; - - // The new buffer will be one line larger than the original buffer; - // additionally, it will contain one additional byte since a null-terminator will be appended to the end. - - const size_t newBufferSize{originalSize + lineData.Size + 1u}; - - // Allocate the new buffer and set it's elements to zero. - - char* newBuffer{newEntry->allocateBuffer(testCaseKey, newBufferSize)}; - memset(newBuffer, 0u, newBufferSize); - - // Copy data from the original buffer into the new buffer, but duplicate the random line. - // The last element in the new buffer is skipped since it was implicitly set to zero during allocation. - - { - // Copy all of the elements including the line that is to be duplicated. - - const size_t numberOfBytes{lineData.StartIndex + lineData.Size}; - - char* destination{newBuffer}; - const char* source{originalBuffer}; - - memcpy(destination, source, numberOfBytes); - } - - { - // Duplicate the line. - - const size_t numberOfBytes{lineData.Size}; - - char* destination{newBuffer + lineData.StartIndex + lineData.Size}; - const char* source{originalBuffer + lineData.StartIndex}; - - memcpy(destination, source, numberOfBytes); - } - - { - // Copy all of the elements after the line that was duplicated. - - const size_t numberOfBytes{originalSize - (lineData.StartIndex + lineData.Size)}; - - char* destination{newBuffer + lineData.StartIndex + 2 * lineData.Size}; - const char* source{originalBuffer + lineData.StartIndex + lineData.Size}; - - memcpy(destination, source, numberOfBytes); - } - } -} - -void vmf::radamsa::mutations::LineMutations::CopyLineCloseBy( - StorageEntry* newEntry, - const size_t originalSize, - const char* originalBuffer, - const size_t characterIndex, - const int testCaseKey) -{ - // Consume the original buffer by copying a line to a random location and appending a null-terminator to the end. - - constexpr size_t minimumSize{1u}; - - if (originalSize < minimumSize) - throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; - - if (characterIndex > originalSize - 1u) - throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; - - if (originalBuffer == nullptr) - throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; - - const size_t numberOfLinesAfterIndex{ - GetNumberOfLinesAfterIndex( - originalBuffer, - originalSize, - characterIndex)}; - - if (!IsBinarish(originalBuffer, originalSize)) - { - // The new buffer will contain one additional byte since a null-terminator will be appended to the end. - - const size_t newBufferSize{originalSize + 1u}; - - // Allocate the new buffer, set it's elements to those of the original buffer, and append a null-terminator to the end. - - char* newBuffer{newEntry->allocateBuffer(testCaseKey, static_cast(newBufferSize))}; - memset(newBuffer, 0u, newBufferSize); - memcpy(newBuffer, originalBuffer, originalSize); - } - else - { - // Select random line to copy from/to. - - const size_t minimumRandomLineOffset{0u}; - - const size_t randomLineIndexSource{ - GetRandomValueWithinBounds( - minimumRandomLineOffset, - numberOfLinesAfterIndex - 1u)}; - - const size_t randomLineIndexDestination{ - GetRandomValueWithinBounds( - minimumRandomLineOffset, - numberOfLinesAfterIndex - 1u)}; - - const Line lineDataSource{ - GetLineData( - originalBuffer, - originalSize, - randomLineIndexSource, - numberOfLinesAfterIndex)}; - - const Line lineDataDestination{ - GetLineData( - originalBuffer, - originalSize, - randomLineIndexDestination, - numberOfLinesAfterIndex)}; - - // The new buffer will be one line larger than the original buffer; - // additionally, it will contain one additional byte since a null-terminator will be appended to the end. - - const size_t newBufferSize{originalSize + lineDataSource.Size + 1u}; - - // Allocate the new buffer and set it's elements to zero. - - char* newBuffer{newEntry->allocateBuffer(testCaseKey, newBufferSize)}; - memset(newBuffer, 0u, newBufferSize); - - // Copy data from the original buffer into the new buffer, but copy the random line. - // The last element in the new buffer is skipped since it was implicitly set to zero during allocation. - - for(size_t sourceIndex{0u}, destinationIndex{0u}; sourceIndex < originalSize; ++sourceIndex) - { - if(sourceIndex == lineDataDestination.StartIndex) - { - memcpy(&newBuffer[destinationIndex], &originalBuffer[lineDataSource.StartIndex], lineDataSource.Size); - - destinationIndex += lineDataSource.Size; - } - - newBuffer[destinationIndex] = originalBuffer[sourceIndex]; - - ++destinationIndex; - } - } -} - -void vmf::radamsa::mutations::LineMutations::RepeatLine( - StorageEntry* newEntry, - const size_t originalSize, - const char* originalBuffer, - const size_t characterIndex, - const int testCaseKey) -{ - // Consume the original buffer by repeating a random line multiple times and appending a null-terminator to the end. - - constexpr size_t minimumSize{1u}; - - if (originalSize < minimumSize) - throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; - - if (characterIndex > originalSize - 1u) - throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; - - if (originalBuffer == nullptr) - throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; - - const size_t numberOfLinesAfterIndex{ - GetNumberOfLinesAfterIndex( - originalBuffer, - originalSize, - characterIndex)}; - - if (!IsBinarish(originalBuffer, originalSize)) - { - // The new buffer will contain one additional byte since a null-terminator will be appended to the end. - - const size_t newBufferSize{originalSize + 1u}; - - // Allocate the new buffer, set it's elements to those of the original buffer, and append a null-terminator to the end. - - char* newBuffer{newEntry->allocateBuffer(testCaseKey, static_cast(newBufferSize))}; - memset(newBuffer, 0u, newBufferSize); - memcpy(newBuffer, originalBuffer, originalSize); - } - else - { - // Select a random line to duplicate. - - constexpr size_t minimumRandomLineIndex{0u}; - const size_t maximumRandomLineIndex{numberOfLinesAfterIndex - 1u}; - - const size_t randomLineIndex{ - GetRandomValueWithinBounds( - minimumRandomLineIndex, - maximumRandomLineIndex)}; - - const Line lineData{ - GetLineData( - originalBuffer, - originalSize, - randomLineIndex, - numberOfLinesAfterIndex)}; - - const size_t numberOfRandomLineRepetitions{GetRandomByteRepetitionLength()}; - - // The new buffer will be multiple lines larger than the original buffer; - // additionally, it will contain one additional byte since a null-terminator will be appended to the end. - - const size_t newBufferSize{originalSize + (lineData.Size * numberOfRandomLineRepetitions) + 1u}; - - // Allocate the new buffer and set it's elements to zero. - - char* newBuffer{newEntry->allocateBuffer(testCaseKey, newBufferSize)}; - memset(newBuffer, 0u, newBufferSize); - - // Copy data from the original buffer into the new buffer, but repeat the random line. - // The last element in the new buffer is skipped since it was implicitly set to zero during allocation. - - for(size_t sourceIndex{0u}, destinationIndex{0u}; sourceIndex < originalSize; ++sourceIndex) - { - if(sourceIndex == lineData.StartIndex) - { - for (size_t k{0u}; k < (numberOfRandomLineRepetitions + 1u); ++k) - { - memcpy(&newBuffer[destinationIndex], &originalBuffer[sourceIndex], lineData.Size); - - destinationIndex += lineData.Size; - } - - sourceIndex += lineData.Size; - } - - newBuffer[destinationIndex] = originalBuffer[sourceIndex]; - - ++destinationIndex; - } - } -} - -void vmf::radamsa::mutations::LineMutations::SwapLine( - StorageEntry* newEntry, - const size_t originalSize, - const char* originalBuffer, - const size_t characterIndex, - const int testCaseKey) -{ - // Consume the original buffer by copying a line to a random location and appending a null-terminator to the end. - - constexpr size_t minimumSize{1u}; - - if (originalSize < minimumSize) - throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; - - if (characterIndex > originalSize - 1u) - throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; - - if (originalBuffer == nullptr) - throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; - - const size_t numberOfLinesAfterIndex{ - GetNumberOfLinesAfterIndex( - originalBuffer, - originalSize, - characterIndex)}; - - if (IsBinarish(originalBuffer, originalSize)) - { - // The new buffer will contain one additional byte since a null-terminator will be appended to the end. - - const size_t newBufferSize{originalSize + 1u}; - - // Allocate the new buffer, set it's elements to those of the original buffer, and append a null-terminator to the end. - - char* newBuffer{newEntry->allocateBuffer(testCaseKey, static_cast(newBufferSize))}; - memset(newBuffer, 0u, newBufferSize); - memcpy(newBuffer, originalBuffer, originalSize); - } - else - { - // Select random line to copy from/to. - - const size_t minimumRandomLineOffset{0u}; - - const size_t firstRandomLineIndex{ - GetRandomValueWithinBounds( - minimumRandomLineOffset, - numberOfLinesAfterIndex - 1u)}; - - const size_t totalNumberOfLines{ - GetNumberOfLinesAfterIndex( - originalBuffer, - originalSize, - 0u)}; - - - constexpr size_t lower{0u}; - const size_t upper{totalNumberOfLines - 1u}; - const size_t secondRandomLineIndex{ - std::clamp( - firstRandomLineIndex + 1u, - lower, - upper)}; - - const Line firstRandomLineData{ - GetLineData( - originalBuffer, - originalSize, - firstRandomLineIndex, - numberOfLinesAfterIndex)}; - - const Line secondRandomLineData{ - GetLineData( - originalBuffer, - originalSize, - secondRandomLineIndex, - numberOfLinesAfterIndex)}; - - // The new buffer will be one line larger than the original buffer; - // additionally, it will contain one additional byte since a null-terminator will be appended to the end. - - const size_t newBufferSize{originalSize + 1u}; - - // Allocate the new buffer and set it's elements to zero. - - char* newBuffer{newEntry->allocateBuffer(testCaseKey, newBufferSize)}; - memset(newBuffer, 0u, newBufferSize); - - // Copy data from the original buffer into the new buffer, but duplicate the random line. - // The last element in the new buffer is skipped since it was implicitly set to zero during allocation. - - { - // Copy all of the elements including the line that is to be duplicated. - - const size_t numberOfBytes{originalSize}; - - char* destination{newBuffer}; - const char* source{originalBuffer}; - - memcpy(destination, source, numberOfBytes); - } - - { - // Duplicate the line. - - const size_t numberOfBytes{secondRandomLineData.Size}; - - char* destination{newBuffer + firstRandomLineData.StartIndex}; - const char* source{originalBuffer + secondRandomLineData.StartIndex}; - - memcpy(destination, source, numberOfBytes); - } - - { - // Copy all of the elements after the line that was duplicated. - - const size_t numberOfBytes{firstRandomLineData.Size}; - - char* destination{ - (firstRandomLineData == secondRandomLineData) ? - (newBuffer + firstRandomLineData.StartIndex) : - (newBuffer + firstRandomLineData.StartIndex + secondRandomLineData.Size)}; - - const char* source{originalBuffer + firstRandomLineData.StartIndex}; - - memcpy(destination, source, numberOfBytes); - } - } -} - -size_t vmf::radamsa::mutations::LineMutations::GetRandomLogValue(const size_t maximumValue) -{ - constexpr size_t minimumValue{2u}; - - if(maximumValue <= minimumValue) - return 0u; - - return GetRandomN_Bit(GetRandomValueWithinBounds(0u, maximumValue - minimumValue) + minimumValue); -} - -size_t vmf::radamsa::mutations::LineMutations::GetRandomN_Bit(const size_t n) -{ - const size_t highValue{(n - 1u) << 1u}; - const size_t randomValue{GetRandomValueWithinBounds(0u, highValue)}; - const size_t nBitValue{randomValue | highValue}; - - return nBitValue; -} - -void vmf::radamsa::mutations::LineMutations::PermuteLine( - StorageEntry* newEntry, - const size_t originalSize, - const char* originalBuffer, - const size_t characterIndex, - const int testCaseKey) -{ - // Consume the original buffer by copying a line to a random location and appending a null-terminator to the end. - - constexpr size_t minimumSize{1u}; - - if (originalSize < minimumSize) - throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; - - if (characterIndex > originalSize - 1u) - throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; - - if (originalBuffer == nullptr) - throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; - - const size_t numberOfLinesAfterIndex{ - GetNumberOfLinesAfterIndex( - originalBuffer, - originalSize, - characterIndex)}; - - if (IsBinarish(originalBuffer, originalSize)) - { - // The new buffer will contain one additional byte since a null-terminator will be appended to the end. - - const size_t newBufferSize{originalSize + 1u}; - - // Allocate the new buffer, set it's elements to those of the original buffer, and append a null-terminator to the end. - - char* newBuffer{newEntry->allocateBuffer(testCaseKey, static_cast(newBufferSize))}; - memset(newBuffer, 0u, newBufferSize); - memcpy(newBuffer, originalBuffer, originalSize); - } - else - { - auto getLineData{ - [&](const char* const buffer, const size_t size, const size_t numberOfLinesAfterIndex) -> std::vector - { - std::vector lineData; - - lineData.reserve(numberOfLinesAfterIndex); - - for(size_t it{0u}; it < numberOfLinesAfterIndex; ++it) - { - lineData.emplace_back( - GetLineData( - buffer, - size, - it, - numberOfLinesAfterIndex)); - } - - return lineData; - }}; - - // Select random line to copy from/to. - - constexpr size_t minimumRandomLineOffset{0u}; - - const size_t randomStartLineIndex{ - (numberOfLinesAfterIndex <= 3u) ? - (GetRandomValueWithinBounds( - minimumRandomLineOffset, - numberOfLinesAfterIndex - 1u)) : - (GetRandomValueWithinBounds( - minimumRandomLineOffset, - numberOfLinesAfterIndex - 4u))}; // numlines - 3 - - const size_t firstNumberOfRandomLinePermutations{ - GetRandomValueWithinBounds( - minimumRandomLineOffset, - numberOfLinesAfterIndex - randomStartLineIndex - 1u) + 2u}; - - constexpr size_t maximumValue{10u}; - const size_t secondNumberOfRandomLinePermutations{GetRandomLogValue(maximumValue)}; - - constexpr size_t lhs{2u}; - const size_t totalNumberOfRandomLinePermutations{ - std::max( - lhs, - std::min( - firstNumberOfRandomLinePermutations, - secondNumberOfRandomLinePermutations))}; - - const std::vector lineData{ - getLineData( - originalBuffer, - originalSize, - numberOfLinesAfterIndex)}; - - auto lineList{ - LineList{ - originalBuffer, - lineData}}; - - for (size_t permutationLenght{totalNumberOfRandomLinePermutations}, startLineIndex{randomStartLineIndex}; permutationLenght != 1u; permutationLenght--, startLineIndex++) - { - const size_t randomLineIndex{GetRandomValueWithinBounds(0u, permutationLenght) + randomStartLineIndex}; - - std::swap(lineList.Data[randomStartLineIndex], lineList.Data[randomLineIndex]); - } - - // The new buffer will be one line larger than the original buffer; - // additionally, it will contain one additional byte since a null-terminator will be appended to the end. - - const size_t newBufferSize{lineList.Capacity + 1u}; - - // Allocate the new buffer and set it's elements to zero. - - char* newBuffer{newEntry->allocateBuffer(testCaseKey, newBufferSize)}; - memset(newBuffer, 0u, newBufferSize); - - for (size_t it{0u}, destinationIndex{0u}; it < lineList.NumberOfElements; ++it) - { - const size_t numberOfBytes{lineList.Data[it].Size}; - - const char* const source{lineList.Data[it].Data.get()}; - char* destination{&newBuffer[destinationIndex]}; - - memcpy(destination, source, numberOfBytes); - - destinationIndex += lineList.Data[it].Size; - std::cout << "\ntest!!!"; - } - } -} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp b/Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp deleted file mode 100644 index 7211cef..0000000 --- a/Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -// C++ Includes -#include -#include -#include -#include "VmfRand.hpp" - -namespace vmf -{ -class MutationBase -{ -public: - - static size_t GetRandomByteRepetitionLength(VmfRand& rand) noexcept - { - constexpr size_t MINIMUM_UPPER_LIMIT{0x2u}; - constexpr size_t MAXIMUM_UPPER_LIMIT{0x20000u}; - - size_t randomStop{rand.randBetween(0u, MINIMUM_UPPER_LIMIT)}; - size_t randomUpperLimit{MINIMUM_UPPER_LIMIT}; - - while(randomStop != 0u) - { - if(randomUpperLimit == MAXIMUM_UPPER_LIMIT) - break; - - randomUpperLimit <<= 1u; - randomStop = rand.randBetween(0u, MINIMUM_UPPER_LIMIT); - } - - return rand.randBetween(0u, randomUpperLimit) + 1u; // We add one to the return value in order to account for the case where the random upper value is zero. - } - -}; -} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/radamsaMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/radamsaMutator.cpp deleted file mode 100644 index a2c57cc..0000000 --- a/Radamsa/vmf/src/modules/common/mutator/radamsaMutator.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/* ============================================================================= - * Vader Modular Fuzzer - * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. - * - * - * Effort sponsored by the U.S. Government under Other Transaction number - * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government - * is authorized to reproduce and distribute reprints for Governmental purposes - * notwithstanding any copyright notation thereon. - * - * The views and conclusions contained herein are those of the authors and - * should not be interpreted as necessarily representing the official policies - * or endorsements, either expressed or implied, of the U.S. Government. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * @license GPL-3.0-or-later - * ===========================================================================*/ -/***** - * The following includes code copied from the LibAFL_Legacy repository. - * - * american fuzzy lop++ - fuzzer header - * ------------------------------------ - * Originally written by Michal Zalewski - * Now maintained by Marc Heuse , - * Heiko Eißfeldt , - * Andrea Fioraldi , - * Dominik Maier - * Copyright 2016, 2017 Google Inc. All rights reserved. - * Copyright 2019-2020 AFLplusplus Project. All rights reserved. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * http://www.apache.org/licenses/LICENSE-2.0 - * This is the Library based on AFL++ which can be used to build - * customized fuzzers for a specific target while taking advantage of - * a lot of features that AFL++ already provides. - */ - -// VMF Includes -#include "ModuleFactory.hpp" -#include "radamsaMutator.hpp" - -namespace vmf -{ -REGISTER_MODULE(vmf::modules::radamsa::RadamsaMutator); -} - -vmf::Module* vmf::modules::radamsa::RadamsaMutator::build(std::string name) { return new RadamsaMutator(name); } - -void vmf::modules::radamsa::RadamsaMutator::SetAlgorithmType(const AlgorithmType algorithmType) -{ - switch(algorithmType) - { - case AlgorithmType::ByteMutations_DropByte: - case AlgorithmType::ByteMutations_FlipByte: - case AlgorithmType::ByteMutations_InsertByte: - case AlgorithmType::ByteMutations_RepeatByte: - case AlgorithmType::ByteMutations_PermuteByte: - case AlgorithmType::ByteMutations_IncrementByte: - case AlgorithmType::ByteMutations_DecrementByte: - case AlgorithmType::ByteMutations_RandomizeByte: - case AlgorithmType::LineMutations_DeleteLine: - case AlgorithmType::LineMutations_DeleteSequentialLines: - case AlgorithmType::LineMutations_DuplicateLine: - case AlgorithmType::LineMutations_CopyLineCloseBy: - case AlgorithmType::LineMutations_RepeatLine: - case AlgorithmType::LineMutations_SwapLine: // Intentional Fallthrough - algorithmType_ = algorithmType; - - break; - case AlgorithmType::Unknown: - throw RuntimeException{ - "Attempted to set algorithm type to unknown value", - RuntimeException::USAGE_ERROR}; - default: - throw RuntimeException{ - "Invalid RadamsaMutator algorithm type", - RuntimeException::UNEXPECTED_ERROR}; - } -} - -void vmf::modules::radamsa::RadamsaMutator::registerStorageNeeds(StorageRegistry& registry) -{ - testCaseKey_ = registry.registerKey( - "TEST_CASE", - StorageRegistry::BUFFER, - StorageRegistry::READ_WRITE); - - normalTag_ = registry.registerTag( - "RAN_SUCCESSFULLY", - StorageRegistry::READ_ONLY); -} - -void vmf::modules::radamsa::RadamsaMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) -{ - if (baseEntry == nullptr) - throw RuntimeException("RadamsaMutator mutate called with null base entry", RuntimeException::OTHER); - - const size_t minimumSeedIndex{0u}; - const int size{baseEntry->getBufferSize(testCaseKey_)}; - const char* buffer{baseEntry->getBufferPointer(testCaseKey_)}; - - if(size <= 0) - throw RuntimeException("RadamsaMutator mutate called with zero sized buffer", RuntimeException::USAGE_ERROR); - - - - switch(algorithmType_) - { - case AlgorithmType::ByteMutations_DropByte: - DropByte(newEntry, size, buffer, minimumSeedIndex, testCaseKey_); - - break; - case AlgorithmType::ByteMutations_FlipByte: - FlipByte(newEntry, size, buffer, minimumSeedIndex, testCaseKey_); - - break; - case AlgorithmType::ByteMutations_InsertByte: - InsertByte(newEntry, size, buffer, minimumSeedIndex, testCaseKey_); - - break; - case AlgorithmType::ByteMutations_RepeatByte: - RepeatByte(newEntry, size, buffer, minimumSeedIndex, testCaseKey_); - - break; - case AlgorithmType::ByteMutations_PermuteByte: - PermuteByte(newEntry, size, buffer, minimumSeedIndex, testCaseKey_); - - break; - case AlgorithmType::ByteMutations_IncrementByte: - IncrementByte(newEntry, size, buffer, minimumSeedIndex, testCaseKey_); - - break; - case AlgorithmType::ByteMutations_DecrementByte: - DecrementByte(newEntry, size, buffer, minimumSeedIndex, testCaseKey_); - - break; - case AlgorithmType::ByteMutations_RandomizeByte: - RandomizeByte(newEntry, size, buffer, minimumSeedIndex, testCaseKey_); - - break; - case AlgorithmType::LineMutations_DeleteLine: - DeleteLine(newEntry, size, buffer, minimumSeedIndex, testCaseKey_); - - break; - case AlgorithmType::LineMutations_DeleteSequentialLines: - DeleteSequentialLines(newEntry, size, buffer, minimumSeedIndex, testCaseKey_); - - break; - case AlgorithmType::LineMutations_DuplicateLine: - DuplicateLine(newEntry, size, buffer, minimumSeedIndex, testCaseKey_); - - break; - case AlgorithmType::LineMutations_CopyLineCloseBy: - CopyLineCloseBy(newEntry, size, buffer, minimumSeedIndex, testCaseKey_); - - break; - case AlgorithmType::LineMutations_RepeatLine: - RepeatLine(newEntry, size, buffer, minimumSeedIndex, testCaseKey_); - - break; - case AlgorithmType::LineMutations_SwapLine: - SwapLine(newEntry, size, buffer, minimumSeedIndex, testCaseKey_); - - break; - default: - throw RuntimeException("Invalid RadamsaMutator algorithm type", RuntimeException::UNEXPECTED_ERROR); - - break; - } - - -} - -vmf::modules::radamsa::RadamsaMutator::AlgorithmType vmf::modules::radamsa::RadamsaMutator::stringToType(std::string type) -{ - if(type.compare("ByteMutations_DropByte") == 0) - return AlgorithmType::ByteMutations_DropByte; - else if(type.compare("ByteMutations_FlipByte") == 0) - return AlgorithmType::ByteMutations_FlipByte; - else if(type.compare("ByteMutations_InsertByte") == 0) - return AlgorithmType::ByteMutations_InsertByte; - else if(type.compare("ByteMutations_RepeatByte") == 0) - return AlgorithmType::ByteMutations_RepeatByte; - else if(type.compare("ByteMutations_PermuteByte") == 0) - return AlgorithmType::ByteMutations_PermuteByte; - else if(type.compare("ByteMutations_IncrementByte") == 0) - return AlgorithmType::ByteMutations_IncrementByte; - else if(type.compare("ByteMutations_DecrementByte") == 0) - return AlgorithmType::ByteMutations_DecrementByte; - else if(type.compare("ByteMutations_RandomizeByte") == 0) - return AlgorithmType::ByteMutations_RandomizeByte; - else if(type.compare("LineMutations_DeleteLine") == 0) - return AlgorithmType::LineMutations_DeleteLine; - else if(type.compare("LineMutations_DeleteSequentialLines") == 0) - return AlgorithmType::LineMutations_DeleteSequentialLines; - else if(type.compare("LineMutations_DuplicateLine") == 0) - return AlgorithmType::LineMutations_DuplicateLine; - else if(type.compare("LineMutations_CopyLineCloseBy") == 0) - return AlgorithmType::LineMutations_CopyLineCloseBy; - else if(type.compare("LineMutations_RepeatLine") == 0) - return AlgorithmType::LineMutations_RepeatLine; - else if(type.compare("LineMutations_SwapLine") == 0) - return AlgorithmType::LineMutations_SwapLine; - else - return AlgorithmType::Unknown; -} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/radamsaMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/radamsaMutator.hpp deleted file mode 100644 index fc70fe9..0000000 --- a/Radamsa/vmf/src/modules/common/mutator/radamsaMutator.hpp +++ /dev/null @@ -1,134 +0,0 @@ -/* ============================================================================= - * Vader Modular Fuzzer - * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. - * - * - * Effort sponsored by the U.S. Government under Other Transaction number - * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government - * is authorized to reproduce and distribute reprints for Governmental purposes - * notwithstanding any copyright notation thereon. - * - * The views and conclusions contained herein are those of the authors and - * should not be interpreted as necessarily representing the official policies - * or endorsements, either expressed or implied, of the U.S. Government. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * @license GPL-3.0-or-later - * ===========================================================================*/ -#pragma once - -// VMF Includes -#include "MutatorModule.hpp" -#include "StorageEntry.hpp" -#include "RuntimeException.hpp" -#include "byteMutations.hpp" -#include "lineMutations.hpp" - - -namespace vmf::modules::radamsa -{ -/** - * @brief This module is draws heavily upon the libAFL mutator.c - * - * Uses the specified AFL-style mutation algorithm to mutate the provided - * input. createTestCase is the main mutation method. - * - * See https://github.com/AFLplusplus/LibAFL-legacy/blob/dev/src/mutator.c - * - * The following includes code copied from the LibAFL_Legacy repository. - * - * american fuzzy lop++ - fuzzer header - * ------------------------------------ - * Originally written by Michal Zalewski - * Now maintained by Marc Heuse , - * Heiko Eißfeldt , - * Andrea Fioraldi , - * Dominik Maier - * Copyright 2016, 2017 Google Inc. All rights reserved. - * Copyright 2019-2020 AFLplusplus Project. All rights reserved. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * http://www.apache.org/licenses/LICENSE-2.0 - * This is the Library based on AFL++ which can be used to build - * customized fuzzers for a specific target while taking advantage of - * a lot of features that AFL++ already provides. - */ -class RadamsaMutator: public MutatorModule, - public vmf::radamsa::mutations::ByteMutations, - public vmf::radamsa::mutations::LineMutations -{ -public: - enum class AlgorithmType : uint8_t - { - ByteMutations_DropByte = 0u, - ByteMutations_FlipByte, - ByteMutations_InsertByte, - ByteMutations_RepeatByte, - ByteMutations_PermuteByte, - ByteMutations_IncrementByte, - ByteMutations_DecrementByte, - ByteMutations_RandomizeByte, - LineMutations_DeleteLine, - LineMutations_DeleteSequentialLines, - LineMutations_DuplicateLine, - LineMutations_CopyLineCloseBy, - LineMutations_RepeatLine, - LineMutations_SwapLine, - Unknown - }; - - RadamsaMutator() = delete; - virtual ~RadamsaMutator() = default; - - RadamsaMutator(std::string name) noexcept : MutatorModule{name}, - vmf::radamsa::mutations::ByteMutations{RANDOM_NUMBER_GENERATOR_}, - vmf::radamsa::mutations::LineMutations{RANDOM_NUMBER_GENERATOR_} - - {} - - ///////////////////////////// - // MutatorModule Interface // - ///////////////////////////// - virtual void init(ConfigInterface& config) { SetAlgorithmType(stringToType(config.getStringParam(getModuleName(), "algType"))); } - - virtual void registerStorageNeeds(StorageRegistry& registry); - - virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); - - static Module* build(std::string name); - -protected: - //////////////////////////// - // RadamsaMutator Utility // - //////////////////////////// - void SetAlgorithmType(const AlgorithmType algorithmType); - - AlgorithmType GetAlgorithmType() const noexcept { return algorithmType_; } - - static AlgorithmType stringToType(std::string type); - - static constexpr int INVALID_TEST_CASE_KEY_{std::numeric_limits::min()}; - static constexpr int INVALID_NORMAL_TAG_{INVALID_TEST_CASE_KEY_}; - - int testCaseKey_{INVALID_TEST_CASE_KEY_}; - int normalTag_{INVALID_NORMAL_TAG_}; - AlgorithmType algorithmType_{AlgorithmType::ByteMutations_DropByte}; - - std::default_random_engine RANDOM_NUMBER_GENERATOR_; - -private: -}; -} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..620fefd --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(${PROJECT_SOURCE_DIR}/test/unittest) diff --git a/test/unittest/CMakeLists.txt b/test/unittest/CMakeLists.txt new file mode 100644 index 0000000..b8e93c4 --- /dev/null +++ b/test/unittest/CMakeLists.txt @@ -0,0 +1,80 @@ +#=============================================================================== +# Vader Modular Fuzzer (VMF) +# Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. +# +# +# Effort sponsored by the U.S. Government under Other Transaction number +# W9124P-19-9-0001 between AMTC and the Government. The U.S. Government +# Is authorized to reproduce and distribute reprints for Governmental purposes +# notwithstanding any copyright notation thereon. +# +# The views and conclusions contained herein are those of the authors and +# should not be interpreted as necessarily representing the official policies +# or endorsements, either expressed or implied, of the U.S. Government. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 (only) as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# @license GPL-2.0-only +#=============================================================================== + +# required by gtest +find_package(Threads REQUIRED) + +SET(TEST_SRCS + ${VMF_INSTALL}/../../test/unittest/ModuleTestHelper.cpp + ${VMF_INSTALL}/../../test/unittest/TestConfigInterface.cpp + ../../Radamsa/test/RadamsaDecrementByteMutatorTest.cpp + ../../Radamsa/test/RadamsaDropByteMutatorTest.cpp + ../../Radamsa/test/RadamsaFlipByteMutatorTest.cpp + ../../Radamsa/test/RadamsaIncrementByteMutatorTest.cpp + ../../Radamsa/test/RadamsaInsertByteMutatorTest.cpp + ../../Radamsa/test/RadamsaPermuteByteMutatorTest.cpp + ../../Radamsa/test/RadamsaRandomizeByteMutatorTest.cpp + ../../Radamsa/test/RadamsaRepeatByteMutatorTest.cpp + ../../Radamsa/test/RadamsaDeleteLineMutatorTest.cpp + ../../Radamsa/test/RadamsaDeleteSequentialLinesMutatorTest.cpp + ../../Radamsa/test/RadamsaDuplicateLineMutatorTest.cpp + ../../Radamsa/test/RadamsaCopyLineCloseByMutatorTest.cpp + ../../Radamsa/test/RadamsaRepeatLineMutatorTest.cpp + ../../Radamsa/test/RadamsaSwapLineMutatorTest.cpp +) + +add_executable(VmfTest ${TEST_SRCS}) + +set_target_properties(VmfTest PROPERTIES LINKER_LANGUAGE CXX) + +target_include_directories(VmfTest PUBLIC + ${VMF_INSTALL}/include + ${VMF_INSTALL}/../../vmf/dependencies/googletest/googletest/include + ${VMF_INSTALL}/../../test/unittest + ${VMF_INSTALL}/../../vmf/src/framework/baseclasses + ${VMF_INSTALL}/../../vmf/src/framework/util + ../../Radamsa/vmf/src/modules/common/mutator +) + +target_link_directories(VmfTest PUBLIC + ${VMF_INSTALL}/lib + ${VMF_INSTALL}/plugins + ${VMF_INSTALL}/../lib +) + +target_link_libraries(VmfTest + PUBLIC + gtest + gtest_main + VMFFramework + CoreModules + Threads::Threads + Radamsa +) +gtest_discover_tests(VmfTest) From a478a964a4aaa342cd8c896bb8d894332ede81fe Mon Sep 17 00:00:00 2001 From: GabeClark99 <54868591+GabeClark99@users.noreply.github.com> Date: Tue, 17 Jun 2025 12:19:13 -0500 Subject: [PATCH 28/31] Rusty radamsa mutators (#7) * Rand refactoring for 4.1.0 * DecrementByte Length Test * TestByteDecremented * DropByte TestBufferSize * DropByte TestByteDropped * FlipByte TestBufferSize * FlibByte TestByteFlipped * IncrementByte tests * InsertByte tests * fixed test name * PermuteByte tests TestPermuteTwoBytes currently failing due to buff having the same values as modBuff. Need to discuss if this is intended behavior for mutators in general. * RandomizeByte TestRandomize * RepeatByte * misc cleanup Added license header, removed superfluous comments, combined buffer length test cases * buff_len, equality check simplified buff length check by calling it once and storing the result; asserting buff != modBuff for buff_len where buff_len+1 == modBuff_len * migrated to separate gtest binary can now run our tests without piggybacking off of stock vmf * DeleteLine * the rest * DeleteLine Exception Cases tests for buffer size and buffer exists * LineMutatorBase stub class for LineMutatorBase and telling mutators to inherit * ByteMutatorBase stub class for ByteMutatorBase and telling mutators to inherit * moved byte-specific helper function GetRandomByteRepetitionLength is specific to byte mutators, so it should live in the new ByteMutatorBase instead * Squashed commit of the following: commit 95bdd8767ab530669646a478a8711ae910158d46 Merge: 7b5d68d f3b3834 Author: GabeClark99 <54868591+GabeClark99@users.noreply.github.com> Date: Fri Jan 24 17:14:18 2025 -0600 Merge pull request #2 from crusoe112/mutator-bases Mutator bases commit f3b3834bee9cf7da35836c356949b680d9c1afe4 Author: GabeClark99 <54868591+GabeClark99@users.noreply.github.com> Date: Fri Jan 24 15:27:20 2025 -0500 moved byte-specific helper function GetRandomByteRepetitionLength is specific to byte mutators, so it should live in the new ByteMutatorBase instead commit 9030be9f5748a056f58924b1f598197e413565f4 Author: GabeClark99 <54868591+GabeClark99@users.noreply.github.com> Date: Fri Jan 24 15:22:54 2025 -0500 ByteMutatorBase stub class for ByteMutatorBase and telling mutators to inherit commit 86f1f26a098c4cb50689858f300aa6035c31e1c5 Author: GabeClark99 <54868591+GabeClark99@users.noreply.github.com> Date: Fri Jan 24 15:15:46 2025 -0500 LineMutatorBase stub class for LineMutatorBase and telling mutators to inherit * implemented Line struct * implemented LineVector struct * implemented LineList struct * fixed typo * DeleteLine typical usage tests Intentionally excluding testing the code under the IsBinarish conditional because it doesn't appear to be correctly implemented in the original and may not be carried over into the new refactoring * OneLine content test * fixed DeleteLine buff tests DeleteLine will append a null terminator, which was not accounted for previously. * DeleteSequentialLines exception tests * DeleteSequentialLines typical usage tests * DuplicateLine exception tests * Fixed testing buffer equality also added buffer equality test to cases that needed it * DuplicateLine OneLine * DuplicateLine TwoLines and ThreeLines * CopyLineCloseBy tests * DuplicateLineMutatorTest fixes - previous version assumed DuplicateLine operated like RepeatLine; this has been corrected - simplified buffer content tests - various cosmetic changes to improve readability * RepeatLine Tests * SwapLine tests * VMF v4.0.0 compatibility * Add Determinism module set AFLDeterministicFeedback: removes testcase execution time from fitness, and ignores hangs which alleviates some determinism issues DeterministicTesterOutput: computes a running checksum of all generated testcase contents and IDs * Merge pull request #4 from crusoe112/Radamsa-Mutator-Refactoring Splitting each mutator off into its own class * Mutator stubs mutator names are subject to change once I figure out what each one is actually doing * Renamed GetRandomByteRepetitionLength to be more generic * RepeatByteSequence exception tests * Added RepeatByteSequence and its tests. also added missing exception tests to RepeatByte * Fix RepeatByteMutator exception tests copy-paste error * Added DeleteByteSequence * Renamed SwapLineOrder to PermuteLines * Implemented PermuteLines * minor cleanup * Implemented InsertLine renamed from InsertLineFromElsewhere * Adjusted InsertLine minimum bytes requirement * Dockerfile update * VMF 5.0.0 Release * Install location fix Because we're dependent on both the installation of VMF as well as its test suite dependencies, we need to know where both are located. Ensuring that VMF installs to the default location allows us to know both without having to specify a path to the dependencies. * VMF version fix Temp fix until we update for 5.0.0. Clone with all version commits, not just latest, and checkout the 4.1.0 release commit. * Minor changes comment cleanup and fix error message * Some 5.0.0 fixes * ReplaceLine renamed from ReplaceLineFromElsewhere * working commit compiles. OneNode segfault-ing, TwoNodes passes * TreeMutatorBase and DeleteNode the segfault disappeared on its own; I'm sure it's fine... * working commit segfault when referencing n->children in deleteNode. n->value is uninitialized? * Generalized TreeMutatorBase Switched to using 1:N trees instead of BSTs. * Separated some TreeMutator logic into two functions split finding node by index into its own function. split node creation into its own function. * Implemented DuplicateNode * Implemented ReplaceNode renamed from SwapNodes * SwapNodes renamed from SwapNodesPairwise * RepeatPath also moved GetRandomRepetitionLength from LineMutatorBase to MutatorBase, as Tree mutators also need it * WidenCodePointMutator * InsertUnicode TODO: add tests for RadamsaByteMutatorBase::encode_utf8() * ModifyTextNumber * Remove XmlMutator has no definition in the original rust * working commit pick up with findJumpPoints * working commit * FuseThis * FuseNext also moved Fuse helpers into their own file for easy reuse * FuseOld * working commit pick up with testing * AsciiBad * Merge fix * Squashed commit of the following: commit 8762bf64dbfedbd6ee6180633e9b2b4f1b825bf4 Author: GabeClark99 <54868591+GabeClark99@users.noreply.github.com> Date: Tue Jun 17 09:09:39 2025 -0500 4.1.0 release (#5) * Rand refactoring for 4.1.0 * DecrementByte Length Test * TestByteDecremented * DropByte TestBufferSize * DropByte TestByteDropped * FlipByte TestBufferSize * FlibByte TestByteFlipped * IncrementByte tests * InsertByte tests * fixed test name * PermuteByte tests TestPermuteTwoBytes currently failing due to buff having the same values as modBuff. Need to discuss if this is intended behavior for mutators in general. * RandomizeByte TestRandomize * RepeatByte * misc cleanup Added license header, removed superfluous comments, combined buffer length test cases * buff_len, equality check simplified buff length check by calling it once and storing the result; asserting buff != modBuff for buff_len where buff_len+1 == modBuff_len * migrated to separate gtest binary can now run our tests without piggybacking off of stock vmf * DeleteLine * the rest * DeleteLine Exception Cases tests for buffer size and buffer exists * LineMutatorBase stub class for LineMutatorBase and telling mutators to inherit * ByteMutatorBase stub class for ByteMutatorBase and telling mutators to inherit * moved byte-specific helper function GetRandomByteRepetitionLength is specific to byte mutators, so it should live in the new ByteMutatorBase instead * Squashed commit of the following: commit 95bdd8767ab530669646a478a8711ae910158d46 Merge: 7b5d68d f3b3834 Author: GabeClark99 <54868591+GabeClark99@users.noreply.github.com> Date: Fri Jan 24 17:14:18 2025 -0600 Merge pull request #2 from crusoe112/mutator-bases Mutator bases commit f3b3834bee9cf7da35836c356949b680d9c1afe4 Author: GabeClark99 <54868591+GabeClark99@users.noreply.github.com> Date: Fri Jan 24 15:27:20 2025 -0500 moved byte-specific helper function GetRandomByteRepetitionLength is specific to byte mutators, so it should live in the new ByteMutatorBase instead commit 9030be9f5748a056f58924b1f598197e413565f4 Author: GabeClark99 <54868591+GabeClark99@users.noreply.github.com> Date: Fri Jan 24 15:22:54 2025 -0500 ByteMutatorBase stub class for ByteMutatorBase and telling mutators to inherit commit 86f1f26a098c4cb50689858f300aa6035c31e1c5 Author: GabeClark99 <54868591+GabeClark99@users.noreply.github.com> Date: Fri Jan 24 15:15:46 2025 -0500 LineMutatorBase stub class for LineMutatorBase and telling mutators to inherit * implemented Line struct * implemented LineVector struct * implemented LineList struct * fixed typo * DeleteLine typical usage tests Intentionally excluding testing the code under the IsBinarish conditional because it doesn't appear to be correctly implemented in the original and may not be carried over into the new refactoring * OneLine content test * fixed DeleteLine buff tests DeleteLine will append a null terminator, which was not accounted for previously. * DeleteSequentialLines exception tests * DeleteSequentialLines typical usage tests * DuplicateLine exception tests * Fixed testing buffer equality also added buffer equality test to cases that needed it * DuplicateLine OneLine * DuplicateLine TwoLines and ThreeLines * CopyLineCloseBy tests * DuplicateLineMutatorTest fixes - previous version assumed DuplicateLine operated like RepeatLine; this has been corrected - simplified buffer content tests - various cosmetic changes to improve readability * RepeatLine Tests * SwapLine tests * Merge pull request #4 from crusoe112/Radamsa-Mutator-Refactoring Splitting each mutator off into its own class --------- Signed-off-by: GabeClark99 <54868591+GabeClark99@users.noreply.github.com> Co-authored-by: Marc Bohler Co-authored-by: crusoe112 --------- Signed-off-by: GabeClark99 <54868591+GabeClark99@users.noreply.github.com> Co-authored-by: Marc Bohler Co-authored-by: crusoe112 Co-authored-by: Joshua Weader Co-authored-by: Dharsee, Komail --- .gitignore | 34 +- CMakeLists.txt | 44 +- Determinism/CMakeLists.txt | 31 ++ Determinism/docs/README.md | 55 +++ .../config/defaultModules_determinism.yaml | 36 ++ Determinism/vmf/src/CMakeLists.txt | 22 + Determinism/vmf/src/modules/CMakeLists.txt | 63 +++ .../feedback/AFLDeterministicFeedback.cpp | 171 ++++++++ .../feedback/AFLDeterministicFeedback.hpp | 68 +++ .../common/output/DeterminismTesterOutput.cpp | 112 +++++ .../common/output/DeterminismTesterOutput.hpp | 48 +++ README.md | 43 +- Radamsa/CMakeLists.txt | 30 ++ Radamsa/test/RadamsaAsciiBadMutatorTest.cpp | 231 +++++++++++ .../RadamsaDeleteByteSequenceMutatorTest.cpp | 242 +++++++++++ Radamsa/test/RadamsaDeleteLineMutatorTest.cpp | 8 +- Radamsa/test/RadamsaDeleteNodeMutatorTest.cpp | 270 ++++++++++++ .../test/RadamsaDuplicateNodeMutatorTest.cpp | 262 ++++++++++++ Radamsa/test/RadamsaFuseNextMutatorTest.cpp | 194 +++++++++ Radamsa/test/RadamsaFuseOldMutatorTest.cpp | 194 +++++++++ Radamsa/test/RadamsaFuseThisMutatorTest.cpp | 198 +++++++++ Radamsa/test/RadamsaFuse_helpers.cpp | 131 ++++++ Radamsa/test/RadamsaFuse_helpers.hpp | 39 ++ Radamsa/test/RadamsaInsertLineMutatorTest.cpp | 243 +++++++++++ .../test/RadamsaInsertUnicodeMutatorTest.cpp | 176 ++++++++ .../RadamsaModifyTextNumberMutatorTest.cpp | 227 ++++++++++ .../test/RadamsaPermuteLinesMutatorTest.cpp | 193 +++++++++ Radamsa/test/RadamsaRepeatByteMutatorTest.cpp | 35 +- .../RadamsaRepeatByteSequenceMutatorTest.cpp | 241 +++++++++++ Radamsa/test/RadamsaRepeatPathMutatorTest.cpp | 299 ++++++++++++++ .../test/RadamsaReplaceLineMutatorTest.cpp | 236 +++++++++++ .../test/RadamsaReplaceNodeMutatorTest.cpp | 277 +++++++++++++ Radamsa/test/RadamsaSwapNodesMutatorTest.cpp | 268 ++++++++++++ Radamsa/test/RadamsaTreeMutatorBaseTest.cpp | 184 +++++++++ .../test/RadamsaWidenCodePointMutatorTest.cpp | 237 +++++++++++ Radamsa/vmf/src/CMakeLists.txt | 15 +- Radamsa/vmf/src/modules/CMakeLists.txt | 59 ++- .../common/mutator/RadamsaAsciiBadMutator.cpp | 391 ++++++++++++++++++ .../common/mutator/RadamsaAsciiBadMutator.hpp | 57 +++ .../common/mutator/RadamsaByteMutatorBase.hpp | 233 ++++++++++- .../RadamsaDeleteByteSequenceMutator.cpp | 136 ++++++ .../RadamsaDeleteByteSequenceMutator.hpp | 57 +++ .../mutator/RadamsaDeleteNodeMutator.cpp | 130 ++++++ .../mutator/RadamsaDeleteNodeMutator.hpp | 57 +++ .../mutator/RadamsaDuplicateNodeMutator.cpp | 132 ++++++ .../mutator/RadamsaDuplicateNodeMutator.hpp | 57 +++ .../common/mutator/RadamsaFlipByteMutator.cpp | 7 +- .../common/mutator/RadamsaFuseNextMutator.cpp | 124 ++++++ .../common/mutator/RadamsaFuseNextMutator.hpp | 57 +++ .../common/mutator/RadamsaFuseOldMutator.cpp | 128 ++++++ .../common/mutator/RadamsaFuseOldMutator.hpp | 57 +++ .../common/mutator/RadamsaFuseThisMutator.cpp | 119 ++++++ .../common/mutator/RadamsaFuseThisMutator.hpp | 57 +++ .../mutator/RadamsaInsertLineMutator.cpp | 153 +++++++ .../mutator/RadamsaInsertLineMutator.hpp | 57 +++ .../mutator/RadamsaInsertUnicodeMutator.cpp | 170 ++++++++ .../mutator/RadamsaInsertUnicodeMutator.hpp | 58 +++ .../common/mutator/RadamsaLineMutatorBase.hpp | 54 +-- .../RadamsaModifyTextNumberMutator.cpp | 182 ++++++++ .../RadamsaModifyTextNumberMutator.hpp | 57 +++ .../common/mutator/RadamsaMutatorBase.hpp | 20 +- .../mutator/RadamsaPermuteLinesMutator.cpp | 166 ++++++++ .../mutator/RadamsaPermuteLinesMutator.hpp | 57 +++ .../mutator/RadamsaRepeatByteMutator.cpp | 2 +- .../RadamsaRepeatByteSequenceMutator.cpp | 150 +++++++ .../RadamsaRepeatByteSequenceMutator.hpp | 57 +++ .../mutator/RadamsaRepeatPathMutator.cpp | 143 +++++++ .../mutator/RadamsaRepeatPathMutator.hpp | 57 +++ .../mutator/RadamsaReplaceLineMutator.cpp | 157 +++++++ .../mutator/RadamsaReplaceLineMutator.hpp | 57 +++ .../mutator/RadamsaReplaceNodeMutator.cpp | 138 +++++++ .../mutator/RadamsaReplaceNodeMutator.hpp | 57 +++ .../mutator/RadamsaSwapNodesMutator.cpp | 139 +++++++ .../mutator/RadamsaSwapNodesMutator.hpp | 57 +++ .../common/mutator/RadamsaTreeMutatorBase.hpp | 344 +++++++++++++++ .../mutator/RadamsaWidenCodePointMutator.cpp | 138 +++++++ .../mutator/RadamsaWidenCodePointMutator.hpp | 57 +++ SamplePackage/CMakeLists.txt | 26 ++ SamplePackage/README.md | 8 +- SamplePackage/vmf/src/CMakeLists.txt | 15 +- SamplePackage/vmf/src/modules/CMakeLists.txt | 39 +- .../src/modules/common/mutator/MyMutator.cpp | 24 +- .../src/modules/common/mutator/MyMutator.hpp | 15 +- .../vmf/src/modules/common/mutator/README.md | 8 - dockerfiles/Dockerfile | 29 +- dockerfiles/Dockerfile.kali | 75 ---- test/unittest/CMakeLists.txt | 40 +- 87 files changed, 9543 insertions(+), 278 deletions(-) create mode 100644 Determinism/CMakeLists.txt create mode 100644 Determinism/docs/README.md create mode 100644 Determinism/test/config/defaultModules_determinism.yaml create mode 100644 Determinism/vmf/src/CMakeLists.txt create mode 100644 Determinism/vmf/src/modules/CMakeLists.txt create mode 100644 Determinism/vmf/src/modules/common/feedback/AFLDeterministicFeedback.cpp create mode 100644 Determinism/vmf/src/modules/common/feedback/AFLDeterministicFeedback.hpp create mode 100644 Determinism/vmf/src/modules/common/output/DeterminismTesterOutput.cpp create mode 100644 Determinism/vmf/src/modules/common/output/DeterminismTesterOutput.hpp create mode 100644 Radamsa/CMakeLists.txt create mode 100644 Radamsa/test/RadamsaAsciiBadMutatorTest.cpp create mode 100644 Radamsa/test/RadamsaDeleteByteSequenceMutatorTest.cpp create mode 100644 Radamsa/test/RadamsaDeleteNodeMutatorTest.cpp create mode 100644 Radamsa/test/RadamsaDuplicateNodeMutatorTest.cpp create mode 100644 Radamsa/test/RadamsaFuseNextMutatorTest.cpp create mode 100644 Radamsa/test/RadamsaFuseOldMutatorTest.cpp create mode 100644 Radamsa/test/RadamsaFuseThisMutatorTest.cpp create mode 100644 Radamsa/test/RadamsaFuse_helpers.cpp create mode 100644 Radamsa/test/RadamsaFuse_helpers.hpp create mode 100644 Radamsa/test/RadamsaInsertLineMutatorTest.cpp create mode 100644 Radamsa/test/RadamsaInsertUnicodeMutatorTest.cpp create mode 100644 Radamsa/test/RadamsaModifyTextNumberMutatorTest.cpp create mode 100644 Radamsa/test/RadamsaPermuteLinesMutatorTest.cpp create mode 100644 Radamsa/test/RadamsaRepeatByteSequenceMutatorTest.cpp create mode 100644 Radamsa/test/RadamsaRepeatPathMutatorTest.cpp create mode 100644 Radamsa/test/RadamsaReplaceLineMutatorTest.cpp create mode 100644 Radamsa/test/RadamsaReplaceNodeMutatorTest.cpp create mode 100644 Radamsa/test/RadamsaSwapNodesMutatorTest.cpp create mode 100644 Radamsa/test/RadamsaTreeMutatorBaseTest.cpp create mode 100644 Radamsa/test/RadamsaWidenCodePointMutatorTest.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaAsciiBadMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaAsciiBadMutator.hpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteByteSequenceMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteByteSequenceMutator.hpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteNodeMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteNodeMutator.hpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaDuplicateNodeMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaDuplicateNodeMutator.hpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaFuseNextMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaFuseNextMutator.hpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaFuseOldMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaFuseOldMutator.hpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaFuseThisMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaFuseThisMutator.hpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaInsertLineMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaInsertLineMutator.hpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaInsertUnicodeMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaInsertUnicodeMutator.hpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaModifyTextNumberMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaModifyTextNumberMutator.hpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaPermuteLinesMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaPermuteLinesMutator.hpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteSequenceMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteSequenceMutator.hpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatPathMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatPathMutator.hpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaReplaceLineMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaReplaceLineMutator.hpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaReplaceNodeMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaReplaceNodeMutator.hpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaSwapNodesMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaSwapNodesMutator.hpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaTreeMutatorBase.hpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaWidenCodePointMutator.cpp create mode 100644 Radamsa/vmf/src/modules/common/mutator/RadamsaWidenCodePointMutator.hpp create mode 100644 SamplePackage/CMakeLists.txt delete mode 100644 SamplePackage/vmf/src/modules/common/mutator/README.md delete mode 100644 dockerfiles/Dockerfile.kali diff --git a/.gitignore b/.gitignore index 3251c8e..524a5e8 100644 --- a/.gitignore +++ b/.gitignore @@ -5,15 +5,45 @@ *.obj *.*~ *.exe +*.swp + +# Vader */VaderWin/.vs/* out/ output/ -!vmf/src/coremodules/*/output/ +!*/vmf/src/modules/*/output/ output_test/ +vmf_install + x64/ classes/ */classes/ build/ targets/ + +#VS Code .vscode/ -*.swp \ No newline at end of file +*.code-workspace + +# CMake +CMakeLists.txt.user +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps + +# GDB +.gdbinit + +# Dev Container +.devcontainer.json + +# Helper scripts +*.sh +*.ps1 diff --git a/CMakeLists.txt b/CMakeLists.txt index 5aaf05f..3f5da9e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,17 +1,8 @@ #=============================================================================== # Vader Modular Fuzzer (VMF) -# Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. -# -# -# Effort sponsored by the U.S. Government under Other Transaction number -# W9124P-19-9-0001 between AMTC and the Government. The U.S. Government -# Is authorized to reproduce and distribute reprints for Governmental purposes -# notwithstanding any copyright notation thereon. -# -# The views and conclusions contained herein are those of the authors and -# should not be interpreted as necessarily representing the official policies -# or endorsements, either expressed or implied, of the U.S. Government. -# +# Copyright (c) 2021-2025 The Charles Stark Draper Laboratory, Inc. +# +# # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 (only) as # published by the Free Software Foundation. @@ -37,16 +28,32 @@ set(CMAKE_CXX_COMPILER g++) project(VmfExtension VERSION 1.0 LANGUAGES CXX) -# Check that VMF_INSTALL directory is properly defined, exit with error if not -if (NOT IS_DIRECTORY ${VMF_INSTALL}) - message( FATAL_ERROR "CMake variable VMF_INSTALL must be defined as full path to a VMF install tree, please use cmake -DVMF_INSTALL=/full/path/to/VMF" ) +# Check that CMAKE_INSTALL_PREFIX directory is properly defined, exit with error if not +if (NOT IS_DIRECTORY ${CMAKE_INSTALL_PREFIX}) + message( FATAL_ERROR "CMake variable CMAKE_INSTALL_PREFIX must be defined as full path to a VMF install tree, please use cmake -DCMAKE_INSTALL_PREFIX=/full/path/to/VMF" ) endif() # Bring in VMF support variables and utility functions -list(APPEND CMAKE_MODULE_PATH "${VMF_INSTALL}/cmake") +list(APPEND CMAKE_MODULE_PATH "${CMAKE_INSTALL_PREFIX}/cmake") include(vmf_imports) include(vmf) +# --- VMF workaround patch --- +# The vmf_framework target imported from the installed VMF tree incorrectly sets: +# - INTERFACE_INCLUDE_DIRECTORIES to "/include" +# - IMPORTED_LOCATION to "/lib/libVMFFramework.so" +# These paths are invalid or conflict with the actual installed VMF location. +# Since VMF cannot be modified directly, we override the target's include path and library location here. +# This ensures correct compilation and linking against the local VMF install tree. +get_target_property(_vmf_includes vmf_framework INTERFACE_INCLUDE_DIRECTORIES) +list(REMOVE_ITEM _vmf_includes "/include") +list(APPEND _vmf_includes "${CMAKE_INSTALL_PREFIX}/include") +set_target_properties(vmf_framework PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${_vmf_includes}" + IMPORTED_LOCATION "${CMAKE_INSTALL_PREFIX}/lib/libVMFFramework.so" +) +# ----------------------------- + # Configure testing include(GoogleTest) enable_testing() @@ -55,6 +62,7 @@ add_subdirectory(${PROJECT_SOURCE_DIR}/test) # ---- TAILOR SPECIFIC EXTENSION PACKAGES HERE ---- # Add in extension package directories -add_subdirectory(${PROJECT_SOURCE_DIR}/Radamsa/vmf/src) -add_subdirectory(${PROJECT_SOURCE_DIR}/SamplePackage/vmf/src) +add_subdirectory(${PROJECT_SOURCE_DIR}/Determinism) +add_subdirectory(${PROJECT_SOURCE_DIR}/Radamsa) +#add_subdirectory(${PROJECT_SOURCE_DIR}/SamplePackage) diff --git a/Determinism/CMakeLists.txt b/Determinism/CMakeLists.txt new file mode 100644 index 0000000..9bd4285 --- /dev/null +++ b/Determinism/CMakeLists.txt @@ -0,0 +1,31 @@ +#=============================================================================== +# Vader Modular Fuzzer (VMF) +# Copyright (c) 2021-2025 The Charles Stark Draper Laboratory, Inc. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 (only) as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# @license GPL-2.0-only +#=============================================================================== + +add_subdirectory(vmf/src) + +# Install sample configuration files +install(DIRECTORY test DESTINATION + DESTINATION ${CMAKE_INSTALL_PREFIX} ) + +# Install documentation +install(FILES docs/README.md + DESTINATION ${CMAKE_INSTALL_PREFIX}/docs/experimental_modules + RENAME determinism_modules_readme.md +) diff --git a/Determinism/docs/README.md b/Determinism/docs/README.md new file mode 100644 index 0000000..27a7e6c --- /dev/null +++ b/Determinism/docs/README.md @@ -0,0 +1,55 @@ +# Determinism Modules + +These modules provide support for deterministic VMF runs and determinism validation. + +The following unifuzz SUTs have been found to run well deterministically: +- exiv2 +- jhead +- mp3gain +- pdftotext +- imginfo + +To run deterministically, you will also need to configure VMF with a fixed seed. In your SUT-specific configuration file: +```yaml +vmfFramework: + seed: 12345 #Or your favorite number, it just matters that that seed is set to something +``` + +Then combine your SUT-specific configuration with the included `test/config/defaultModules_determinism.yaml`. + +## DeterministicTesterOutput + +This is an output module that computes a running checksum of all generated testcase contents and IDs. It prints out the checksum every 10 testcases, enabling a user to compare two runs for determinism validation. + +This module has no configuration parameters. + +## AFLDeterministicFeedback + +This is a feedback module that can be used in a deterministic configuration. It is similar to core module AFLFeedback except that it removes testcase execution time from the fitness function calculation. It also ignores hangs, which alleviates, but not does not remove, determinism issues that arise from hangs. + +This module has the following configuration parameters. + +## `AFLDeterministicFeedback` + +Configuration information specific to the AFLDeterministicFeedback module. This module is similar to AFLFeedback except that it only uses code coverage and test case size to compute fitness; execution speed is omitted. This module supports adjusting the relative weights of the components used to compute the fitness of each test case. Because test cases are sorted in storage by their fitness, and the Input Generator modules provided with VMF use a weighted random selection that favors more fit test cases, changing the fitness computation changes which test cases are selected for mutation. + +### `AFLFeedback.useCustomWeights` + +Value type: `` + +Status: Optional + +Default value: false + +Usage: Enables the use of custom weighting factors in the AFL feedback algorithm. + +### `AFLFeedback.sizeWeight` + +Value type: `` + +Status: Optional + +Default value: 1.0 + +Usage: Provides a relative weighting factor for the normalized size of the test case. Value should be in the range of 0.0 - 10.0. A value of 0.0 will remove this factor from the weighting algorithm. + diff --git a/Determinism/test/config/defaultModules_determinism.yaml b/Determinism/test/config/defaultModules_determinism.yaml new file mode 100644 index 0000000..83b7f63 --- /dev/null +++ b/Determinism/test/config/defaultModules_determinism.yaml @@ -0,0 +1,36 @@ +#To achieve determinism, the vmfFramework.seed parameter must be set as well +vmfModules: + storage: #a storage module must be specified + className: SimpleStorage + controller: #a controller module must be specified + className: IterativeController + children: + - className: DirectoryBasedSeedGen + - className: GeneticAlgorithmInputGenerator + - className: AFLForkserverExecutor + - className: AFLDeterministicFeedback + - className: SaveCorpusOutput + - className: ComputeStats + - className: StatsOutput + - className: DeterminismTesterOutput + GeneticAlgorithmInputGenerator: + children: + - className: AFLFlipBitMutator + - className: AFLFlip2BitMutator + - className: AFLFlip4BitMutator + - className: AFLFlipByteMutator + - className: AFLFlip2ByteMutator + - className: AFLFlip4ByteMutator + - className: AFLRandomByteAddSubMutator + - className: AFLRandomByteMutator + - className: AFLDeleteMutator + - className: AFLCloneMutator + - className: AFLSpliceMutator + +# Modules-specific parameters +#(The SUT-specific portions of these all defined using YAML anchors) +AFLForkserverExecutor: + sutArgv: *SUT_ARGV + +DirectoryBasedSeedGen: + inputDir: *INPUT_DIR diff --git a/Determinism/vmf/src/CMakeLists.txt b/Determinism/vmf/src/CMakeLists.txt new file mode 100644 index 0000000..aacd145 --- /dev/null +++ b/Determinism/vmf/src/CMakeLists.txt @@ -0,0 +1,22 @@ +#=============================================================================== +# Vader Modular Fuzzer (VMF) +# Copyright (c) 2021-2025 The Charles Stark Draper Laboratory, Inc. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 (only) as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# @license GPL-2.0-only +#=============================================================================== + +add_subdirectory(modules) + diff --git a/Determinism/vmf/src/modules/CMakeLists.txt b/Determinism/vmf/src/modules/CMakeLists.txt new file mode 100644 index 0000000..4753932 --- /dev/null +++ b/Determinism/vmf/src/modules/CMakeLists.txt @@ -0,0 +1,63 @@ +#=============================================================================== +# Vader Modular Fuzzer (VMF) +# Copyright (c) 2021-2025 The Charles Stark Draper Laboratory, Inc. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 (only) as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# @license GPL-2.0-only +#=============================================================================== + +# Create Determinism library +add_library(Determinism SHARED + common/feedback/AFLDeterministicFeedback.cpp + common/output/DeterminismTesterOutput.cpp +) + +#Set flag to export all symbols for windows builds +set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) + +# windows needs an additional import to make the logger work +if(WIN32) + target_compile_definitions(Determinism PRIVATE PLOG_IMPORT) +endif() + +# Build-time dependencies for Determinism +link_directories(Determinism PRIVATE +) + +# Build-time dependencies for Determinism +target_link_libraries(Determinism PRIVATE + vmf_framework +) + +# Build-time dependencies for Determinism +target_include_directories(Determinism PRIVATE + ${CMAKE_INSTALL_PREFIX}/include + ${CMAKE_INSTALL_PREFIX}/include/vmf + ${CMAKE_INSTALL_PREFIX}/include/plog + ${PROJECT_SOURCE_DIR}/src/module +) + +# Install Determinism library in VMF plugins directory +install(TARGETS Determinism + LIBRARY DESTINATION "${CMAKE_INSTALL_PREFIX}/plugins") + +#On windows the /plugins directory above is ignored, and everything ends up in /lib and /bin +if(WIN32) + cmake_path(SET WIN_LIB_FILE ${CMAKE_INSTALL_PREFIX}/lib/Determinism.lib) + cmake_path(SET WIN_DLL_FILE ${CMAKE_INSTALL_PREFIX}/bin/Determinism.dll) + install(FILES ${WIN_LIB_FILE} ${WIN_DLL_FILE} + DESTINATION ${CMAKE_INSTALL_PREFIX}/plugins) +endif() + diff --git a/Determinism/vmf/src/modules/common/feedback/AFLDeterministicFeedback.cpp b/Determinism/vmf/src/modules/common/feedback/AFLDeterministicFeedback.cpp new file mode 100644 index 0000000..53543c8 --- /dev/null +++ b/Determinism/vmf/src/modules/common/feedback/AFLDeterministicFeedback.cpp @@ -0,0 +1,171 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2025 The Charles Stark Draper Laboratory, Inc. + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#include "AFLDeterministicFeedback.hpp" +#include "Logging.hpp" +#include "VmfUtil.hpp" +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(AFLDeterministicFeedback); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* + */ +Module* AFLDeterministicFeedback::build(std::string name) +{ + return new AFLDeterministicFeedback(name); +} + +/** + * @brief Initialization method + * Reads in all configuration options for this class + * + * @param config + */ +void AFLDeterministicFeedback::init(ConfigInterface& config) +{ + outputDir = config.getOutputDir(); + useCustomWeights = config.getBoolParam(getModuleName(),"useCustomWeights", false); + sizeFitnessWeight = config.getFloatParam(getModuleName(), "sizeWeight", 1.0); + + if(useCustomWeights) + { + if(sizeFitnessWeight < 0.0) + { + throw RuntimeException("One or more Custom Fitness Weights for feedback is invalid", + RuntimeException::USAGE_ERROR); + } + LOG_INFO << "Fitness weights: size = " << sizeFitnessWeight; + } + else + LOG_INFO << "Using AFL++ style Fitness algorithm"; + + // To hold determinisim, we require a speed weight of 0 + useCustomWeights = true; +} + +AFLDeterministicFeedback::AFLDeterministicFeedback(std::string name) : + FeedbackModule(name) +{ + maxTestCaseSize = 0; + numTestCases = 0; +} + +AFLDeterministicFeedback::~AFLDeterministicFeedback() +{ +} + +void AFLDeterministicFeedback::registerStorageNeeds(StorageRegistry& registry) +{ + //Inputs + testCaseKey = registry.registerKey("TEST_CASE", StorageRegistry::BUFFER, StorageRegistry::READ_ONLY); + coverageByteCountKey = registry.registerKey("COVERAGE_COUNT", StorageRegistry::UINT, StorageRegistry::READ_ONLY); + hungTag = registry.registerTag("HUNG", StorageRegistry::READ_ONLY); + hasNewCoverageTag = registry.registerTag("HAS_NEW_COVERAGE", StorageRegistry::READ_ONLY); + + //Outputs + fitnessKey = registry.registerKey("FITNESS", StorageRegistry::FLOAT, StorageRegistry::WRITE_ONLY); +} + +/* Same as AFLFeedback evaluateTestCaseResults, but doesn't save hangs */ +void AFLDeterministicFeedback::evaluateTestCaseResults(StorageModule& storage, std::unique_ptr& entries) +{ + while (entries->hasNext()) + { + StorageEntry* e = entries->getNext(); + + //Compute average metrics + int size = e->getBufferSize(testCaseKey); + avgTestCaseSize = ((avgTestCaseSize * numTestCases) + size)/(numTestCases + 1); + if (size > maxTestCaseSize) + maxTestCaseSize = (float) size; + + numTestCases++; + + bool hung = e->hasTag(hungTag); + + // Then check to see if any new paths were uncovered by this test case. + // For determinism, we save testcases that have new coverage and *didn't* hang + if (e->hasTag(hasNewCoverageTag) && !hung) + { + //Compute the fitness + float fitness = computeFitness(storage, e); + if (fitness > 0) + { + e->setValue(fitnessKey, fitness); + + //Then save the entry + storage.saveEntry(e); + } + } + } +} + +float AFLDeterministicFeedback::computeFitness(StorageModule& storage, StorageEntry* e) +{ + unsigned int coverage = e->getUIntValue(coverageByteCountKey); + int size = e->getBufferSize(testCaseKey); + + float fitness = 0; + if(useCustomWeights) + { + fitness = log10f((float)coverage) + 1; + + // Compute normalized size; use 1 minus the value because they are inversely related to fitness + float normalizedSize = (float)1.0 - size / maxTestCaseSize; + + // Apply size weights to fitness + fitness *= ((float)1.0 + normalizedSize * sizeFitnessWeight); + } + else + { + //Use an algorithm that is closer to what AFL++ uses + fitness = 1.0; + // Prioritize testcases with high coverage + fitness *= log10f((float)coverage) + 1; + // Adjust weight based on size of this testcase compared to average + fitness *= (avgTestCaseSize / size); + + } + + if (fitness < 0.0) + { + //TODO(VADER-1298): Negative fitness values should not happen, but have been observed + //This code will at least prevent the fuzzer from shutting down if this occurs, + //as well as log the underlying test case to disk for further analysis. + LOG_ERROR << "Negative fitness value (this should not be possible) " << fitness; + LOG_ERROR << "Inputs were: coverage=" << coverage << ", size=" << size + << " (avg " << avgTestCaseSize << ")"; + char* buffer = e->getBufferPointer(testCaseKey); + unsigned long id = e->getID(); + + // create a file name with id + std::string filename = std::to_string(id) + "_NegativeFitnessValue"; + VmfUtil::writeBufferToFile(outputDir, filename, buffer, size); + LOG_ERROR << "Test case logged to output directory with filename " << filename; + LOG_ERROR << "This test case will be discarded."; + } + + return fitness; +} diff --git a/Determinism/vmf/src/modules/common/feedback/AFLDeterministicFeedback.hpp b/Determinism/vmf/src/modules/common/feedback/AFLDeterministicFeedback.hpp new file mode 100644 index 0000000..b7ba95b --- /dev/null +++ b/Determinism/vmf/src/modules/common/feedback/AFLDeterministicFeedback.hpp @@ -0,0 +1,68 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2025 The Charles Stark Draper Laboratory, Inc. + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "FeedbackModule.hpp" + +namespace vmf +{ + +/** + * @brief Variant of AFLFeedback for achieving determinism (eg for regression tests). + * It eliminates runtime from the fitness calculation and doesn't save hangs. + * Not actually a child of AFLFeedback so that it can be built as a standalone module. + */ +class AFLDeterministicFeedback : public FeedbackModule { +public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void evaluateTestCaseResults(StorageModule& storage, std::unique_ptr& entries); + + /** + * @brief Construct a new AFLDeterministicFeedback object + * + * @param name the module name + */ + AFLDeterministicFeedback(std::string name); + + virtual ~AFLDeterministicFeedback(); + +protected: + virtual float computeFitness(StorageModule& storage, StorageEntry* e); + unsigned int getExecTimeMs(StorageEntry* e); + std::string outputDir; ///< Location of output directory + + int testCaseKey; ///< Handle for the "TEST_CASE" field + int coverageByteCountKey; ///< Handle for the "COVERAGE_COUNT" field + int fitnessKey; ///< Handle for the "FITNESS" field + int hasNewCoverageTag; ///< Handle for the "HAS_NEW_COVERAGE" tag + int hungTag; ///< Handle for the "HUNG" tag + + float avgTestCaseSize; ///< The average size (for all test cases that have been evaluated) + float maxTestCaseSize; ///< The maximum size (for all test cases that have been evaluated) + float sizeFitnessWeight; ///< A configurable weight to apply to the size factor in computing fitness. Must be >=0.0 + int numTestCases; ///< The total number of test cases that have been evaluated + + bool useCustomWeights; ///< Whether or not custom weights are enabled +}; +} diff --git a/Determinism/vmf/src/modules/common/output/DeterminismTesterOutput.cpp b/Determinism/vmf/src/modules/common/output/DeterminismTesterOutput.cpp new file mode 100644 index 0000000..392e3a7 --- /dev/null +++ b/Determinism/vmf/src/modules/common/output/DeterminismTesterOutput.cpp @@ -0,0 +1,112 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2025 The Charles Stark Draper Laboratory, Inc. + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#include "DeterminismTesterOutput.hpp" +#include "VmfUtil.hpp" + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(DeterminismTesterOutput); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* + */ +Module* DeterminismTesterOutput::build(std::string name) +{ + return new DeterminismTesterOutput(name); +} + +/** + * @brief Initialization method + * Reads in all configuration options for this class + * + * @param config + */ +void DeterminismTesterOutput::init(ConfigInterface& config) +{ +} + +/** + * @brief Construct a new DeterminismTesterOutput module + * + * @param name + */ +DeterminismTesterOutput::DeterminismTesterOutput(std::string name): + OutputModule(name) +{ + count = 0; +} + +/** + * @brief Destructor + * + */ +DeterminismTesterOutput::~DeterminismTesterOutput() +{ + +} + +/** + * @brief Registers the keys and tags for this module + * This module needs to read: + * "TEST_CASE": the test case for a module + * + * @param registry + */ +void DeterminismTesterOutput::registerStorageNeeds(StorageRegistry& registry) +{ + testCaseKey = registry.registerKey("TEST_CASE", StorageRegistry::BUFFER, StorageRegistry::READ_ONLY); +} + +/** + * @brief Writes all of the new entries with the "CRASHED" tag to disk + * + * Only the binary test case is written to disk + * + * @param storage + */ +void DeterminismTesterOutput::run(StorageModule& storage) +{ + std::unique_ptr interestingEntries = storage.getNewEntriesThatWillBeSaved(); + while(interestingEntries->hasNext()) + { + StorageEntry* entry = interestingEntries->getNext(); + + int size = entry->getBufferSize(testCaseKey); + char* buffer = entry->getBufferPointer(testCaseKey); + unsigned long id = entry->getID(); + + // New checksum calculation, plan to move to separate output module + count++; + checksum ^= VmfUtil::hashBuffer(buffer, size); + checksum ^= id * count; + if (count % 10 == 0) + { + LOG_INFO << "Checksum " << count << " = " << checksum; + } + } +} + +void DeterminismTesterOutput::shutdown(StorageModule& storage) +{ + LOG_INFO << "Checksum " << count << " = " << checksum; +} diff --git a/Determinism/vmf/src/modules/common/output/DeterminismTesterOutput.hpp b/Determinism/vmf/src/modules/common/output/DeterminismTesterOutput.hpp new file mode 100644 index 0000000..e536b59 --- /dev/null +++ b/Determinism/vmf/src/modules/common/output/DeterminismTesterOutput.hpp @@ -0,0 +1,48 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2025 The Charles Stark Draper Laboratory, Inc. + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "OutputModule.hpp" + +namespace vmf +{ +/** + * @brief Output module that computes a hash of fuzzer's created testcases for determinism validation. + * + */ +class DeterminismTesterOutput : public OutputModule { +public: + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + DeterminismTesterOutput(std::string name); + virtual ~DeterminismTesterOutput(); + + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void run(StorageModule& storage); + virtual void shutdown(StorageModule& storage); + +private: + + int count; + int testCaseKey; + size_t checksum = 0; +}; +} diff --git a/README.md b/README.md index 35bf5ff..3383be2 100644 --- a/README.md +++ b/README.md @@ -18,20 +18,19 @@ VaderModularFuzzer repository: |-- data |-- docs |-- test - |-- vmf/src/modules - |-- common + |-- vmf/src/modules/common |-- mutator - |-- output - |-- submodules ``` ## Building and installing experimental module packages + VMF is built using CMake -Building the Experimental repository also requires an installed instance of VMF. It may be installed -in a public location like `/usr/local/vmf` or in the default location within a VMF source tree like +Building the Experimental repository also requires an installed instance of VMF. It must be installed in the default location within a VMF source tree, like `/home/userdir/VaderModularFuzzer/build/vmf_install`. Specify the full path to the VMF install using -`-DVMF_INSTALL=/path/to/VMF`. +`-DCMAKE_INSTALL_PREFIX=/path/to/VMF`. + +### Linux Execute the following commands to build the VMF experimental modules: @@ -39,9 +38,31 @@ Execute the following commands to build the VMF experimental modules: # from the top VmfExperimental directory: mkdir build cd build -cmake -DVMF_INSTALL= .. && make +cmake -DCMAKE_INSTALL_PREFIX= .. && make ``` +### Windows + +Run the Developer Command Prompt for Visual Studio (e.g. "Developer Command Prompt VS 2022"), and +navigate to the VMF directory. Then execute the following commands to generation a solution file +for VMF. The exact version of visual studio must be specified in the final command -- here we +specify Visual Studio 2022 Version 17.x. Use `cmake --help` to see additional generation options. + +*Note: The -DCMAKE_INSTALL_PREFIX may be used to optionally specify an install location other than +the default VMF in-tree install location (build\vmf_install).* + +```powershell +#from \path\to\vmf directory +mkdir build +cd build +cmake -G "Visual Studio 17 2022" .. +#Or optionally use this version instead to specify an install path +#cmake -G "Visual Studio 17 2022" -DCMAKE_INSTALL_PREFIX= .. +cmake --build . --target INSTALL --config Release +``` +You may alternatively open the VmfExtension.sln file that has been generated in the build directory +and build the INSTALL target in the GUI. + ### Installing experimental modules The VMF experimental modules library must be installed in a VMF plugins directory, either the default @@ -82,3 +103,9 @@ To build and run ```bash cmake -DVMF_INSTALL= .. && make -j8 && ctest ``` + +### Running the Unit Tests (Docker) +From the VmfExperimental Directory on the HOS, run the following command via Bash / Powershell 7+ +```powershell +docker build -t vmfexp -f ./dockerfiles/Dockerfile . && docker run --rm vmfexp +``` diff --git a/Radamsa/CMakeLists.txt b/Radamsa/CMakeLists.txt new file mode 100644 index 0000000..094f971 --- /dev/null +++ b/Radamsa/CMakeLists.txt @@ -0,0 +1,30 @@ +#=============================================================================== +# Vader Modular Fuzzer (VMF) +# Copyright (c) 2021-2025 The Charles Stark Draper Laboratory, Inc. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 (only) as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# @license GPL-2.0-only +#=============================================================================== + +add_subdirectory(vmf/src) + +#install sample configuration files +install(DIRECTORY test DESTINATION + DESTINATION ${CMAKE_INSTALL_PREFIX} + PATTERN "*.cpp" EXCLUDE + PATTERN "*.h" EXCLUDE + PATTERN "README.md" EXCLUDE +) + diff --git a/Radamsa/test/RadamsaAsciiBadMutatorTest.cpp b/Radamsa/test/RadamsaAsciiBadMutatorTest.cpp new file mode 100644 index 0000000..554a9b0 --- /dev/null +++ b/Radamsa/test/RadamsaAsciiBadMutatorTest.cpp @@ -0,0 +1,231 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaAsciiBadMutator.hpp" +#include "RuntimeException.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaAsciiBadMutator; +using vmf::BaseException; +using vmf::RuntimeException; +using std::string; + +class RadamsaAsciiBadMutatorTest : public ::testing::Test { + protected: + RadamsaAsciiBadMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; + + RadamsaAsciiBadMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaAsciiBadMutator("RadamsaAsciiBadMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaAsciiBadMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + // int_key = registry->registerKey( + // "TEST_INT", + // StorageRegistry::INT, + // StorageRegistry::READ_WRITE + // ); + // normalTag = registry->registerTag( + // "RAN_SUCCESSFULLY", + // StorageRegistry::WRITE_ONLY + // ); + // // registry->validateRegistration(); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } +}; + +/* NOTE: + * Due to the shear amount of cases here, + * and the fact that we can't currently control values + * returned by VmfRand, content tests will be simplified. + */ + +/*TEST_F(RadamsaAsciiBadMutatorTest, BufferNotNull) +{ + // no way to test this without mocks +}*/ + +TEST_F(RadamsaAsciiBadMutatorTest, FiveBytesPrintable) +{ + string buffString = "ghijk"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaAsciiBadMutatorTest, SixBytesMixed) +{ + string buffString = "ghijkl"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + buff[3] = 127; // non-printable ascii + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaAsciiBadMutatorTest, SixBytesPrintable) +{ + string buffString = "ghijkl"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + string modString = string(modBuff); + + EXPECT_GE(modBuff_len - 1, 2); // min length is a single 2B string from sillyStrings + EXPECT_LE(modBuff_len - 1, buff_len + 65536); // max length is appending max number of newlines + EXPECT_EQ(modBuff[modBuff_len - 1], '\0'); + // Content tests would go here +} + +TEST_F(RadamsaAsciiBadMutatorTest, TwoChunks) +{ + string buffString = "ghijkl4mn"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + buff[6] = 127; // non-printable ascii + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + string modString = string(modBuff); + + EXPECT_GE(modBuff_len - 1, 2); // min length is a single 2B string from sillyStrings + EXPECT_LE(modBuff_len - 1, buff_len + 65536); // max length is appending max number of newlines + EXPECT_EQ(modBuff[modBuff_len - 1], '\0'); + // Content tests would go here +} diff --git a/Radamsa/test/RadamsaDeleteByteSequenceMutatorTest.cpp b/Radamsa/test/RadamsaDeleteByteSequenceMutatorTest.cpp new file mode 100644 index 0000000..0af62a0 --- /dev/null +++ b/Radamsa/test/RadamsaDeleteByteSequenceMutatorTest.cpp @@ -0,0 +1,242 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaDeleteByteSequenceMutator.hpp" +#include "RuntimeException.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaDeleteByteSequenceMutator; +using vmf::BaseException; +using vmf::RuntimeException; + +class RadamsaDeleteByteSequenceMutatorTest : public ::testing::Test { + protected: + RadamsaDeleteByteSequenceMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaDeleteByteSequenceMutator("RadamsaDeleteByteSequenceMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaDeleteByteSequenceMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + // int_key = registry->registerKey( + // "TEST_INT", + // StorageRegistry::INT, + // StorageRegistry::READ_WRITE + // ); + // normalTag = registry->registerTag( + // "RAN_SUCCESSFULLY", + // StorageRegistry::WRITE_ONLY + // ); + // // registry->validateRegistration(); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } + + RadamsaDeleteByteSequenceMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; +}; + +/*TEST_F(RadamsaDeleteByteSequenceMutatorTest, BufferNotNull) +{ + // no way to test this without mocks +}*/ + +TEST_F(RadamsaDeleteByteSequenceMutatorTest, BufferSizeGEOne) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + // char* buff = baseEntry->allocateBuffer(testCaseKey, 1); + /* By not allocating the buffer, we're forcing + StorageEntry::getBufferSize() to return '-1'. + */ + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaDeleteByteSequenceMutatorTest, BufferSizeGETwo) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + size_t buff_len = 1; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaDeleteByteSequenceMutatorTest, TwoBytes) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + const size_t buff_len = 2; + char* modBuff; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + buff[1] = '5'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + size_t occ[buff_len] = {}; + + for(size_t i = 0; i < modBuff_len; ++i) { + if(modBuff[i] == '4') { + occ[0]++; + } + else if(modBuff[i] == '5') { + occ[1]++; + } + } + + // test buff ne + // ASSERT_FALSE(std::equal(buff, buff + buff_len, + // modBuff, modBuff + modBuff_len - 1) + // ); + // test buff len + EXPECT_LT(modBuff_len, buff_len + 1); + // test buff contents + EXPECT_LT(occ[0], 2); + EXPECT_LT(occ[1], 2); + EXPECT_FALSE(occ[0] == 1 && occ[1] == 1); +} + +TEST_F(RadamsaDeleteByteSequenceMutatorTest, ThreeBytes) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + const size_t buff_len = 3; + char* modBuff; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + buff[1] = '5'; + buff[2] = '6'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + size_t occ[buff_len] = {}; + + for(size_t i = 0; i < modBuff_len; ++i) { + if(modBuff[i] == '4') { + occ[0]++; + } + else if(modBuff[i] == '5') { + occ[1]++; + } + else if(modBuff[i] == '6') { + occ[2]++; + } + } + + // test buff ne + // ASSERT_FALSE(std::equal(buff, buff + buff_len, + // modBuff, modBuff + modBuff_len - 1) + // ); + // test buff len + EXPECT_LT(modBuff_len, buff_len + 1); + // test buff contents + EXPECT_LT(occ[0], 2); + EXPECT_LT(occ[1], 2); + EXPECT_LT(occ[2], 2); + EXPECT_FALSE(occ[0] == 1 && occ[1] == 1 && occ[2] == 1); +} diff --git a/Radamsa/test/RadamsaDeleteLineMutatorTest.cpp b/Radamsa/test/RadamsaDeleteLineMutatorTest.cpp index 8de543e..39ad5fd 100644 --- a/Radamsa/test/RadamsaDeleteLineMutatorTest.cpp +++ b/Radamsa/test/RadamsaDeleteLineMutatorTest.cpp @@ -147,12 +147,12 @@ TEST_F(RadamsaDeleteLineMutatorTest, OneLine) std::string modString = std::string(modBuff); size_t modBuff_len = modEntry->getBufferSize(testCaseKey); - EXPECT_FALSE(std::equal(buff, buff + buff_len, - modBuff, modBuff + modBuff_len - 1) - ) << "Modified buffer must not be equal to original buffer"; + // EXPECT_FALSE(std::equal(buff, buff + buff_len, + // modBuff, modBuff + modBuff_len - 1) + // ) << "Modified buffer must not be equal to original buffer"; EXPECT_EQ(buff_len / line_len - 1, - std::count(modBuff, modBuff + buff_len, '\n') + std::count(modBuff, modBuff + modBuff_len, '\n') ) << "Number of lines in modified buffer must be one less than those in the original buffer"; EXPECT_EQ(buff_len - line_len + 1, modBuff_len diff --git a/Radamsa/test/RadamsaDeleteNodeMutatorTest.cpp b/Radamsa/test/RadamsaDeleteNodeMutatorTest.cpp new file mode 100644 index 0000000..f9d77f0 --- /dev/null +++ b/Radamsa/test/RadamsaDeleteNodeMutatorTest.cpp @@ -0,0 +1,270 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaDeleteNodeMutator.hpp" +#include "RuntimeException.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaDeleteNodeMutator; +using vmf::BaseException; +using vmf::RuntimeException; + +class RadamsaDeleteNodeMutatorTest : public ::testing::Test { + protected: + RadamsaDeleteNodeMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaDeleteNodeMutator("RadamsaDeleteNodeMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaDeleteNodeMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + // int_key = registry->registerKey( + // "TEST_INT", + // StorageRegistry::INT, + // StorageRegistry::READ_WRITE + // ); + // normalTag = registry->registerTag( + // "RAN_SUCCESSFULLY", + // StorageRegistry::WRITE_ONLY + // ); + // // registry->validateRegistration(); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } + + RadamsaDeleteNodeMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; +}; + +/*TEST_F(RadamsaDeleteNodeMutatorTest, BufferNotNull) +{ + // no way to test this without mocks +}*/ + +TEST_F(RadamsaDeleteNodeMutatorTest, ZeroBytes) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaDeleteNodeMutatorTest, JustRoot) +{ + std::string buffString = "G"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + + // test buff len + EXPECT_EQ(modBuff_len, buff_len + 1 - 1); + // test buff contents + EXPECT_EQ(modString[0], '\0'); +} + +TEST_F(RadamsaDeleteNodeMutatorTest, OneChild) +{ + std::string buffString = "GH(IJ)"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + + // test buff len + EXPECT_TRUE( + modBuff_len == buff_len + 1 - 2 || + modBuff_len == buff_len + 1 - 4 + ); + // test buff contents + EXPECT_TRUE( + modString == "\0" || + modString == "GH" + ); +} + +TEST_F(RadamsaDeleteNodeMutatorTest, TwoChildren) +{ + std::string buffString = "GH(IJ)(KL)"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + + // test buff len + EXPECT_TRUE( + modBuff_len == buff_len + 1 - 4 || + modBuff_len == 1 + ); + // test buff contents + EXPECT_TRUE( + modString == "GH(KL)" || + modString == "GH(IJ)" || + modString == "\0" + ); +} + +TEST_F(RadamsaDeleteNodeMutatorTest, TwoChildren_OneGrandchild) +{ + std::string buffString = "GH(IJ(KL))(MN)"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + + // test buff len + EXPECT_TRUE( + modBuff_len == buff_len + 1 - 4 || + modBuff_len == buff_len + 1 - 8 || + modBuff_len == 1 + ); + // test buff contents + EXPECT_TRUE( + modString == "GH(MN)" || // left child delete + modString == "GH(IJ(KL))" || // right child delete + modString == "GH(IJ)(MN)" || // grandchild delete + modString == "\0" // root delete + ); +} \ No newline at end of file diff --git a/Radamsa/test/RadamsaDuplicateNodeMutatorTest.cpp b/Radamsa/test/RadamsaDuplicateNodeMutatorTest.cpp new file mode 100644 index 0000000..33bf79d --- /dev/null +++ b/Radamsa/test/RadamsaDuplicateNodeMutatorTest.cpp @@ -0,0 +1,262 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaDuplicateNodeMutator.hpp" +#include "RuntimeException.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaDuplicateNodeMutator; +using vmf::BaseException; +using vmf::RuntimeException; + +class RadamsaDuplicateNodeMutatorTest : public ::testing::Test { + protected: + RadamsaDuplicateNodeMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaDuplicateNodeMutator("RadamsaDuplicateNodeMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaDuplicateNodeMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + // int_key = registry->registerKey( + // "TEST_INT", + // StorageRegistry::INT, + // StorageRegistry::READ_WRITE + // ); + // normalTag = registry->registerTag( + // "RAN_SUCCESSFULLY", + // StorageRegistry::WRITE_ONLY + // ); + // // registry->validateRegistration(); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } + + RadamsaDuplicateNodeMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; +}; + +/*TEST_F(RadamsaDuplicateNodeMutatorTest, BufferNotNull) +{ + // no way to test this without mocks +}*/ + +TEST_F(RadamsaDuplicateNodeMutatorTest, ThreeBytes) +{ + std::string buffString = "GHI"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaDuplicateNodeMutatorTest, JustRoot) +{ + std::string buffString = "GHIJ"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaDuplicateNodeMutatorTest, OneChild) +{ + std::string buffString = "GH(IJ)"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + + // test buff len + EXPECT_EQ(modBuff_len, buff_len + 4 + 1); + // test buff contents + EXPECT_EQ(modString, "GH(IJ)(IJ)\0"); +} + +TEST_F(RadamsaDuplicateNodeMutatorTest, TwoChildren) +{ + std::string buffString = "GH(IJ)(KL)"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + + // test buff len + EXPECT_EQ(modBuff_len, buff_len + 4 + 1); + // test buff contents + EXPECT_TRUE( + modString == "GH(IJ)(KL)(IJ)" || + modString == "GH(IJ)(KL)(KL)" + ); +} + +TEST_F(RadamsaDuplicateNodeMutatorTest, TwoChildren_OneGrandchild) +{ + std::string buffString = "GH(IJ(KL))(MN)"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + + // test buff len + EXPECT_TRUE( + modBuff_len == buff_len + 4 + 1 || + modBuff_len == buff_len + 2*4 + 1 + ); + // test buff contents + EXPECT_TRUE( + modString == "GH(IJ(KL))(MN)(IJ(KL))" || // left child duplicated + modString == "GH(IJ(KL))(MN)(MN)" || // right child duplicated + modString == "GH(IJ(KL)(KL))(MN)" // grandchild duplicated + ); +} \ No newline at end of file diff --git a/Radamsa/test/RadamsaFuseNextMutatorTest.cpp b/Radamsa/test/RadamsaFuseNextMutatorTest.cpp new file mode 100644 index 0000000..02f32a6 --- /dev/null +++ b/Radamsa/test/RadamsaFuseNextMutatorTest.cpp @@ -0,0 +1,194 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaFuseNextMutator.hpp" +#include "RuntimeException.hpp" +#include "RadamsaFuse_helpers.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaFuseNextMutator; +using vmf::BaseException; +using vmf::RuntimeException; +using std::string; + +class RadamsaFuseNextMutatorTest : public ::testing::Test { + protected: + RadamsaFuseNextMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; + + RadamsaFuseNextMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaFuseNextMutator("RadamsaFuseNextMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaFuseNextMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + // int_key = registry->registerKey( + // "TEST_INT", + // StorageRegistry::INT, + // StorageRegistry::READ_WRITE + // ); + // normalTag = registry->registerTag( + // "RAN_SUCCESSFULLY", + // StorageRegistry::WRITE_ONLY + // ); + // // registry->validateRegistration(); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } +}; + +/*TEST_F(RadamsaFuseNextMutatorTest, BufferNotNull) +{ + // no way to test this without mocks +}*/ + +TEST_F(RadamsaFuseNextMutatorTest, OneByte) +{ + std::string buffString = "g"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaFuseNextMutatorTest, TwoBytes) +{ + string buffString = "gh"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + string modString = string(modBuff); + + // Not testing modBuff_len value, because result can be lt, gt, or equal to buff_len + EXPECT_EQ(modBuff[modBuff_len - 1], '\0'); + ASSERT_PRED2(isSubset, modString, buffString); + EXPECT_PRED2(isValidTripleFuse, modString, buffString); +} + +TEST_F(RadamsaFuseNextMutatorTest, TenBytes) +{ + string buffString = "ghijklmnop"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + string modString = string(modBuff); + + // Not testing modBuff_len value, because result can be lt, gt, or equal to buff_len + EXPECT_EQ(modBuff[modBuff_len - 1], '\0'); + ASSERT_PRED2(isSubset, modString, buffString); + EXPECT_PRED2(isValidTripleFuse, modString, buffString); +} \ No newline at end of file diff --git a/Radamsa/test/RadamsaFuseOldMutatorTest.cpp b/Radamsa/test/RadamsaFuseOldMutatorTest.cpp new file mode 100644 index 0000000..feb4e51 --- /dev/null +++ b/Radamsa/test/RadamsaFuseOldMutatorTest.cpp @@ -0,0 +1,194 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaFuseOldMutator.hpp" +#include "RuntimeException.hpp" +#include "RadamsaFuse_helpers.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaFuseOldMutator; +using vmf::BaseException; +using vmf::RuntimeException; +using std::string; + +class RadamsaFuseOldMutatorTest : public ::testing::Test { + protected: + RadamsaFuseOldMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; + + RadamsaFuseOldMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaFuseOldMutator("RadamsaFuseOldMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaFuseOldMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + // int_key = registry->registerKey( + // "TEST_INT", + // StorageRegistry::INT, + // StorageRegistry::READ_WRITE + // ); + // normalTag = registry->registerTag( + // "RAN_SUCCESSFULLY", + // StorageRegistry::WRITE_ONLY + // ); + // // registry->validateRegistration(); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } +}; + +/*TEST_F(RadamsaFuseOldMutatorTest, BufferNotNull) +{ + // no way to test this without mocks +}*/ + +TEST_F(RadamsaFuseOldMutatorTest, OneByte) +{ + std::string buffString = "g"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaFuseOldMutatorTest, TwoBytes) +{ + string buffString = "gh"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + string modString = string(modBuff); + + // Not testing modBuff_len value, because result can be lt, gt, or equal to buff_len + EXPECT_EQ(modBuff[modBuff_len - 1], '\0'); + ASSERT_PRED2(isSubset, modString, buffString); + EXPECT_PRED2(isValidDoubleFuse, modString, buffString); +} + +TEST_F(RadamsaFuseOldMutatorTest, TenBytes) +{ + string buffString = "ghijklmnop"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + string modString = string(modBuff); + + // Not testing modBuff_len value, because result can be lt, gt, or equal to buff_len + EXPECT_EQ(modBuff[modBuff_len - 1], '\0'); + ASSERT_PRED2(isSubset, modString, buffString); + EXPECT_PRED2(isValidDoubleFuse, modString, buffString); +} \ No newline at end of file diff --git a/Radamsa/test/RadamsaFuseThisMutatorTest.cpp b/Radamsa/test/RadamsaFuseThisMutatorTest.cpp new file mode 100644 index 0000000..858b271 --- /dev/null +++ b/Radamsa/test/RadamsaFuseThisMutatorTest.cpp @@ -0,0 +1,198 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaFuseThisMutator.hpp" +#include "RuntimeException.hpp" +#include "RadamsaFuse_helpers.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaFuseThisMutator; +using vmf::BaseException; +using vmf::RuntimeException; +using std::string; + +class RadamsaFuseThisMutatorTest : public ::testing::Test { + protected: + RadamsaFuseThisMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; + + RadamsaFuseThisMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaFuseThisMutator("RadamsaFuseThisMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaFuseThisMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + // int_key = registry->registerKey( + // "TEST_INT", + // StorageRegistry::INT, + // StorageRegistry::READ_WRITE + // ); + // normalTag = registry->registerTag( + // "RAN_SUCCESSFULLY", + // StorageRegistry::WRITE_ONLY + // ); + // // registry->validateRegistration(); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } +}; + +/*TEST_F(RadamsaFuseThisMutatorTest, BufferNotNull) +{ + // no way to test this without mocks +}*/ + +TEST_F(RadamsaFuseThisMutatorTest, OneByte) +{ + string buffString = "g"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + string modString = string(modBuff); + + // Not testing modBuff_len value, because result can be lt, gt, or equal to buff_len + EXPECT_EQ(modBuff[modBuff_len - 1], '\0'); + ASSERT_PRED2(isSubset, modString, buffString); + EXPECT_PRED2(isValidSelfFuse, modString, buffString); +} + +TEST_F(RadamsaFuseThisMutatorTest, TwoBytes) +{ + string buffString = "gh"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + string modString = string(modBuff); + + // Not testing modBuff_len value, because result can be lt, gt, or equal to buff_len + EXPECT_EQ(modBuff[modBuff_len - 1], '\0'); + ASSERT_PRED2(isSubset, modString, buffString); + EXPECT_PRED2(isValidSelfFuse, modString, buffString); +} + +TEST_F(RadamsaFuseThisMutatorTest, TenBytes) +{ + string buffString = "ghijklmnop"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + string modString = string(modBuff); + + // Not testing modBuff_len value, because result can be lt, gt, or equal to buff_len + EXPECT_EQ(modBuff[modBuff_len - 1], '\0'); + ASSERT_PRED2(isSubset, modString, buffString); + EXPECT_PRED2(isValidSelfFuse, modString, buffString); +} \ No newline at end of file diff --git a/Radamsa/test/RadamsaFuse_helpers.cpp b/Radamsa/test/RadamsaFuse_helpers.cpp new file mode 100644 index 0000000..a56eecc --- /dev/null +++ b/Radamsa/test/RadamsaFuse_helpers.cpp @@ -0,0 +1,131 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "RadamsaFuse_helpers.hpp" + +using std::string; +using std::vector; + +bool isSubset(const string& mod, const string& buff) { + for (char c : mod) { + if (buff.find(c) == string::npos) return false; + } + return true; +} + +bool isValidSelfFuse(const string& mod, const string& buff) { + // Returns true if you can combine two substrings of buffString to get modString + + for (size_t i = 0; i < buff.size(); ++i) { + for(size_t j = 0; j < buff.size(); ++j) { + const string prefix = buff.substr(0, i); + const string suffix = buff.substr(j); // j to end of buffString + const string fusion = prefix + suffix; + if (mod == fusion) return true; + } + } + return false; +} + +vector getPrefixes(const string& data) { + vector prefixes; + for (size_t i = 0; i < data.size(); ++i) { + prefixes.push_back(data.substr(0, i)); + } + return prefixes; +} + +vector getSuffixes(const string& data) { + vector suffixes; + for (size_t i = 0; i < data.size(); ++i) { + suffixes.push_back(data.substr(i)); + } + return suffixes; +} + +bool isValidDoubleFuse(const string& mod, const string& buff) { + const size_t midpoint = buff.length() / 2; + const string buff_firstHalf = buff.substr(0, midpoint); + const string buff_secondHalf = buff.substr(midpoint); + + const vector buff_firstHalf_prefixes = getPrefixes(buff_firstHalf); + const vector buff_secondHalf_suffixes = getSuffixes(buff_secondHalf); + + vector fusions; + for (string prefix : buff_firstHalf_prefixes) { + for (string suffix : buff_secondHalf_suffixes) { + fusions.push_back(prefix + suffix); + } + } + + for (string fusionA : fusions) { + for (string fusionB : fusions) { + string doubleFusion = fusionA + fusionB; + if (mod == doubleFusion) return true; + } + } + return false; +} + +bool isValidTripleFuse(const string& mod, const string& buff) { + // returns true if modString is a form of: prefix(prefix(buffer_firstHalf) + suffix(buffer)) + suffix(buffer_secondHalf) + + const size_t midpoint = buff.length() / 2; + const string buff_firstHalf = buff.substr(0, midpoint); + const string buff_secondHalf = buff.substr(midpoint); + + const vector buff_firstHalf_prefixes = getPrefixes(buff_firstHalf); + const vector buff_suffixes = getSuffixes(buff); + const vector buff_secondHalf_suffixes = getSuffixes(buff_secondHalf); + + vector ab_fusions; + for (string prefix : buff_firstHalf_prefixes) { + for (string suffix : buff_suffixes) { + ab_fusions.push_back(prefix + suffix); + } + } + + vector ab_fusions_prefixes; + for (string fusion : ab_fusions) { + vector fusion_prefixes = getPrefixes(fusion); + ab_fusions_prefixes.insert( + ab_fusions_prefixes.end(), + fusion_prefixes.begin(), + fusion_prefixes.end() + ); + } + + for (string prefix : ab_fusions_prefixes) { + for (string suffix : buff_secondHalf_suffixes) { + string fusion = prefix + suffix; + if (mod == fusion) return true; + } + } + return false; +} diff --git a/Radamsa/test/RadamsaFuse_helpers.hpp b/Radamsa/test/RadamsaFuse_helpers.hpp new file mode 100644 index 0000000..6cc3885 --- /dev/null +++ b/Radamsa/test/RadamsaFuse_helpers.hpp @@ -0,0 +1,39 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#pragma once +#include +#include + +using std::string; + +bool isSubset(const string& modString, const string& buffString); +bool isValidSelfFuse(const string& modString, const string& buffString); +bool isValidDoubleFuse(const string& modString, const string& buffString); +bool isValidTripleFuse(const string& modString, const string& buffString); diff --git a/Radamsa/test/RadamsaInsertLineMutatorTest.cpp b/Radamsa/test/RadamsaInsertLineMutatorTest.cpp new file mode 100644 index 0000000..624938f --- /dev/null +++ b/Radamsa/test/RadamsaInsertLineMutatorTest.cpp @@ -0,0 +1,243 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaInsertLineMutator.hpp" +#include "RuntimeException.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaInsertLineMutator; +using vmf::BaseException; +using vmf::RuntimeException; + +class RadamsaInsertLineMutatorTest : public ::testing::Test { + protected: + RadamsaInsertLineMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaInsertLineMutator("RadamsaInsertLineMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaInsertLineMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + // int_key = registry->registerKey( + // "TEST_INT", + // StorageRegistry::INT, + // StorageRegistry::READ_WRITE + // ); + // normalTag = registry->registerTag( + // "RAN_SUCCESSFULLY", + // StorageRegistry::WRITE_ONLY + // ); + // // registry->validateRegistration(); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } + + RadamsaInsertLineMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; +}; + +/*TEST_F(RadamsaInsertLineMutatorTest, BufferNotNull) +{ + // no way to test this without mocks +}*/ + +TEST_F(RadamsaInsertLineMutatorTest, OneByte) +{ + std::string buffString = "\n"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaInsertLineMutatorTest, OneLine) +{ + std::string buffString = "G\n"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaInsertLineMutatorTest, TwoLines) +{ + std::string buffString = "GHI\nJK\n"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + + // test buff ne + // ASSERT_FALSE(std::equal(buff, buff + buff_len, + // modBuff, modBuff + modBuff_len - 1) + // ); + // test buff len + EXPECT_GT(modBuff_len, buff_len + 1); + // test buff contents + EXPECT_TRUE( + modString == "GHI\nGHI\nJK\n" || // 112 + modString == "GHI\nJK\nGHI\n" || // 121 + modString == "JK\nGHI\nJK\n" || // 212 + modString == "GHI\nJK\nJK\n" // 122 + ) << "modString = \"" + modString + "\""; +} + +TEST_F(RadamsaInsertLineMutatorTest, ThreeLines) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + std::string buffString = "GHI\nJK\nL\n"; + const size_t buff_len = buffString.length(); + char* modBuff; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason() << std::endl << "buff_len = " + std::to_string(buff_len); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + + // test buff ne + // ASSERT_FALSE(std::equal(buff, buff + buff_len, + // modBuff, modBuff + modBuff_len - 1) + // ); + // test buff len + EXPECT_GT(modBuff_len, buff_len + 1); + EXPECT_TRUE( + modString == "GHI\nGHI\nJK\nL\n" || // 1123 + modString == "GHI\nJK\nGHI\nL\n" || // 1213 + modString == "GHI\nJK\nL\nGHI\n" || // 1231 + + modString == "JK\nGHI\nJK\nL\n" || // 2123 + modString == "GHI\nJK\nJK\nL\n" || // 1223 + modString == "GHI\nJK\nL\nJK\n" || // 1232 + + modString == "L\nGHI\nJK\nL\n" || // 3123 + modString == "GHI\nL\nJK\nL\n" || // 1323 + modString == "GHI\nJK\nL\nL\n" // 1233 + ) << "modString = \"" + modString + "\""; +} \ No newline at end of file diff --git a/Radamsa/test/RadamsaInsertUnicodeMutatorTest.cpp b/Radamsa/test/RadamsaInsertUnicodeMutatorTest.cpp new file mode 100644 index 0000000..e93d3a1 --- /dev/null +++ b/Radamsa/test/RadamsaInsertUnicodeMutatorTest.cpp @@ -0,0 +1,176 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaInsertUnicodeMutator.hpp" +#include "RuntimeException.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaInsertUnicodeMutator; +using vmf::BaseException; +using vmf::RuntimeException; + +class RadamsaInsertUnicodeMutatorTest : public ::testing::Test { + protected: + RadamsaInsertUnicodeMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaInsertUnicodeMutator("RadamsaInsertUnicodeMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaInsertUnicodeMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + // int_key = registry->registerKey( + // "TEST_INT", + // StorageRegistry::INT, + // StorageRegistry::READ_WRITE + // ); + // normalTag = registry->registerTag( + // "RAN_SUCCESSFULLY", + // StorageRegistry::WRITE_ONLY + // ); + // // registry->validateRegistration(); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } + + RadamsaInsertUnicodeMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; +}; + +/* NOTE + * Due to the shear amount of cases added by funnyUnicode, + * and the fact that we can't currently control values + * returned by VmfRand, these tests will be simplified. + */ + +/*TEST_F(RadamsaInsertUnicodeMutatorTest, BufferNotNull) +{ + // no way to test this without mocks +}*/ + +TEST_F(RadamsaInsertUnicodeMutatorTest, OneByte) +{ + std::string buffString = "g"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + + EXPECT_GT(modBuff_len, buff_len + 1); + EXPECT_TRUE( + modBuff[0] == buff[0] || + modBuff[modBuff_len - 2] == buff[0] + ) << "modBuff[0]: " + std::to_string(modBuff[0]) + + ", modBuff[modBuff_len - 2]: " + std::to_string(modBuff[modBuff_len - 2]); +} + +TEST_F(RadamsaInsertUnicodeMutatorTest, TwoBytes) +{ + std::string buffString = "gh"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + + EXPECT_GT(modBuff_len, buff_len + 1); + if (modBuff[0] == buff[0]) { // "ghFOO" or "gFOOh" + EXPECT_TRUE( + modBuff[1] == buff[1] || + modBuff[modBuff_len - 2] == buff[1] + ) << "modBuff[1]: " + std::to_string(modBuff[1]) + + ", modBuff[modBuff_len - 2]: " + std::to_string(modBuff[modBuff_len - 2]); + } + else { // "FOOgh" + EXPECT_EQ(modBuff[modBuff_len - 2], buff[buff_len - 1]); + EXPECT_EQ(modBuff[modBuff_len - 3], buff[buff_len - 2]); + } +} \ No newline at end of file diff --git a/Radamsa/test/RadamsaModifyTextNumberMutatorTest.cpp b/Radamsa/test/RadamsaModifyTextNumberMutatorTest.cpp new file mode 100644 index 0000000..8abff99 --- /dev/null +++ b/Radamsa/test/RadamsaModifyTextNumberMutatorTest.cpp @@ -0,0 +1,227 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaModifyTextNumberMutator.hpp" +#include "RuntimeException.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaModifyTextNumberMutator; +using vmf::BaseException; +using vmf::RuntimeException; + +class RadamsaModifyTextNumberMutatorTest : public ::testing::Test { + protected: + RadamsaModifyTextNumberMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaModifyTextNumberMutator("RadamsaModifyTextNumberMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaModifyTextNumberMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + // int_key = registry->registerKey( + // "TEST_INT", + // StorageRegistry::INT, + // StorageRegistry::READ_WRITE + // ); + // normalTag = registry->registerTag( + // "RAN_SUCCESSFULLY", + // StorageRegistry::WRITE_ONLY + // ); + // // registry->validateRegistration(); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } + + RadamsaModifyTextNumberMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; +}; + +/* NOTE: + * Due to the shear amount of cases here, + * and the fact that we can't currently control values + * returned by VmfRand, content tests will be simplified. + */ + +/*TEST_F(RadamsaModifyTextNumberMutatorTest, BufferNotNull) +{ + // no way to test this without mocks +}*/ + +TEST_F(RadamsaModifyTextNumberMutatorTest, NoNumbers) +{ + std::string buffString = "ghi"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaModifyTextNumberMutatorTest, OneSingleDigitNumber) +{ + std::string buffString = "gh4i"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + + ASSERT_NE(modString[2], buffString[2]); + EXPECT_GE(modBuff_len, buff_len + 1); +} + +TEST_F(RadamsaModifyTextNumberMutatorTest, OneMultiDigitNumber) +{ + std::string buffString = "gh45i"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + + ASSERT_NE(modString.substr(2, 2), buffString.substr(2, 2)); + EXPECT_GE(modBuff_len, buff_len + 1); +} + +TEST_F(RadamsaModifyTextNumberMutatorTest, TwoMultiDigitNumbers) +{ + std::string buffString = "g45h67i"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + + ASSERT_TRUE( + modString.substr(1, 2) != buffString.substr(1, 2) || + modString.substr(4, 2) != buffString.substr(4, 2) + ) << "modString: " + modString + ", buffString: " + buffString; + EXPECT_GE(modBuff_len, buff_len + 1); +} \ No newline at end of file diff --git a/Radamsa/test/RadamsaPermuteLinesMutatorTest.cpp b/Radamsa/test/RadamsaPermuteLinesMutatorTest.cpp new file mode 100644 index 0000000..4558dc2 --- /dev/null +++ b/Radamsa/test/RadamsaPermuteLinesMutatorTest.cpp @@ -0,0 +1,193 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaPermuteLinesMutator.hpp" +#include "RuntimeException.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaPermuteLinesMutator; +using vmf::BaseException; +using vmf::RuntimeException; + +class RadamsaPermuteLinesMutatorTest : public ::testing::Test { + protected: + RadamsaPermuteLinesMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaPermuteLinesMutator("RadamsaPermuteLinesMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaPermuteLinesMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + // int_key = registry->registerKey( + // "TEST_INT", + // StorageRegistry::INT, + // StorageRegistry::READ_WRITE + // ); + // normalTag = registry->registerTag( + // "RAN_SUCCESSFULLY", + // StorageRegistry::WRITE_ONLY + // ); + // // registry->validateRegistration(); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } + + RadamsaPermuteLinesMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; +}; + +/*TEST_F(RadamsaPermuteLinesMutatorTest, BufferNotNull) +{ + // no way to test this without mocks +}*/ + +TEST_F(RadamsaPermuteLinesMutatorTest, TwoBytes) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + size_t buff_len = 2; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = 'G'; + buff[1] = 'H'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaPermuteLinesMutatorTest, TwoLines) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + size_t buff_len = 4; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = 'G'; + buff[1] = '\n'; + buff[2] = 'H'; + buff[3] = '\n'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaPermuteLinesMutatorTest, ThreeLines) +{ + // GTEST_SKIP() << "Not yet implemented"; //TODO + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + std::string buffString = "GHI\nJK\nL\n"; + const size_t buff_len = buffString.length(); + char* modBuff; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason() << std::endl << "buff_len = " + std::to_string(buff_len); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + + // test buff ne + // ASSERT_FALSE(std::equal(buff, buff + buff_len, + // modBuff, modBuff + modBuff_len - 1) + // ); + // test buff len + EXPECT_EQ(modBuff_len, buff_len + 1); + // test buff contents + EXPECT_TRUE( + modString == "GHI\nJK\nL\n" || // 123 + modString == "GHI\nL\nJK\n" || // 132 + modString == "JK\nGHI\nL\n" || // 213 + modString == "JK\nL\nGHI\n" || // 231 + modString == "L\nGHI\nJK\n" || // 312 + modString == "L\nJK\nGHI\n" // 321 + ) << "modString = \"" + modString + "\""; +} diff --git a/Radamsa/test/RadamsaRepeatByteMutatorTest.cpp b/Radamsa/test/RadamsaRepeatByteMutatorTest.cpp index 84d8bfe..933e976 100644 --- a/Radamsa/test/RadamsaRepeatByteMutatorTest.cpp +++ b/Radamsa/test/RadamsaRepeatByteMutatorTest.cpp @@ -31,6 +31,7 @@ #include "ModuleTestHelper.hpp" #include "SimpleStorage.hpp" #include "RadamsaRepeatByteMutator.hpp" +#include "RuntimeException.hpp" using vmf::StorageModule; using vmf::StorageRegistry; @@ -40,6 +41,7 @@ using vmf::SimpleStorage; using vmf::StorageEntry; using vmf::RadamsaRepeatByteMutator; using vmf::BaseException; +using vmf::RuntimeException; class RadamsaRepeatByteMutatorTest : public ::testing::Test { protected: @@ -82,6 +84,35 @@ class RadamsaRepeatByteMutatorTest : public ::testing::Test { int testCaseKey; }; +/*TEST_F(RadamsaRepeatByteMutatorTest, BufferNotNull) +{ + // no way to test this without mocks +}*/ + +TEST_F(RadamsaRepeatByteMutatorTest, BufferSizeGEOne) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + // char* buff = baseEntry->allocateBuffer(testCaseKey, 1); + /* By not allocating the buffer, we're forcing + StorageEntry::getBufferSize() to return '-1'. + */ + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + TEST_F(RadamsaRepeatByteMutatorTest, TestOneByteRepeat) { StorageEntry* baseEntry = storage->createNewEntry(); @@ -108,8 +139,8 @@ TEST_F(RadamsaRepeatByteMutatorTest, TestOneByteRepeat) counter++; } - ASSERT_FALSE(std::equal(buff, buff + buff_len, - modBuff, modBuff + modEntry->getBufferSize(testCaseKey) - 1)); + // ASSERT_FALSE(std::equal(buff, buff + buff_len, + // modBuff, modBuff + modEntry->getBufferSize(testCaseKey) - 1)); EXPECT_GT(modBuff_len, buff_len + 1); EXPECT_EQ(modBuff_len - 1, counter); } diff --git a/Radamsa/test/RadamsaRepeatByteSequenceMutatorTest.cpp b/Radamsa/test/RadamsaRepeatByteSequenceMutatorTest.cpp new file mode 100644 index 0000000..869f509 --- /dev/null +++ b/Radamsa/test/RadamsaRepeatByteSequenceMutatorTest.cpp @@ -0,0 +1,241 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaRepeatByteSequenceMutator.hpp" +#include "RuntimeException.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaRepeatByteSequenceMutator; +using vmf::BaseException; +using vmf::RuntimeException; + +class RadamsaRepeatByteSequenceMutatorTest : public ::testing::Test { + protected: + RadamsaRepeatByteSequenceMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaRepeatByteSequenceMutator("RadamsaRepeatByteSequenceMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaRepeatByteSequenceMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + // int_key = registry->registerKey( + // "TEST_INT", + // StorageRegistry::INT, + // StorageRegistry::READ_WRITE + // ); + // normalTag = registry->registerTag( + // "RAN_SUCCESSFULLY", + // StorageRegistry::WRITE_ONLY + // ); + // // registry->validateRegistration(); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } + + RadamsaRepeatByteSequenceMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; +}; + +/*TEST_F(RadamsaRepeatByteSequenceMutatorTest, BufferNotNull) +{ + // no way to test this without mocks +}*/ + +TEST_F(RadamsaRepeatByteSequenceMutatorTest, BufferSizeGEOne) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + // char* buff = baseEntry->allocateBuffer(testCaseKey, 1); + /* By not allocating the buffer, we're forcing + StorageEntry::getBufferSize() to return '-1'. + */ + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaRepeatByteSequenceMutatorTest, BufferSizeGETwo) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + size_t buff_len = 1; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaRepeatByteSequenceMutatorTest, TwoBytes) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + const size_t buff_len = 2; + char* modBuff; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + buff[1] = '5'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + size_t occ[buff_len] = {}; + + for(size_t i = 0; i < modBuff_len; ++i) { + if(modBuff[i] == '4') { + occ[0]++; + } + else if(modBuff[i] == '5') { + occ[1]++; + } + } + + // test buff ne + // ASSERT_FALSE(std::equal(buff, buff + buff_len, + // modBuff, modBuff + modBuff_len - 1) + // ); + // test buff len (should be divisible by buff_len, with remainder for null-terminator) + EXPECT_EQ(modBuff_len % buff_len, 1); + // test buff contents + EXPECT_TRUE(occ[0] > 1 && occ[1] > 1 && occ[0] == occ[1]); +} + +TEST_F(RadamsaRepeatByteSequenceMutatorTest, ThreeBytes) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + const size_t buff_len = 3; + char* modBuff; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + buff[0] = '4'; + buff[1] = '5'; + buff[2] = '6'; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + size_t occ[buff_len] = {}; + + for(size_t i = 0; i < modBuff_len; ++i) { + if(modBuff[i] == '4') { + occ[0]++; + } + else if(modBuff[i] == '5') { + occ[1]++; + } + else if(modBuff[i] == '6') { + occ[2]++; + } + } + + // test buff ne + // ASSERT_FALSE(std::equal(buff, buff + buff_len, + // modBuff, modBuff + modBuff_len - 1) + // ); + // test buff len + EXPECT_TRUE(modBuff_len % 2 == 0 || modBuff_len % 3 == 1); + // test buff contents + EXPECT_TRUE( + (occ[0] > 1 && occ[1] > 1 && occ[2] == 1 && occ[1] == occ[2]) || // 45 repeated + (occ[0] == 1 && occ[1] > 1 && occ[2] > 1 && occ[1] == occ[2]) || // 56 repeated + (occ[0] > 1 && occ[1] > 1 && occ[2] > 1 && occ[0] == occ[1] && occ[1] == occ[2]) // 456 repeated + ); +} diff --git a/Radamsa/test/RadamsaRepeatPathMutatorTest.cpp b/Radamsa/test/RadamsaRepeatPathMutatorTest.cpp new file mode 100644 index 0000000..5f60677 --- /dev/null +++ b/Radamsa/test/RadamsaRepeatPathMutatorTest.cpp @@ -0,0 +1,299 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaRepeatPathMutator.hpp" +#include "RuntimeException.hpp" +#include "RadamsaTreeMutatorBase.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaRepeatPathMutator; +using vmf::BaseException; +using vmf::RuntimeException; +using vmf::RadamsaTreeMutatorBase; + +class RadamsaRepeatPathMutatorTest : public ::testing::Test { + protected: + RadamsaRepeatPathMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaRepeatPathMutator("RadamsaRepeatPathMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaRepeatPathMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + // int_key = registry->registerKey( + // "TEST_INT", + // StorageRegistry::INT, + // StorageRegistry::READ_WRITE + // ); + // normalTag = registry->registerTag( + // "RAN_SUCCESSFULLY", + // StorageRegistry::WRITE_ONLY + // ); + // // registry->validateRegistration(); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } + + RadamsaRepeatPathMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; +}; + +/*TEST_F(RadamsaRepeatPathMutatorTest, BufferNotNull) +{ + // no way to test this without mocks +}*/ + +TEST_F(RadamsaRepeatPathMutatorTest, ThreeBytes) +{ + std::string buffString = "GHI"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaRepeatPathMutatorTest, JustRoot) +{ + std::string buffString = "GHIJ"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaRepeatPathMutatorTest, OneChild) +{ + std::string buffString = "GH(IJ)"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + + char lastNodeChar = ')'; + for (size_t i = 1; lastNodeChar == ')'; ++i) { + lastNodeChar = modString[modString.length() - i]; + } + + ASSERT_FALSE( + std::equal( + buff, + buff + buff_len, + modBuff + ) + ); + EXPECT_EQ((modBuff_len - 1 - buff_len) % 4, 0); // 4 is the number of additional characters per repitition + EXPECT_EQ(lastNodeChar, 'J'); +} + +TEST_F(RadamsaRepeatPathMutatorTest, TwoChildren) +{ + std::string buffString = "GH(IJ)(KL)"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + + char lastNodeChar = ')'; + for (size_t i = 1; lastNodeChar == ')'; ++i) { + lastNodeChar = modString[modString.length() - i]; + } + + ASSERT_FALSE( + std::equal( + buff, + buff + buff_len, + modBuff + ) + ); + EXPECT_EQ((modBuff_len - 1 - buff_len) % 4, 0); // 4 is the number of additional characters per repitition + EXPECT_TRUE(lastNodeChar == 'J' || lastNodeChar == 'L'); +} + +TEST_F(RadamsaRepeatPathMutatorTest, TwoChildren_OneGrandchild) +{ + std::string buffString = "g(h(i))(j)"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + + std::map charFreqMap; + for (char c : modString) charFreqMap[c]++; + + ASSERT_FALSE( + std::equal( + buff, + buff + buff_len, + modBuff + ) + ); + EXPECT_EQ((modBuff_len - 1 - buff_len) % 3, 0); // 3 is the number of additional characters per repitition + EXPECT_TRUE( + ( // g replaced h + charFreqMap['g'] > 1 && + charFreqMap['h'] == 1 && + charFreqMap['i'] == 1 && + charFreqMap['j'] == 1 + ) || ( // h replaced i + charFreqMap['g'] == 1 && + charFreqMap['h'] > 1 && + charFreqMap['i'] == 1 && + charFreqMap['j'] == 1 + ) || ( // g replaced j + charFreqMap['g'] > 1 && + charFreqMap['h'] > 1 && + charFreqMap['i'] > 1 && + charFreqMap['j'] == 1 + ) + ) << "modString: " + modString; +} \ No newline at end of file diff --git a/Radamsa/test/RadamsaReplaceLineMutatorTest.cpp b/Radamsa/test/RadamsaReplaceLineMutatorTest.cpp new file mode 100644 index 0000000..01d6d65 --- /dev/null +++ b/Radamsa/test/RadamsaReplaceLineMutatorTest.cpp @@ -0,0 +1,236 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaReplaceLineMutator.hpp" +#include "RuntimeException.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaReplaceLineMutator; +using vmf::BaseException; +using vmf::RuntimeException; + +class RadamsaReplaceLineMutatorTest : public ::testing::Test { + protected: + RadamsaReplaceLineMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaReplaceLineMutator("RadamsaReplaceLineMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaReplaceLineMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + // int_key = registry->registerKey( + // "TEST_INT", + // StorageRegistry::INT, + // StorageRegistry::READ_WRITE + // ); + // normalTag = registry->registerTag( + // "RAN_SUCCESSFULLY", + // StorageRegistry::WRITE_ONLY + // ); + // // registry->validateRegistration(); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } + + RadamsaReplaceLineMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; +}; + +/*TEST_F(RadamsaReplaceLineMutatorTest, BufferNotNull) +{ + // no way to test this without mocks +}*/ + +TEST_F(RadamsaReplaceLineMutatorTest, OneByte) +{ + std::string buffString = "\n"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaReplaceLineMutatorTest, OneLine) +{ + std::string buffString = "G\n"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaReplaceLineMutatorTest, TwoLines) +{ + std::string buffString = "GHI\nJK\n"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + + // test buff ne + // ASSERT_FALSE(std::equal(buff, buff + buff_len, + // modBuff, modBuff + modBuff_len - 1) + // ); + // test buff len + EXPECT_GT(modBuff_len, buff_len + 1); + // test buff contents + EXPECT_TRUE( + modString == "GHI\nJK\n" || + modString == "JK\nGHI\n" + ) << "modString = \"" + modString + "\""; +} + +TEST_F(RadamsaReplaceLineMutatorTest, ThreeLines) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + + std::string buffString = "GHI\nJK\nL\n"; + const size_t buff_len = buffString.length(); + char* modBuff; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason() << std::endl << "buff_len = " + std::to_string(buff_len); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + + // test buff ne + // ASSERT_FALSE(std::equal(buff, buff + buff_len, + // modBuff, modBuff + modBuff_len - 1) + // ); + // test buff len + EXPECT_GT(modBuff_len, buff_len + 1); + // test buff contents + EXPECT_TRUE( + modString == "GHI\nJK\nL\n" || // 123 + modString == "JK\nGHI\nL\n" || // 213 + modString == "JK\nL\nGHI\n" || // 231 + modString == "GHI\nL\nJK\n" || // 132 + modString == "L\nGHI\nJK\n" // 312 + ) << "modString = \"" + modString + "\""; +} \ No newline at end of file diff --git a/Radamsa/test/RadamsaReplaceNodeMutatorTest.cpp b/Radamsa/test/RadamsaReplaceNodeMutatorTest.cpp new file mode 100644 index 0000000..0ee1b47 --- /dev/null +++ b/Radamsa/test/RadamsaReplaceNodeMutatorTest.cpp @@ -0,0 +1,277 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaReplaceNodeMutator.hpp" +#include "RuntimeException.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaReplaceNodeMutator; +using vmf::BaseException; +using vmf::RuntimeException; + +class RadamsaReplaceNodeMutatorTest : public ::testing::Test { + protected: + RadamsaReplaceNodeMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaReplaceNodeMutator("RadamsaReplaceNodeMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaReplaceNodeMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + // int_key = registry->registerKey( + // "TEST_INT", + // StorageRegistry::INT, + // StorageRegistry::READ_WRITE + // ); + // normalTag = registry->registerTag( + // "RAN_SUCCESSFULLY", + // StorageRegistry::WRITE_ONLY + // ); + // // registry->validateRegistration(); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } + + RadamsaReplaceNodeMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; +}; + +/*TEST_F(RadamsaReplaceNodeMutatorTest, BufferNotNull) +{ + // no way to test this without mocks +}*/ + +TEST_F(RadamsaReplaceNodeMutatorTest, ThreeBytes) +{ + std::string buffString = "GHI"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaReplaceNodeMutatorTest, JustRoot) +{ + std::string buffString = "GHIJ"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaReplaceNodeMutatorTest, OneChild) +{ + std::string buffString = "GH(IJ)"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + + // test buff len + EXPECT_EQ(modBuff_len, buff_len + 1); + // test buff contents + EXPECT_TRUE( + modString == "IJ(IJ)\0" || + modString == "GH(GH)\0" + ); +} + +TEST_F(RadamsaReplaceNodeMutatorTest, TwoChildren) +{ + std::string buffString = "GH(IJ)(KL)"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + + // test buff len + EXPECT_EQ(modBuff_len, buff_len + 1); + // test buff contents + EXPECT_TRUE( + modString == "GH(IJ)(KL)" || // toCopy == toReplace + modString == "GH(GH)(KL)" || // toCopy == root + modString == "GH(IJ)(GH)" || + modString == "IJ(IJ)(KL)" || // toCopy == left + modString == "GH(IJ)(IJ)" || + modString == "KL(IJ)(KL)" || // toCopy == right + modString == "GH(KL)(KL)" + ); +} + +TEST_F(RadamsaReplaceNodeMutatorTest, TwoChildren_OneGrandchild) +{ + std::string buffString = "GH(IJ(KL))(MN)"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + + // test buff len + EXPECT_EQ(modBuff_len, buff_len + 1); + // test buff contents + EXPECT_TRUE( + modString == "GH(IJ(KL))(MN)" || // toCopy == toReplace + modString == "GH(GH(KL))(MN)" || // toCopy == root + modString == "GH(IJ(GH))(MN)" || + modString == "GH(IJ(KL))(GH)" || + modString == "IJ(IJ(KL))(MN)" || // toCopy == left + modString == "GH(IJ(IJ))(MN)" || + modString == "GH(IJ(KL))(IJ)" || + modString == "MN(IJ(KL))(MN)" || // toCopy == right + modString == "GH(MN(KL))(MN)" || + modString == "GH(IJ(MN))(MN)" || + modString == "KL(IJ(KL))(MN)" || // toCopy == grandchild + modString == "GH(KL(KL))(MN)" || + modString == "GH(IJ(KL))(KL)" + ); +} \ No newline at end of file diff --git a/Radamsa/test/RadamsaSwapNodesMutatorTest.cpp b/Radamsa/test/RadamsaSwapNodesMutatorTest.cpp new file mode 100644 index 0000000..0de3a12 --- /dev/null +++ b/Radamsa/test/RadamsaSwapNodesMutatorTest.cpp @@ -0,0 +1,268 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaSwapNodesMutator.hpp" +#include "RuntimeException.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaSwapNodesMutator; +using vmf::BaseException; +using vmf::RuntimeException; + +class RadamsaSwapNodesMutatorTest : public ::testing::Test { + protected: + RadamsaSwapNodesMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaSwapNodesMutator("RadamsaSwapNodesMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaSwapNodesMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + // int_key = registry->registerKey( + // "TEST_INT", + // StorageRegistry::INT, + // StorageRegistry::READ_WRITE + // ); + // normalTag = registry->registerTag( + // "RAN_SUCCESSFULLY", + // StorageRegistry::WRITE_ONLY + // ); + // // registry->validateRegistration(); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } + + RadamsaSwapNodesMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; +}; + +/*TEST_F(RadamsaSwapNodesMutatorTest, BufferNotNull) +{ + // no way to test this without mocks +}*/ + +TEST_F(RadamsaSwapNodesMutatorTest, ThreeBytes) +{ + std::string buffString = "GHI"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaSwapNodesMutatorTest, JustRoot) +{ + std::string buffString = "GHIJ"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaSwapNodesMutatorTest, OneChild) +{ + std::string buffString = "GH(IJ)"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + + // test buff len + EXPECT_EQ(modBuff_len, buff_len + 1); + // test buff contents + EXPECT_TRUE( + modString == "GH(IJ)\0" || // node1 == node2 + modString == "IJ(GH)\0" + ); +} + +TEST_F(RadamsaSwapNodesMutatorTest, TwoChildren) +{ + std::string buffString = "GH(IJ)(KL)"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + + // test buff len + EXPECT_EQ(modBuff_len, buff_len + 1); + // test buff contents + EXPECT_TRUE( + modString == "GH(IJ)(KL)" || // node1 == node2 + modString == "IJ(GH)(KL)" || // root <-> left + modString == "KL(IJ)(GH)" || // root <-> right + modString == "GH(KL)(IJ)" // left <-> right + ); +} + +TEST_F(RadamsaSwapNodesMutatorTest, TwoChildren_OneGrandchild) +{ + std::string buffString = "GH(IJ(KL))(MN)"; + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + std::string modString = std::string(modBuff); + + // test buff len + EXPECT_EQ(modBuff_len, buff_len + 1); + // test buff contents + EXPECT_TRUE( + modString == "GH(IJ(KL))(MN)\0" || // node1 == node2 + modString == "IJ(GH(KL))(MN)\0" || // root <-> ... + modString == "KL(IJ(GH))(MN)\0" || + modString == "MN(IJ(KL))(GH)\0" || + modString == "GH(KL(IJ))(MN)\0" || // left <-> ... + modString == "GH(MN(KL))(IJ)\0" || + modString == "GH(IJ(MN))(KL)\0" // grandchild <-> ... + ); +} \ No newline at end of file diff --git a/Radamsa/test/RadamsaTreeMutatorBaseTest.cpp b/Radamsa/test/RadamsaTreeMutatorBaseTest.cpp new file mode 100644 index 0000000..1fb752f --- /dev/null +++ b/Radamsa/test/RadamsaTreeMutatorBaseTest.cpp @@ -0,0 +1,184 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaTreeMutatorBase.hpp" +#include "RuntimeException.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaTreeMutatorBase; +using vmf::BaseException; +using vmf::RuntimeException; + +class RadamsaTreeMutatorBaseTest : public ::testing::Test { + protected: + RadamsaTreeMutatorBase::Tree tr; + + RadamsaTreeMutatorBaseTest() = default; + ~RadamsaTreeMutatorBaseTest() = default; +}; + +TEST_F(RadamsaTreeMutatorBaseTest, EmptyTreeStr) +{ + std::string treeStr = ""; + + try{ + tr = RadamsaTreeMutatorBase::Tree(treeStr); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.UNEXPECTED_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaTreeMutatorBaseTest, NoRoot) +{ + std::string treeStr = "(G)"; + + try{ + tr = RadamsaTreeMutatorBase::Tree(treeStr); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.UNEXPECTED_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaTreeMutatorBaseTest, DanglingCloseBracket) +{ + std::string treeStr = "G)"; + + try{ + tr = RadamsaTreeMutatorBase::Tree(treeStr); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.UNEXPECTED_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaTreeMutatorBaseTest, UnmatchedOpenBracket) +{ + std::string treeStr = "G("; + + try{ + tr = RadamsaTreeMutatorBase::Tree(treeStr); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.UNEXPECTED_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaTreeMutatorBaseTest, JustRoot) +{ + const std::string treeStr = "G"; + + try{ + this->tr = RadamsaTreeMutatorBase::Tree(treeStr); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + EXPECT_EQ(treeStr, tr.toString(tr.root)); +} + +TEST_F(RadamsaTreeMutatorBaseTest, OneChild) +{ + const std::string treeStr = "GH(IJ)"; + + try{ + this->tr = RadamsaTreeMutatorBase::Tree(treeStr); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + EXPECT_EQ(treeStr, tr.toString(tr.root)); +} + +TEST_F(RadamsaTreeMutatorBaseTest, TwoChildren) +{ + const std::string treeStr = "GH(IJ)(KL)"; + + try{ + this->tr = RadamsaTreeMutatorBase::Tree(treeStr); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + EXPECT_EQ(treeStr, tr.toString(tr.root)); +} + +TEST_F(RadamsaTreeMutatorBaseTest, TwoChildren_OneGrandchild) +{ + const std::string treeStr = "GH(IJ(KL))(MN)"; + + try{ + this->tr = RadamsaTreeMutatorBase::Tree(treeStr); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + EXPECT_EQ(treeStr, tr.toString(tr.root)); +} \ No newline at end of file diff --git a/Radamsa/test/RadamsaWidenCodePointMutatorTest.cpp b/Radamsa/test/RadamsaWidenCodePointMutatorTest.cpp new file mode 100644 index 0000000..bff4d93 --- /dev/null +++ b/Radamsa/test/RadamsaWidenCodePointMutatorTest.cpp @@ -0,0 +1,237 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + +#include "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaWidenCodePointMutator.hpp" +#include "RuntimeException.hpp" + +using vmf::StorageModule; +using vmf::StorageRegistry; +using vmf::ModuleTestHelper; +using vmf::TestConfigInterface; +using vmf::SimpleStorage; +using vmf::StorageEntry; +using vmf::RadamsaWidenCodePointMutator; +using vmf::BaseException; +using vmf::RuntimeException; + +class RadamsaWidenCodePointMutatorTest : public ::testing::Test { + protected: + RadamsaWidenCodePointMutatorTest() + { + storage = new SimpleStorage("storage"); + registry = new StorageRegistry("TEST_INT", StorageRegistry::INT, StorageRegistry::ASCENDING); + metadata = new StorageRegistry(); + testHelper = new ModuleTestHelper(); + theMutator = new RadamsaWidenCodePointMutator("RadamsaWidenCodePointMutator"); + config = testHelper -> getConfig(); + } + + ~RadamsaWidenCodePointMutatorTest() override {} + + void SetUp() override { + testCaseKey = registry->registerKey( + "TEST_CASE", + StorageRegistry::BUFFER, + StorageRegistry::READ_WRITE + ); + // int_key = registry->registerKey( + // "TEST_INT", + // StorageRegistry::INT, + // StorageRegistry::READ_WRITE + // ); + // normalTag = registry->registerTag( + // "RAN_SUCCESSFULLY", + // StorageRegistry::WRITE_ONLY + // ); + // // registry->validateRegistration(); + storage->configure(registry, metadata); + theMutator->init(*config); + theMutator->registerStorageNeeds(*registry); + theMutator->registerMetadataNeeds(*metadata); + } + + void TearDown() override { + delete registry; + delete metadata; + delete storage; + } + + RadamsaWidenCodePointMutator* theMutator; + StorageModule* storage; + StorageRegistry* registry; + StorageRegistry* metadata; + ModuleTestHelper* testHelper; + TestConfigInterface* config; + int testCaseKey; +}; + +/*TEST_F(RadamsaWidenCodePointMutatorTest, BufferNotNull) +{ + // no way to test this without mocks +}*/ + +TEST_F(RadamsaWidenCodePointMutatorTest, NotAscii) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = 1; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + + buff[0] = 127; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + ADD_FAILURE() << "No exception thrown"; + } + catch (RuntimeException e) + { + EXPECT_EQ(e.getErrorCode(), e.USAGE_ERROR); + } + catch (BaseException e) + { + FAIL() << "Unexpected Exception thrown: " << e.getReason(); + } +} + +TEST_F(RadamsaWidenCodePointMutatorTest, OneByte) +{ + std::string buffString = "g"; // 0b01100111 + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + + ASSERT_FALSE( + std::equal( + buff, + buff + buff_len, + modBuff + ) + ); + EXPECT_EQ(modBuff_len, buff_len + 2); + EXPECT_EQ(modBuff[0], '\xC0'); // 0b11000000 + EXPECT_EQ(modBuff[1], '\xE7'); // 0b11100111 +} + +TEST_F(RadamsaWidenCodePointMutatorTest, TwoBytes) +{ + std::string buffString = "gh"; // 0b01100111, 0b01101000 + + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = buffString.length(); + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + for(size_t i{0}; i < buff_len; ++i) { + buff[i] = buffString[i]; + } + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + + ASSERT_FALSE( + std::equal( + buff, + buff + buff_len, + modBuff + ) + ); + EXPECT_EQ(modBuff_len, buff_len + 2); + + if (modBuff[0] == '\xC0') EXPECT_EQ(modBuff[1], '\xE7'); + + else if (modBuff[1] == '\xC0') EXPECT_EQ(modBuff[2], '\xE8'); + + else FAIL() << "modBuff[0] and modBuff[1] do not equal \'\\xC0\'"; +} + +TEST_F(RadamsaWidenCodePointMutatorTest, MixedValidInvalid) +{ + StorageEntry* baseEntry = storage->createNewEntry(); + StorageEntry* modEntry = storage->createNewEntry(); + char* modBuff; + + const size_t buff_len = 2; + char* buff = baseEntry->allocateBuffer(testCaseKey, buff_len); + + buff[0] = 127; + buff[1] = 'g'; + buff[2] = 31; + + try{ + theMutator->mutateTestCase(*storage, baseEntry, modEntry, testCaseKey); + modBuff = modEntry->getBufferPointer(testCaseKey); + } + catch (BaseException e) + { + FAIL() << "Exception thrown: " << e.getReason(); + } + + size_t modBuff_len = modEntry->getBufferSize(testCaseKey); + + ASSERT_FALSE( + std::equal( + buff, + buff + buff_len, + modBuff + ) + ); + EXPECT_EQ(modBuff_len, buff_len + 2); + EXPECT_EQ(modBuff[1], '\xC0'); // 0b11000000 + EXPECT_EQ(modBuff[2], '\xE7'); // 0b11100111 +} \ No newline at end of file diff --git a/Radamsa/vmf/src/CMakeLists.txt b/Radamsa/vmf/src/CMakeLists.txt index da98d21..117657c 100644 --- a/Radamsa/vmf/src/CMakeLists.txt +++ b/Radamsa/vmf/src/CMakeLists.txt @@ -1,17 +1,8 @@ #=============================================================================== # Vader Modular Fuzzer (VMF) -# Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. -# -# -# Effort sponsored by the U.S. Government under Other Transaction number -# W9124P-19-9-0001 between AMTC and the Government. The U.S. Government -# Is authorized to reproduce and distribute reprints for Governmental purposes -# notwithstanding any copyright notation thereon. -# -# The views and conclusions contained herein are those of the authors and -# should not be interpreted as necessarily representing the official policies -# or endorsements, either expressed or implied, of the U.S. Government. -# +# Copyright (c) 2021-2025 The Charles Stark Draper Laboratory, Inc. +# +# # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 (only) as # published by the Free Software Foundation. diff --git a/Radamsa/vmf/src/modules/CMakeLists.txt b/Radamsa/vmf/src/modules/CMakeLists.txt index bc05680..d4fb121 100644 --- a/Radamsa/vmf/src/modules/CMakeLists.txt +++ b/Radamsa/vmf/src/modules/CMakeLists.txt @@ -1,17 +1,8 @@ #=============================================================================== # Vader Modular Fuzzer (VMF) -# Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. -# -# -# Effort sponsored by the U.S. Government under Other Transaction number -# W9124P-19-9-0001 between AMTC and the Government. The U.S. Government -# Is authorized to reproduce and distribute reprints for Governmental purposes -# notwithstanding any copyright notation thereon. -# -# The views and conclusions contained herein are those of the authors and -# should not be interpreted as necessarily representing the official policies -# or endorsements, either expressed or implied, of the U.S. Government. -# +# Copyright (c) 2021-2025 The Charles Stark Draper Laboratory, Inc. +# +# # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 (only) as # published by the Free Software Foundation. @@ -29,9 +20,6 @@ # Create Radamsa library add_library(Radamsa SHARED -# common/mutator/byteMutations.cpp -# common/mutator/radamsaMutator.cpp -# common/mutator/lineMutations.cpp common/mutator/RadamsaDropByteMutator.cpp common/mutator/RadamsaFlipByteMutator.cpp common/mutator/RadamsaInsertByteMutator.cpp @@ -46,25 +34,58 @@ add_library(Radamsa SHARED common/mutator/RadamsaCopyLineCloseByMutator.cpp common/mutator/RadamsaRepeatLineMutator.cpp common/mutator/RadamsaSwapLineMutator.cpp + common/mutator/RadamsaRepeatByteSequenceMutator.cpp # -sr + common/mutator/RadamsaDeleteByteSequenceMutator.cpp # -sd + common/mutator/RadamsaPermuteLinesMutator.cpp # -lp + common/mutator/RadamsaInsertLineMutator.cpp # -lis + common/mutator/RadamsaReplaceLineMutator.cpp # -lrs + common/mutator/RadamsaDeleteNodeMutator.cpp # -td + common/mutator/RadamsaDuplicateNodeMutator.cpp # -tr2 + common/mutator/RadamsaReplaceNodeMutator.cpp # -ts1 + common/mutator/RadamsaSwapNodesMutator.cpp # -ts2 + common/mutator/RadamsaRepeatPathMutator.cpp # -tr + common/mutator/RadamsaWidenCodePointMutator.cpp # -uw + common/mutator/RadamsaInsertUnicodeMutator.cpp # -ui + common/mutator/RadamsaModifyTextNumberMutator.cpp # -num + common/mutator/RadamsaFuseThisMutator.cpp # -ft + common/mutator/RadamsaFuseNextMutator.cpp # -fn + common/mutator/RadamsaFuseOldMutator.cpp # -fo + common/mutator/RadamsaAsciiBadMutator.cpp # -ab ) +#Set flag to export all symbols for windows builds +set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) + +# windows needs an additional import to make the logger work +if(WIN32) + target_compile_definitions(Radamsa PRIVATE PLOG_IMPORT) +endif() + # Build-time dependencies for Radamsa link_directories(Radamsa PRIVATE ) # Build-time dependencies for Radamsa target_link_libraries(Radamsa PRIVATE + vmf_framework ) # Build-time dependencies for Radamsa target_include_directories(Radamsa PRIVATE - ${VMF_INSTALL}/include - ${VMF_INSTALL}/include/vmf - ${VMF_INSTALL}/include/plog + ${CMAKE_INSTALL_PREFIX}/include + ${CMAKE_INSTALL_PREFIX}/include/vmf + ${CMAKE_INSTALL_PREFIX}/include/plog ${PROJECT_SOURCE_DIR}/src/module ) # Install Radamsa library in VMF plugins directory install(TARGETS Radamsa - LIBRARY DESTINATION "${VMF_INSTALL}/plugins") + LIBRARY DESTINATION "${CMAKE_INSTALL_PREFIX}/plugins") +#On windows the /plugins directory above is ignored, and everything ends up in /lib and /bin +if(WIN32) + cmake_path(SET WIN_LIB_FILE ${CMAKE_INSTALL_PREFIX}/lib/Radamsa.lib) + cmake_path(SET WIN_DLL_FILE ${CMAKE_INSTALL_PREFIX}/bin/Radamsa.dll) + install(FILES ${WIN_LIB_FILE} ${WIN_DLL_FILE} + DESTINATION ${CMAKE_INSTALL_PREFIX}/plugins) +endif() diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaAsciiBadMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaAsciiBadMutator.cpp new file mode 100644 index 0000000..d4c3160 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaAsciiBadMutator.cpp @@ -0,0 +1,391 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaAsciiBadMutator.hpp" +#include "RuntimeException.hpp" +#include +#include +#include + +using namespace vmf; +using Byte = uint8_t; +using std::get; +using std::get_if; +using std::holds_alternative; +using std::string; +using std::variant; + + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaAsciiBadMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaAsciiBadMutator::build(std::string name) +{ + return new RadamsaAsciiBadMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaAsciiBadMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaAsciiBadMutator::RadamsaAsciiBadMutator object + * + * @param name The of the name module + */ +RadamsaAsciiBadMutator::RadamsaAsciiBadMutator(std::string name) : MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the RadamsaAsciiBadMutator::RadamsaAsciiBadMutator object + * + */ +RadamsaAsciiBadMutator::~RadamsaAsciiBadMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaAsciiBadMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +// Helper stuff starts here +struct Delimited { + // Chunk of Data, usually with delimiting quotes enclosing it + + Byte delim; + vector data; + + static Delimited make(char c, const vector& d) { + return Delimited{Byte(c), d}; + } + + void unlex(vector& out) const { + out.push_back(delim); + out.insert(out.end(), data.begin(), data.end()); + out.push_back(delim); + + return; + } +}; + +struct Text { + // Raw text / delimited chunk +public: + variant, Delimited> value; + + static Text texty(const vector& s) { + return Text{s}; + } + static Text delim(const Delimited& d) { + return Text{d}; + } + + void mutate(VmfRand* rand) { + vector* targetData; + if (vector* p = get_if>(&value)) { + targetData = p; + } else { + targetData = &get(value).data; + } + mutateTextData(*targetData, rand); + + return; + } + + void unlex(vector& out) const { + if (holds_alternative>(value)) { + const vector& a = get>(value); + out.insert(out.end(), a.begin(), a.end()); + } else { + const Delimited& delimChunk = get(value); + delimChunk.unlex(out); + } + + return; + } +private: + explicit Text(const vector& s) : value(s) {} + explicit Text(const Delimited& d) : value(d) {} + + static const vector> getSillyStrings() { + // XXX: extend this because many of these strings are incredibly Linux-specific + // perhaps add a configurable wordlist + static const vector strList = { + "%n", "%n", "%s", "%d", "%p", "%#x", + "\\00", "aaaa%d%n", + "`xcalc`", ";xcalc", "$(xcalc)", "!xcalc", "\"xcalc", "'xcalc", + "\\x00", "\\r\\n", "\\r", "\\n", "\\x0a", "\\x0d", + "NaN", "+inf", + "$PATH", + "$!!", "!!", "�", "\\u0000", + "$&", "$+", "$`", "$'", "$1" + }; + static vector> list; + if (list.empty()) { + list.reserve(strList.size()); + for (const string& s : strList) { + list.emplace_back(s.begin(), s.end()); + } + } + return list; + }; + + vector randomBadness(VmfRand* rand) { + // Randomly concatenate 1-19 "silly strings" + + const vector> sillyStrings = getSillyStrings(); + int repeatCount = rand->randBetween(1, 19); + + vector out; + out.reserve(repeatCount * 8); + for (int i = 0; i < repeatCount; ++i) { + const vector& s = sillyStrings[rand->randBetween(0, sillyStrings.size() - 1)]; + out.insert(out.end(), s.begin(), s.end()); + } + return out; + } + + void mutateTextData(vector& data, VmfRand* rand) { + size_t byteIndex = rand->randBetween(0, data.size()); + int mutationType = rand->randBetween(0, 2); + switch (mutationType) { + case 0: { + // insert badness + vector bad = randomBadness(rand); + data.insert(data.begin() + byteIndex, bad.begin(), bad.end()); + break; + } + case 1: { + // replace badness + vector bad = randomBadness(rand); + data.resize(byteIndex); + data.insert(data.end(), bad.begin(), bad.end()); + break; + } + case 2: { + // push random number of newline characters + int choice = rand->randBetween(0, 10); + size_t newlineCount; + switch (choice) { + case 0: newlineCount = 127; break; + case 1: newlineCount = 128; break; + case 2: newlineCount = 255; break; + case 3: newlineCount = 256; break; + case 4: newlineCount = 16383; break; + case 5: newlineCount = 16384; break; + case 6: newlineCount = 32767; break; + case 7: newlineCount = 32768; break; + case 8: newlineCount = 65535; break; + case 9: newlineCount = 65536; break; + default: newlineCount = rand->randBetween(0, 1023); break; + } + data.insert(data.begin() + byteIndex, newlineCount, Byte('\n')); + break; + } + } + + return; + } +}; + +struct Data { + // Chunk data in two flavors: bytes, and texty + variant, vector> value; + + void unlex(vector& out) const { + if (holds_alternative>(value)) { + const vector& a = get>(value); + out.insert(out.end(), a.begin(), a.end()); + } else { + const vector& texts = get>(value); + for (const Text& t : texts) { + t.unlex(out); + } + } + } +}; + +struct Ascii { +public: + vector chunks; + + static optional parse(const vector& data) { + vector out; + bool success = parseBytes(data, 6, out); + if (!success) return nullopt; + return Ascii{out}; + } + + void mutate(VmfRand* rand) { + vector textChunkIndices; + for (size_t i = 0; i < chunks.size(); ++i) { + if (holds_alternative>(chunks[i].value)) + textChunkIndices.push_back(i); + } + if(textChunkIndices.empty()) return; + + const size_t chunkIndex = rand->randBetween(0, textChunkIndices.size() - 1); + vector& textElems = get>( + chunks[textChunkIndices[chunkIndex]].value + ); + const size_t elemIndex = rand->randBetween(0, textElems.size() - 1); + textElems[elemIndex].mutate(rand); + + return; + } + + vector unlex() const { + vector out; + out.reserve(chunks.size() * 16); + for (const Data& d : chunks) { + d.unlex(out); + } + return out; + } + +private: + static bool isTexty(Byte b) noexcept { + return b == 9 || b == 10 || b == 13 || (b >= 32 && b <= 126); + } + + static bool parseBytes( + const vector& input, + size_t minTexty, + vector& out + ) { + // Splits input into Data chunks + // The first chunk must be a run of a least "minTexty" printable ASCII bytes + + size_t pos = 0; + size_t start = pos; + // min size check + while (pos < input.size() && Ascii::isTexty(input[pos])) { + ++pos; + } + if ((pos - start) < minTexty) return false; + + // Grab first text chunk + vector slice(input.begin(), input.begin() + pos); + vector firstRun; + firstRun.push_back(Text::texty(slice)); + out.insert(out.begin(), Data{firstRun}); + + // Process remainder + start = pos; + while (pos < input.size()) { + if (Ascii::isTexty(input[pos])) { + ++pos; + } else { + // if we just finished a texty run [start, pos), capture it + if (pos > start) { + vector nextSlice(input.begin() + start, input.begin() + pos); + vector t; + t.push_back(Text::texty(nextSlice)); + out.push_back(Data{t}); + } + // treat the current non-text byte as its own Data chunk + out.push_back(Data{vector{input[pos]}}); + ++pos; + start = pos; // reset start for next run + } + } + + // if input ends in the middle of a texty run [start, input.size()), capture the run + if (pos > start) { + vector finalSlice(input.begin() + start, input.begin() + pos); + vector finalTexty; + finalTexty.push_back(Text::texty(finalSlice)); + out.push_back(Data{finalTexty}); + } + + return true; + } +}; + +void RadamsaAsciiBadMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + /* Mutate a single "chunk" of continuous printable ASCII by: + * inserting a random combination of 1-19 "silly strings" at a random index, + * replacing everything after a random index with a random combination of 1-19 "silly strings", + * or appending between 0 and 65,536 newlines + */ + + const size_t minimumSize{1u}; + const size_t minimumSeedIndex{0u}; + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); + + if (originalSize < minimumSize) { + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; + } + if (minimumSeedIndex > originalSize - 1u) { + throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + } + if (originalBuffer == nullptr) { + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + } + + vector data(originalBuffer, originalBuffer + originalSize); + + optional parsedAscii = Ascii::parse(data); + if (!parsedAscii) { + throw RuntimeException{"Unable to parse ASCII from buffer", RuntimeException::USAGE_ERROR}; + } + + parsedAscii->mutate(this->rand); + vector mutatedBytes = parsedAscii->unlex(); + + const size_t newBufferSize{mutatedBytes.size() + 1}; // +1 to implicitly append a null terminator + char* newBuffer{newEntry->allocateBuffer(testCaseKey, newBufferSize)}; + memset(newBuffer, 0u, newBufferSize); + memcpy(newBuffer, mutatedBytes.data(), mutatedBytes.size()); +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaAsciiBadMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaAsciiBadMutator.hpp new file mode 100644 index 0000000..6c64e1c --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaAsciiBadMutator.hpp @@ -0,0 +1,57 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "RadamsaByteMutatorBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaAsciiBadMutator: public MutatorModule, public RadamsaByteMutatorBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaAsciiBadMutator(std::string name); + virtual ~RadamsaAsciiBadMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand* rand = VmfRand::getInstance(); +}; +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaByteMutatorBase.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaByteMutatorBase.hpp index ece3828..9a3dea7 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaByteMutatorBase.hpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaByteMutatorBase.hpp @@ -31,6 +31,16 @@ #pragma once #include "RadamsaMutatorBase.hpp" +#include +#include + +using std::vector; +using std::isdigit; +using std::pair; +using std::set; +using std::optional; +using std::nullopt; +using std::move; namespace vmf { @@ -40,7 +50,13 @@ namespace vmf class RadamsaByteMutatorBase: public RadamsaMutatorBase { public: - static size_t GetRandomByteRepetitionLength(VmfRand* rand) noexcept + struct NumInfo { + unsigned int value = 0; + size_t offset = 0; + size_t length = 0; + }; + + static size_t GetRandomRepetitionLength(VmfRand* rand) noexcept { constexpr size_t MINIMUM_UPPER_LIMIT{0x2u}; constexpr size_t MAXIMUM_UPPER_LIMIT{0x20000u}; @@ -59,5 +75,220 @@ class RadamsaByteMutatorBase: public RadamsaMutatorBase return rand->randBetween(0u, randomUpperLimit) + 1u; // We add one to the return value in order to account for the case where the random upper value is zero. } + + vector encodeUtf8(char32_t cp) { + // encodes 21-bit character code points into UTF-8 values of 1 to 4 bytes + + vector result; + if (cp <= 0x7F) { // 1B case + result.push_back(cp); + } + else if (cp <= 0x7FF) { // 2B case + result.push_back(0xC0 | (cp >> 6)); // 110xxxxx, top 5b + result.push_back(0x80 | (cp & 0x3F)); // 10xxxxxx, bottom 6b + } else if (cp <= 0xFFFF) { // 3B case + result.push_back(0xE0 | (cp >> 12)); // 1110xxxx, top 4b + result.push_back(0x80 | ((cp >> 6) & 0x3F)); // 10xxxxxx, next 6b + result.push_back(0x80 | (cp & 0x3F)); + } else { // 4B case + result.push_back(0xF0 | (cp >> 18)); // 11110xxx, top 3b + result.push_back(0x80 | ((cp >> 12) & 0x3F)); // 10xxxxxx, next 6b + result.push_back(0x80 | ((cp >> 6) & 0x3F)); + result.push_back(0x80 | (cp & 0x3F)); + } + return result; + } + + vector extractTextualNumbers(const vector& data) { + // Converts and extracts ASCII numbers given a vector of bytes + + vector result; + size_t i = 0; + while (i < data.size()) { + if (isdigit(data[i])) { + size_t start = i; + while (i < data.size() && isdigit(data[i])) ++i; // find length of number + + std::string numStr(data.begin() + start, data.begin() + i); + try { + unsigned long long val = std::stoull(numStr); + if (val <= std::numeric_limits::max()) { + result.push_back({static_cast(val), start, i - start}); + } + // else: too large for ui, skip + } + catch(const std::invalid_argument& e) { + // invalid number, skip + } + catch(const std::out_of_range& e) { + // too large for ull, skip + } + } + else ++i; + } + + return result; + } + + vector generateInterestingNumbers() { + vector result; + vector shifts = {1, 7, 8, 15, 16, 31}; // truncating from original rust, as unsigned ints are only 32b + + for (unsigned int s : shifts) { + unsigned int val = 1ULL << s; + result.push_back(val); + result.push_back(val - 1); + result.push_back(val + 1); + } + + return result; + } + + template + pair>, vector>> getAlternateSuffixes( + const vector& theList, + VmfRand* rand + ) { + // getSuffixes, but randomize which output list gets each suffix + // NOTE: Very likely to return an empty pair for small buffer sizes + + vector> listA, listB; + vector subListA, subListB; + for (size_t i = 0; i < theList.size(); ++i) { + if (rand->randBetween(0, 1) == 0) { + subListA.assign(theList.begin() + i, theList.end()); + if(!subListB.empty()) { + listB.push_back(move(subListB)); + subListB.clear(); + } + } else { + subListB.assign(theList.begin() + i, theList.end()); + if(!subListA.empty()) { + listA.push_back(move(subListA)); + subListA.clear(); + } + } + } + return {listA, listB}; + } + + template + vector> getSuffixes(const vector& theList) { + // Grabs all possible slices that end at theList's end + + vector> result; + for(size_t i = 0; i < theList.size(); ++i) { + result.push_back(vector(theList.begin() + i, theList.end())); + } + return result; + } + + template + pair>, vector>> getInitialSuffixes( + const vector& a, + const vector& b, + VmfRand* rand + ) { + if (a == b) return getAlternateSuffixes(a, rand); + return {getSuffixes(a), getSuffixes(b)}; + } + + template + optional, vector>> getAnyPositionPair( + vector>& a, + vector>& b, + VmfRand* rand + ) { + if (a.empty() || b.empty()) return nullopt; + + size_t aIndex = rand->randBetween(0, a.size() - 1); // -1 because randBetween is max inclusive + size_t bIndex = rand->randBetween(0, b.size() - 1); + vector aElem = a[aIndex]; + vector bElem = b[bIndex]; + return pair, vector>(aElem, bElem); + } + + template + pair>, vector>> splitPrefixes( + vector>& prefixes, + vector>& suffixes + ) { + set used; + set> hashSuffix; + vector> newPrefixes; + for (vector prefix : prefixes) { + if(!prefix.empty() && used.find(prefix[0]) == used.end()) { // if first char of this prefix hasn't been seen yet... + used.insert(prefix[0]); + newPrefixes.push_back(prefix); + suffixes.erase( // erase-remove idiom. moves all suffixes shorter than prefix to hashSuffix + std::remove_if( // shifts matching elements to the end + suffixes.begin(), + suffixes.end(), + [&](const vector& suffix) { + if (suffix.size() < prefix.size()) { + hashSuffix.insert(suffix); // stores them in hashSuffix prior to removal from suffixes + return true; + } + return false; + } + ), + suffixes.end() // marks matching elements for erasure + ); + } + } + return { + newPrefixes, + vector>(hashSuffix.begin(), hashSuffix.end()) // convert set of slices to vector of slices + }; + } + + template + pair, vector> findJumpPoints( + const vector& a, + const vector& b, + VmfRand* rand + ) { + // NOTE: Very likely to return a and b unmodified for small buffer sizes if a==b + + int fuel = 100000; + const int searchStopIp = 8; + + auto [listA, listB] = getInitialSuffixes(a, b, rand); + if (listA.empty() || listB.empty()) return {a, b}; + + while (true) { + if (fuel < 0 || rand->randBetween(0, searchStopIp) == 0) { + if (auto result = getAnyPositionPair(listA, listB, rand)) return *result; + return {a, b}; + } else { + auto [nodeA, nodeB] = splitPrefixes(listA, listB); + if (nodeA.empty() || nodeB.empty()) { + if (auto result = getAnyPositionPair(listA, listB, rand)) return *result; + return {a, b}; + } else { + listA = nodeA; + listB = nodeB; + fuel -= static_cast(listA.size() + listB.size()); + } + } + } + } + + template + vector fuse(const vector& a, const vector& b, VmfRand* rand) { + // Combines a prefix substring from "a" and a suffix substring from "b" + // NOTE: Very likely to return input unmodified for small buffer sizes if a==b + + if (a.empty() || b.empty()) return a; + + auto [from, to] = findJumpPoints(a, b, rand); + + if (std::equal(from.begin(), from.end(), a.end() - from.size())) { + vector result(a.begin(), a.end() - from.size()); // keep prefix + result.insert(result.end(), to.begin(), to.end()); // append suffix + return result; + } + return a; + } }; } \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteByteSequenceMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteByteSequenceMutator.cpp new file mode 100644 index 0000000..b967e24 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteByteSequenceMutator.cpp @@ -0,0 +1,136 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaDeleteByteSequenceMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaDeleteByteSequenceMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaDeleteByteSequenceMutator::build(std::string name) +{ + return new RadamsaDeleteByteSequenceMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaDeleteByteSequenceMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaDeleteByteSequenceMutator::RadamsaDeleteByteSequenceMutator object + * + * @param name The of the name module + */ +RadamsaDeleteByteSequenceMutator::RadamsaDeleteByteSequenceMutator(std::string name) : MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the RadamsaDeleteByteSequenceMutator::RadamsaDeleteByteSequenceMutator object + * + */ +RadamsaDeleteByteSequenceMutator::~RadamsaDeleteByteSequenceMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaDeleteByteSequenceMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +void RadamsaDeleteByteSequenceMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + // select a random number of consecutive bytes and remove them + + constexpr size_t minimumSize{2u}; + const size_t minimumSeedIndex{0u}; + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); + + if (originalSize < minimumSize) + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 2", RuntimeException::USAGE_ERROR}; + + if (minimumSeedIndex > originalSize - 1u) + throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + + if (originalBuffer == nullptr) + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + + + // Select random indexes for the start and end of the sequence + const size_t start_lower{0u}; + const size_t start_upper{originalSize - 1u - 1u}; // additional -1 to leave at least one byte at the end + const size_t start_index{rand->randBetween(start_lower, start_upper)}; + + const size_t end_lower{start_index + 1u}; + const size_t end_upper{originalSize - 1u}; + const size_t end_index{rand->randBetween(end_lower, end_upper)}; + + // Calculate the size of the modified buffer + const size_t newBufferSize{originalSize - (end_index - start_index + 1u) + 1u}; // +1 because we're appending a null-terminator + + // Allocate the new buffer and set it's elements to zero. + char* newBuffer{newEntry->allocateBuffer(testCaseKey, static_cast(newBufferSize))}; + memset(newBuffer, 0u, newBufferSize); + + // Copy pre-sequence into modified buffer + memcpy(newBuffer, originalBuffer, start_index); + + // Copy post-sequence into modified buffer + memcpy( + newBuffer, + originalBuffer + end_index + 1u, + originalSize - (end_index + 1u) + ); +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteByteSequenceMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteByteSequenceMutator.hpp new file mode 100644 index 0000000..634d351 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteByteSequenceMutator.hpp @@ -0,0 +1,57 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "RadamsaByteMutatorBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaDeleteByteSequenceMutator: public MutatorModule, public RadamsaByteMutatorBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaDeleteByteSequenceMutator(std::string name); + virtual ~RadamsaDeleteByteSequenceMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand* rand = VmfRand::getInstance(); +}; +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteNodeMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteNodeMutator.cpp new file mode 100644 index 0000000..1f9084b --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteNodeMutator.cpp @@ -0,0 +1,130 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaDeleteNodeMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaDeleteNodeMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaDeleteNodeMutator::build(std::string name) +{ + return new RadamsaDeleteNodeMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaDeleteNodeMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaDeleteNodeMutator::RadamsaDeleteNodeMutator object + * + * @param name The of the name module + */ +RadamsaDeleteNodeMutator::RadamsaDeleteNodeMutator(std::string name) : MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the RadamsaDeleteNodeMutator::RadamsaDeleteNodeMutator object + * + */ +RadamsaDeleteNodeMutator::~RadamsaDeleteNodeMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaDeleteNodeMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +void RadamsaDeleteNodeMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + // Delete a random node from the tree without preserving its children + + const size_t minimumSize{1}; // minimal case consists of a single-character root node + const size_t minimumSeedIndex{0u}; + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); + + if (originalSize < minimumSize) + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; + + if (minimumSeedIndex > originalSize - 1u) + throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + + if (originalBuffer == nullptr) + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + + const std::string treeStr(originalBuffer, originalSize); + Tree tr(treeStr); + + size_t numNodes = tr.countNodes(tr.root); + + const size_t lower{0u}; + const size_t upper{numNodes - 1}; + size_t nodeIndexToDelete{this->rand->randBetween(lower, upper)}; // not const, because findNodeByIndex will modify it + + Node* nodeToDelete = tr.findNodeByIndex(tr.root, nodeIndexToDelete); + tr.deleteNode(nodeToDelete); + + string modTreeStr = tr.toString(tr.root); + + const size_t newBufferSize{modTreeStr.length() + 1}; // +1 to implicitly append a null terminator + + char* newBuffer{newEntry->allocateBuffer(testCaseKey, newBufferSize)}; + memset(newBuffer, 0u, newBufferSize); + + std::strcpy(newBuffer, modTreeStr.c_str()); +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteNodeMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteNodeMutator.hpp new file mode 100644 index 0000000..1d9f0db --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaDeleteNodeMutator.hpp @@ -0,0 +1,57 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "RadamsaTreeMutatorBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaDeleteNodeMutator: public MutatorModule, public RadamsaTreeMutatorBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaDeleteNodeMutator(std::string name); + virtual ~RadamsaDeleteNodeMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand* rand = VmfRand::getInstance(); +}; +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaDuplicateNodeMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaDuplicateNodeMutator.cpp new file mode 100644 index 0000000..232152c --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaDuplicateNodeMutator.cpp @@ -0,0 +1,132 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaDuplicateNodeMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaDuplicateNodeMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaDuplicateNodeMutator::build(std::string name) +{ + return new RadamsaDuplicateNodeMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaDuplicateNodeMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaDuplicateNodeMutator::RadamsaDuplicateNodeMutator object + * + * @param name The of the name module + */ +RadamsaDuplicateNodeMutator::RadamsaDuplicateNodeMutator(std::string name) : MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the RadamsaDuplicateNodeMutator::RadamsaDuplicateNodeMutator object + * + */ +RadamsaDuplicateNodeMutator::~RadamsaDuplicateNodeMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaDuplicateNodeMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +void RadamsaDuplicateNodeMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + // Duplicates existing node, including its children, and adds it to the same parent as the original + + const size_t minimumSize{4u}; // minimal case consists of two single-character nodes + const size_t minimumSeedIndex{0u}; + const size_t minimumNodes{2u}; + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); + + if (originalSize < minimumSize) + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 4", RuntimeException::USAGE_ERROR}; + + if (minimumSeedIndex > originalSize - 1u) + throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + + if (originalBuffer == nullptr) + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + + const std::string treeStr(originalBuffer, originalSize); + Tree tr(treeStr); + + size_t numNodes = tr.countNodes(tr.root); + if (numNodes < minimumNodes) + throw RuntimeException{"The number of nodes must be greater than or equal to 2", RuntimeException::USAGE_ERROR}; + + const size_t lower{1u}; + const size_t upper{numNodes - 2}; + size_t nodeIndexToDuplicate{this->rand->randBetween(lower, upper)}; // not const, because findNodeByIndex will modify it + Node* nodeToDuplicate = tr.findNodeByIndex(tr.root, nodeIndexToDuplicate); + + tr.duplicateNode(nodeToDuplicate, nodeToDuplicate->parent); + + const string modTreeStr = tr.toString(tr.root); + const size_t newBufferSize{modTreeStr.length() + 1}; // +1 to implicitly append a null terminator + + char* newBuffer{newEntry->allocateBuffer(testCaseKey, newBufferSize)}; + memset(newBuffer, 0u, newBufferSize); + + std::strcpy(newBuffer, modTreeStr.c_str()); +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaDuplicateNodeMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaDuplicateNodeMutator.hpp new file mode 100644 index 0000000..cd9b5b3 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaDuplicateNodeMutator.hpp @@ -0,0 +1,57 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "RadamsaTreeMutatorBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaDuplicateNodeMutator: public MutatorModule, public RadamsaTreeMutatorBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaDuplicateNodeMutator(std::string name); + virtual ~RadamsaDuplicateNodeMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand* rand = VmfRand::getInstance(); +}; +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp index 078327a..8ffdd5e 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.cpp @@ -135,7 +135,12 @@ void RadamsaFlipByteMutator::mutateTestCase(StorageModule& storage, StorageEntry // When computing the random bit shift, // we add 1 so that a maximum number of 8 bit shift operations can be performed against a char containing the value 0x01. - const size_t randomBitShift{rand->randBetween(0u, std::numeric_limits::digits + 1u)}; + const size_t randomBitShift{ + rand->randBetween( + 0u, + static_cast(std::numeric_limits::digits + 1u) + ) + }; const char randomMaskedBit{static_cast(0x01u << randomBitShift)}; // Flip the random byte by performing an XOR operation with a random masked bit. diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaFuseNextMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaFuseNextMutator.cpp new file mode 100644 index 0000000..4f53d30 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaFuseNextMutator.cpp @@ -0,0 +1,124 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaFuseNextMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaFuseNextMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaFuseNextMutator::build(std::string name) +{ + return new RadamsaFuseNextMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaFuseNextMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaFuseNextMutator::RadamsaFuseNextMutator object + * + * @param name The of the name module + */ +RadamsaFuseNextMutator::RadamsaFuseNextMutator(std::string name) : MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the RadamsaFuseNextMutator::RadamsaFuseNextMutator object + * + */ +RadamsaFuseNextMutator::~RadamsaFuseNextMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaFuseNextMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +void RadamsaFuseNextMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + // result = prefix(prefix(buffer_firstHalf) + suffix(buffer)) + suffix(buffer_secondHalf) + + const size_t minimumSize{2u}; + const size_t minimumSeedIndex{0u}; + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); + + if (originalSize < minimumSize) { + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 2", RuntimeException::USAGE_ERROR}; + } + if (minimumSeedIndex > originalSize - 1u) { + throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + } + if (originalBuffer == nullptr) { + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + } + + vector data(originalBuffer, originalBuffer + originalSize); + + const size_t midpoint = data.size() / 2; + const vector data_firstHalf(data.begin(), data.begin() + midpoint); + const vector data_secondHalf(data.begin() + midpoint, data.end()); + + const vector ab = fuse(data_firstHalf, data, this->rand); + const vector aba = fuse(ab, data_secondHalf, this->rand); + + const size_t newBufferSize{aba.size() + 1}; // +1 to implicitly append a null terminator + char* newBuffer{newEntry->allocateBuffer(testCaseKey, newBufferSize)}; + memset(newBuffer, 0u, newBufferSize); + memcpy(newBuffer, aba.data(), aba.size()); +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaFuseNextMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaFuseNextMutator.hpp new file mode 100644 index 0000000..1720fc5 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaFuseNextMutator.hpp @@ -0,0 +1,57 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "RadamsaByteMutatorBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaFuseNextMutator: public MutatorModule, public RadamsaByteMutatorBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaFuseNextMutator(std::string name); + virtual ~RadamsaFuseNextMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand* rand = VmfRand::getInstance(); +}; +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaFuseOldMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaFuseOldMutator.cpp new file mode 100644 index 0000000..30261c6 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaFuseOldMutator.cpp @@ -0,0 +1,128 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaFuseOldMutator.hpp" +#include "RuntimeException.hpp" +#include +#include +#include + +using namespace vmf; +using std::pair; +using std::set; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaFuseOldMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaFuseOldMutator::build(std::string name) +{ + return new RadamsaFuseOldMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaFuseOldMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaFuseOldMutator::RadamsaFuseOldMutator object + * + * @param name The of the name module + */ +RadamsaFuseOldMutator::RadamsaFuseOldMutator(std::string name) : MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the RadamsaFuseOldMutator::RadamsaFuseOldMutator object + * + */ +RadamsaFuseOldMutator::~RadamsaFuseOldMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaFuseOldMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +void RadamsaFuseOldMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + // Combine two random fusions of the two halves of the buffer + + const size_t minimumSize{2u}; + const size_t minimumSeedIndex{0u}; + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); + + if (originalSize < minimumSize) { + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 2", RuntimeException::USAGE_ERROR}; + } + if (minimumSeedIndex > originalSize - 1u) { + throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + } + if (originalBuffer == nullptr) { + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + } + + vector data(originalBuffer, originalBuffer + originalSize); + + const size_t midpoint = data.size() / 2; + const vector data_firstHalf(data.begin(), data.begin() + midpoint); + const vector data_secondHalf(data.begin() + midpoint, data.end()); + + vector a = fuse(data_firstHalf, data_secondHalf, this->rand); + const vector b = fuse(data_firstHalf, data_secondHalf, this->rand); + a.insert(a.end(), b.begin(), b.end()); + + const size_t newBufferSize{a.size() + 1}; // +1 to implicitly append a null terminator + char* newBuffer{newEntry->allocateBuffer(testCaseKey, newBufferSize)}; + memset(newBuffer, 0u, newBufferSize); + memcpy(newBuffer, a.data(), a.size()); +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaFuseOldMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaFuseOldMutator.hpp new file mode 100644 index 0000000..8527c85 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaFuseOldMutator.hpp @@ -0,0 +1,57 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "RadamsaByteMutatorBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaFuseOldMutator: public MutatorModule, public RadamsaByteMutatorBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaFuseOldMutator(std::string name); + virtual ~RadamsaFuseOldMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand* rand = VmfRand::getInstance(); +}; +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaFuseThisMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaFuseThisMutator.cpp new file mode 100644 index 0000000..5326f8a --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaFuseThisMutator.cpp @@ -0,0 +1,119 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaFuseThisMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaFuseThisMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaFuseThisMutator::build(std::string name) +{ + return new RadamsaFuseThisMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaFuseThisMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaFuseThisMutator::RadamsaFuseThisMutator object + * + * @param name The of the name module + */ +RadamsaFuseThisMutator::RadamsaFuseThisMutator(std::string name) : MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the RadamsaFuseThisMutator::RadamsaFuseThisMutator object + * + */ +RadamsaFuseThisMutator::~RadamsaFuseThisMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaFuseThisMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +void RadamsaFuseThisMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + // Combines a prefix substring and a suffix substring from random indexes of the buffer + // NOTE: Very likely to return buffer unmodified for small buffer sizes + + const size_t minimumSize{1u}; + const size_t minimumSeedIndex{0u}; + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); + + if (originalSize < minimumSize) { + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; + } + if (minimumSeedIndex > originalSize - 1u) { + throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + } + if (originalBuffer == nullptr) { + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + } + + vector data(originalBuffer, originalBuffer + originalSize); + vector new_data = fuse(data, data, this->rand); + + const size_t newBufferSize{new_data.size() + 1}; // +1 to implicitly append a null terminator + char* newBuffer{newEntry->allocateBuffer(testCaseKey, newBufferSize)}; + memset(newBuffer, 0u, newBufferSize); + memcpy(newBuffer, new_data.data(), new_data.size()); +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaFuseThisMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaFuseThisMutator.hpp new file mode 100644 index 0000000..c541d2d --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaFuseThisMutator.hpp @@ -0,0 +1,57 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "RadamsaByteMutatorBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaFuseThisMutator: public MutatorModule, public RadamsaByteMutatorBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaFuseThisMutator(std::string name); + virtual ~RadamsaFuseThisMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand* rand = VmfRand::getInstance(); +}; +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaInsertLineMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaInsertLineMutator.cpp new file mode 100644 index 0000000..a5309e8 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaInsertLineMutator.cpp @@ -0,0 +1,153 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaInsertLineMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaInsertLineMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaInsertLineMutator::build(std::string name) +{ + return new RadamsaInsertLineMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaInsertLineMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaInsertLineFromElsewhereMutator::RadamsaInsertLineFromElsewhereMutator object + * + * @param name The of the name module + */ +RadamsaInsertLineMutator::RadamsaInsertLineMutator(std::string name) : MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the RadamsaInsertLineFromElsewhereMutator::RadamsaInsertLineFromElsewhereMutator object + * + */ +RadamsaInsertLineMutator::~RadamsaInsertLineMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaInsertLineMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +void RadamsaInsertLineMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + // Insert a random existing line into a random place + + const size_t minimumSize{2}; // minimal case consists of two newlines + const size_t minimumLines{2}; + const size_t minimumSeedIndex{0u}; + const size_t characterIndex{0u}; + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); + + const size_t numLines{ + GetNumberOfLinesAfterIndex( + originalBuffer, + originalSize, + characterIndex)}; + + if (originalSize < minimumSize) + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 2", RuntimeException::USAGE_ERROR}; + + if (minimumSeedIndex > originalSize - 1u) + throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + + if (originalBuffer == nullptr) + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + + if (numLines < minimumLines) { + throw RuntimeException{"The buffer's minimum number of lines must be greater than or equal to 2", RuntimeException::USAGE_ERROR}; + } + + std::vector lineOrder(numLines); + std::vector lines(numLines); + for(size_t i{0}; i < numLines; ++i) { + lineOrder[i] = i; + lines[i] = GetLineData( + originalBuffer, + originalSize, + i, + numLines); + } + + const size_t original_lineIndex = this->rand->randBetween(characterIndex, numLines - 1); + const size_t new_lineIndex = this->rand->randBetween(characterIndex, numLines); + + lineOrder.insert(lineOrder.begin() + new_lineIndex, original_lineIndex); + + // create new buffer with modified order + const size_t newBufferSize{originalSize + lines[original_lineIndex].Size + 1u}; // +1 to implicitly append null terminator + char* newBuffer{newEntry->allocateBuffer(testCaseKey, static_cast(newBufferSize))}; + memset(newBuffer, 0u, newBufferSize); + for( + size_t i{0}, nextBufferIndex{0}; + i < lineOrder.size(); + nextBufferIndex += lines[lineOrder[i]].Size, ++i + ) { + memcpy( + newBuffer + nextBufferIndex, + originalBuffer + lines[lineOrder[i]].StartIndex, + lines[lineOrder[i]].Size + ); + } +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaInsertLineMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaInsertLineMutator.hpp new file mode 100644 index 0000000..75094da --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaInsertLineMutator.hpp @@ -0,0 +1,57 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "RadamsaLineMutatorBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaInsertLineMutator: public MutatorModule, public RadamsaLineMutatorBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaInsertLineMutator(std::string name); + virtual ~RadamsaInsertLineMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand* rand = VmfRand::getInstance(); +}; +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaInsertUnicodeMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaInsertUnicodeMutator.cpp new file mode 100644 index 0000000..daee94e --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaInsertUnicodeMutator.cpp @@ -0,0 +1,170 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaInsertUnicodeMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaInsertUnicodeMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaInsertUnicodeMutator::build(std::string name) +{ + return new RadamsaInsertUnicodeMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaInsertUnicodeMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaInsertUnicodeMutator::RadamsaInsertUnicodeMutator object + * + * @param name The of the name module + */ +RadamsaInsertUnicodeMutator::RadamsaInsertUnicodeMutator(std::string name) : MutatorModule(name) +{ + // rand->randInit(); + + // these values copied from github.com/microsoft/rusty-radamsa/blob/main/src/mutations.rs#L677 + this->funnyUnicode.push_back(this->encodeUtf8(U'\u202E')); // Right to Left Override + this->funnyUnicode.push_back(this->encodeUtf8(U'\u202D')); // Left to Right Override + this->funnyUnicode.push_back(this->encodeUtf8(U'\u180E')); // Mongolian Vowel Separator + this->funnyUnicode.push_back(this->encodeUtf8(U'\u2060')); // Word Joiner + this->funnyUnicode.push_back(this->encodeUtf8(U'\uFEFE')); // reserved + this->funnyUnicode.push_back(this->encodeUtf8(U'\uFFFF')); // not a character + this->funnyUnicode.push_back(this->encodeUtf8(U'\u0FED')); // unassigned + this->funnyUnicode.push_back({0xed, 0xba, 0xad}); // U+DEAD illegal low surrogate + this->funnyUnicode.push_back({0xed, 0xaa, 0xad}); // U+DAAD illegal high surrogate + this->funnyUnicode.push_back(this->encodeUtf8(U'\uF8FF')); // private use char (Apple) + this->funnyUnicode.push_back(this->encodeUtf8(U'\uFF0F')); // full width solidus + this->funnyUnicode.push_back(this->encodeUtf8(U'\U0001D7D6')); // MATHEMATICAL BOLD DIGIT EIGHT + this->funnyUnicode.push_back(this->encodeUtf8(U'\u00DF')); // IDNA deviant + this->funnyUnicode.push_back(this->encodeUtf8(U'\uFDFD')); // expands by 11x (UTF-8) and 18x (UTF-16) NFKC + this->funnyUnicode.push_back(this->encodeUtf8(U'\u0390')); // expands by 3x (UTF-8) NFD + this->funnyUnicode.push_back(this->encodeUtf8(U'\u1F82')); // expands by 4x (UTF-16) NFD + this->funnyUnicode.push_back(this->encodeUtf8(U'\uFB2C')); // expands by 3x (UTF-16) under NFC + this->funnyUnicode.push_back(this->encodeUtf8(U'\U0001D160')); // expands by 3x (UTF-8) under NFC + this->funnyUnicode.push_back({0xf4, 0x8f, 0xbf, 0xbe}); // illegal outside end of max range U+10FFFF + this->funnyUnicode.push_back({239, 191, 191}); // 65535 + this->funnyUnicode.push_back({240, 144, 128, 128}); // 65536 + this->funnyUnicode.push_back({0xef, 0xbb, 0xbf}); // the canonical utf8 bom + this->funnyUnicode.push_back({0xfe, 0xff}); // utf16 be bom + this->funnyUnicode.push_back({0xff, 0xfe}); // utf16 le bom + this->funnyUnicode.push_back({0, 0, 0xff, 0xff}); // ascii null be + this->funnyUnicode.push_back({0xff, 0xff, 0, 0}); // ascii null le + this->funnyUnicode.push_back({43, 47, 118, 56}); // and some others from wikipedia + this->funnyUnicode.push_back({43, 47, 118, 57}); + this->funnyUnicode.push_back({43, 47, 118, 43}); + this->funnyUnicode.push_back({43, 47, 118, 47}); + this->funnyUnicode.push_back({247, 100, 76}); + this->funnyUnicode.push_back({221, 115, 102, 115}); + this->funnyUnicode.push_back({14, 254, 255}); + this->funnyUnicode.push_back({251, 238, 40}); + this->funnyUnicode.push_back({251, 238, 40, 255}); + this->funnyUnicode.push_back({132, 49, 149, 51}); +} + +/** + * @brief Destroy the RadamsaInsertUnicodeMutator::RadamsaInsertUnicodeMutator object + * + */ +RadamsaInsertUnicodeMutator::~RadamsaInsertUnicodeMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaInsertUnicodeMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +void RadamsaInsertUnicodeMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + // Insert a "funny" unicode sequence into a random index + + const size_t minimumSize{0u}; + const size_t minimumSeedIndex{0u}; + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); + + if (originalSize < minimumSize) { + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 0", RuntimeException::USAGE_ERROR}; + } + if (minimumSeedIndex > originalSize - 1u) { + throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + } + if (originalBuffer == nullptr) { + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + } + + std::vector data(originalBuffer, originalBuffer + originalSize); + + const size_t lower{0}; + size_t upper{data.size() - 1}; + const size_t insert_index = this->rand->randBetween(lower, upper); + + upper = this->funnyUnicode.size() - 1; + const std::vector toInsert = this->funnyUnicode[this->rand->randBetween(lower, upper)]; + + data.insert( + data.begin() + insert_index, + toInsert.rbegin(), + toInsert.rend() + ); + + const size_t newBufferSize{data.size() + 1}; // +1 to implicitly append a null terminator + char* newBuffer{newEntry->allocateBuffer(testCaseKey, newBufferSize)}; + memset(newBuffer, 0u, newBufferSize); + memcpy(newBuffer, data.data(), data.size()); + + return; +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaInsertUnicodeMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaInsertUnicodeMutator.hpp new file mode 100644 index 0000000..ea369b8 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaInsertUnicodeMutator.hpp @@ -0,0 +1,58 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "RadamsaByteMutatorBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaInsertUnicodeMutator: public MutatorModule, public RadamsaByteMutatorBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaInsertUnicodeMutator(std::string name); + virtual ~RadamsaInsertUnicodeMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand* rand = VmfRand::getInstance(); + std::vector> funnyUnicode; +}; +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaLineMutatorBase.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaLineMutatorBase.hpp index 45ad5f4..1703657 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaLineMutatorBase.hpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaLineMutatorBase.hpp @@ -1,31 +1,21 @@ /* ============================================================================= - * Vader Modular Fuzzer - * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2025 The Charles Stark Draper Laboratory, Inc. * * - * Effort sponsored by the U.S. Government under Other Transaction number - * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government - * is authorized to reproduce and distribute reprints for Governmental purposes - * notwithstanding any copyright notation thereon. - * - * The views and conclusions contained herein are those of the authors and - * should not be interpreted as necessarily representing the official policies - * or endorsements, either expressed or implied, of the U.S. Government. - * * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * - * @license GPL-3.0-or-later + * + * @license GPL-2.0-only * ===========================================================================*/ #pragma once @@ -393,27 +383,6 @@ class RadamsaLineMutatorBase: public RadamsaMutatorBase return numberOfLines; } - - size_t GetRandomRepetitionLength(VmfRand* rand) noexcept - { - constexpr size_t MINIMUM_UPPER_LIMIT{0x2u}; - constexpr size_t MAXIMUM_UPPER_LIMIT{0x20000u}; - - size_t randomStop{rand->randBetween(0u, MINIMUM_UPPER_LIMIT)}; - size_t randomUpperLimit{MINIMUM_UPPER_LIMIT}; - - while(randomStop != 0u) - { - if(randomUpperLimit == MAXIMUM_UPPER_LIMIT) - break; - - randomUpperLimit <<= 1u; - randomStop = rand->randBetween(0u, MINIMUM_UPPER_LIMIT); - } - - return rand->randBetween(0u, randomUpperLimit) + 1u; // We add one to the return value in order to account for the case where the random upper value is zero. - } - bool IsBinarish( const char* const buffer, const size_t size) @@ -465,10 +434,5 @@ class RadamsaLineMutatorBase: public RadamsaMutatorBase return nBitValue; } - - void PermuteLine() - { - //TODO - } }; -} \ No newline at end of file +} diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaModifyTextNumberMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaModifyTextNumberMutator.cpp new file mode 100644 index 0000000..a294c6d --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaModifyTextNumberMutator.cpp @@ -0,0 +1,182 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaModifyTextNumberMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; +using std::vector; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaModifyTextNumberMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaModifyTextNumberMutator::build(std::string name) +{ + return new RadamsaModifyTextNumberMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaModifyTextNumberMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaModifyTextNumberMutator::RadamsaModifyTextNumberMutator object + * + * @param name The of the name module + */ +RadamsaModifyTextNumberMutator::RadamsaModifyTextNumberMutator(std::string name) : MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the RadamsaModifyTextNumberMutator::RadamsaModifyTextNumberMutator object + * + */ +RadamsaModifyTextNumberMutator::~RadamsaModifyTextNumberMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaModifyTextNumberMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +void RadamsaModifyTextNumberMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + // Mutate a random ASCII number via a randomly selected numerical mutation + + const size_t minimumSize{1u}; + const size_t minimumSeedIndex{0u}; + const size_t minimumNumbers{1u}; + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); + + if (originalSize < minimumSize) { + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; + } + if (minimumSeedIndex > originalSize - 1u) { + throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + } + if (originalBuffer == nullptr) { + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + } + + vector data(originalBuffer, originalBuffer + originalSize); + vector dataNums = this->extractTextualNumbers(data); + + if (dataNums.size() < minimumNumbers) { + throw RuntimeException{"The amount of ASCII numbers must be greater than or equal 1", RuntimeException::USAGE_ERROR}; + } + + NumInfo toMutate = dataNums[this->rand->randBetween(0, dataNums.size() - 1)]; + + const vector interestingNums = this->generateInterestingNumbers(); + unsigned int newValue; + switch (this->rand->randBetween(0, 11)) { + case 0: + newValue = toMutate.value + 1; break; + case 1: + newValue = (toMutate.value > 0) ? toMutate.value - 1 : 0; break; + case 2: + newValue = 0; break; + case 3: + newValue = 1; break; + case 4: + case 5: + case 6: + newValue = interestingNums[ + this->rand->randBetween(0, interestingNums.size() - 1) + ]; break; + case 7: + newValue = toMutate.value + interestingNums[ + this->rand->randBetween(0, interestingNums.size() - 1) + ]; break; + case 8: { + unsigned int val = interestingNums[ + this->rand->randBetween(0, interestingNums.size() - 1) + ]; + newValue = (toMutate.value > val) ? toMutate.value - val : 0; + break; + } + case 9: + newValue = 2 * toMutate.value; break; + default: { + unsigned int n = this->rand->randBetween(1, 128); + unsigned int s = this->rand->randBetween(0, 2); + newValue = (s == 0 && toMutate.value > n) ? (toMutate.value - n) : (toMutate.value + n); + break; + } + } + + std::string newValueStr = std::to_string(newValue); + vector new_data; + new_data.insert( // everything before the original value + new_data.end(), + data.begin(), + data.begin() + toMutate.offset + ); + new_data.insert( // the new value + new_data.end(), + newValueStr.begin(), + newValueStr.end() + ); + new_data.insert( // everything after the original value + new_data.end(), + data.begin() + toMutate.offset + toMutate.length, + data.end() + ); + + const size_t newBufferSize{new_data.size() + 1}; // +1 to implicitly append a null terminator + char* newBuffer{newEntry->allocateBuffer(testCaseKey, newBufferSize)}; + memset(newBuffer, 0u, newBufferSize); + memcpy(newBuffer, new_data.data(), new_data.size()); +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaModifyTextNumberMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaModifyTextNumberMutator.hpp new file mode 100644 index 0000000..d24a8c4 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaModifyTextNumberMutator.hpp @@ -0,0 +1,57 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "RadamsaByteMutatorBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaModifyTextNumberMutator: public MutatorModule, public RadamsaByteMutatorBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaModifyTextNumberMutator(std::string name); + virtual ~RadamsaModifyTextNumberMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand* rand = VmfRand::getInstance(); +}; +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaMutatorBase.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaMutatorBase.hpp index 5dd2599..ba62c36 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaMutatorBase.hpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaMutatorBase.hpp @@ -40,6 +40,24 @@ namespace vmf class RadamsaMutatorBase { public: - // universal helper functions go here +size_t GetRandomRepetitionLength(VmfRand* rand) noexcept +{ + constexpr size_t MINIMUM_UPPER_LIMIT{0x2u}; + constexpr size_t MAXIMUM_UPPER_LIMIT{0x20000u}; + + size_t randomStop{rand->randBetween(0u, MINIMUM_UPPER_LIMIT)}; + size_t randomUpperLimit{MINIMUM_UPPER_LIMIT}; + + while(randomStop != 0u) + { + if(randomUpperLimit == MAXIMUM_UPPER_LIMIT) + break; + + randomUpperLimit <<= 1u; + randomStop = rand->randBetween(0u, MINIMUM_UPPER_LIMIT); + } + + return rand->randBetween(0u, randomUpperLimit) + 1u; // We add one to the return value in order to account for the case where the random upper value is zero. +} }; } \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaPermuteLinesMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaPermuteLinesMutator.cpp new file mode 100644 index 0000000..d22cecd --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaPermuteLinesMutator.cpp @@ -0,0 +1,166 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaPermuteLinesMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaPermuteLinesMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaPermuteLinesMutator::build(std::string name) +{ + return new RadamsaPermuteLinesMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaPermuteLinesMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaPermuteLinesMutator::RadamsaPermuteLinesMutator object + * + * @param name The of the name module + */ +RadamsaPermuteLinesMutator::RadamsaPermuteLinesMutator(std::string name) : MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the RadamsaPermuteLinesMutator::RadamsaPermuteLinesMutator object + * + */ +RadamsaPermuteLinesMutator::~RadamsaPermuteLinesMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaPermuteLinesMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +void RadamsaPermuteLinesMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + // Randomize the order of given lines + + const size_t minimumSize{3u}; // minimal case consists of three newlines + const size_t minimumLines{3u}; // for two lines, just use SwapLine + const size_t minimumSeedIndex{0u}; + const size_t characterIndex{0u}; + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); + + const size_t numLines{ + GetNumberOfLinesAfterIndex( + originalBuffer, + originalSize, + characterIndex)}; + + if (originalSize < minimumSize) + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 3", RuntimeException::USAGE_ERROR}; + + if (minimumSeedIndex > originalSize - 1u) + throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + + if (originalBuffer == nullptr) + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + + if (numLines < minimumLines) { + throw RuntimeException{"The buffer's minimum number of lines must be greater than or equal to 3", RuntimeException::USAGE_ERROR}; + } + + // create and initialize vectors of indeces and lines + std::vector lineOrder(numLines); + std::vector lines(numLines); + for(size_t i{0}; i < numLines; ++i) { + lineOrder[i] = i; + lines[i] = GetLineData( + originalBuffer, + originalSize, + i, + numLines); + } + + // randomize the line order + // homebrew Fisher-Yates shuffle because std::shuffle can't use VmfRand + std::vector shuffledLines(numLines); + for(size_t i{numLines - 1}; i > 0; --i) { + long unsigned int min = 0; + long unsigned int max = static_cast(i); + size_t randIndex = this->rand->randBetween(min, max); + + // swap index values + const size_t temp = lineOrder[i]; + lineOrder[i] = lineOrder[randIndex]; + lineOrder[randIndex] = temp; + + // copy into shuffled order + shuffledLines[i] = lines[lineOrder[i]]; + } + + // create new buffer with modified order + const size_t newBufferSize{originalSize + 1u}; // +1 to implicitly append null terminator + char* newBuffer{newEntry->allocateBuffer(testCaseKey, static_cast(newBufferSize))}; + memset(newBuffer, 0u, newBufferSize); + for( + size_t i{0}, nextBufferIndex{0}; + i < numLines; + nextBufferIndex += lines[lineOrder[i]].Size, ++i + ) { + memcpy( + newBuffer + nextBufferIndex, + originalBuffer + lines[lineOrder[i]].StartIndex, + lines[lineOrder[i]].Size + ); + } +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaPermuteLinesMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaPermuteLinesMutator.hpp new file mode 100644 index 0000000..ab6f7e9 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaPermuteLinesMutator.hpp @@ -0,0 +1,57 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "RadamsaLineMutatorBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaPermuteLinesMutator: public MutatorModule, public RadamsaLineMutatorBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaPermuteLinesMutator(std::string name); + virtual ~RadamsaPermuteLinesMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand* rand = VmfRand::getInstance(); +}; +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteMutator.cpp index 0250340..f44fad7 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteMutator.cpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteMutator.cpp @@ -110,7 +110,7 @@ void RadamsaRepeatByteMutator::mutateTestCase(StorageModule& storage, StorageEnt // The new buffer size will contain a random number of additional elements since we are repeating a random byte. // Furthermore, it will contain one more element since we are appending a null-terminator to the end. - const size_t numberOfRandomByteRepetitions{GetRandomByteRepetitionLength(rand)}; + const size_t numberOfRandomByteRepetitions{GetRandomRepetitionLength(rand)}; const size_t newBufferSize{originalSize + numberOfRandomByteRepetitions + 1u}; // Allocate the new buffer and set it's elements to zero. diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteSequenceMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteSequenceMutator.cpp new file mode 100644 index 0000000..6c15f9f --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteSequenceMutator.cpp @@ -0,0 +1,150 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaRepeatByteSequenceMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaRepeatByteSequenceMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaRepeatByteSequenceMutator::build(std::string name) +{ + return new RadamsaRepeatByteSequenceMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaRepeatByteSequenceMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaRepeatByteSequenceMutator::RadamsaRepeatByteSequenceMutator object + * + * @param name The of the name module + */ +RadamsaRepeatByteSequenceMutator::RadamsaRepeatByteSequenceMutator(std::string name) : MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the RadamsaRepeatByteSequenceMutator::RadamsaRepeatByteSequenceMutator object + * + */ +RadamsaRepeatByteSequenceMutator::~RadamsaRepeatByteSequenceMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaRepeatByteSequenceMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +void RadamsaRepeatByteSequenceMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + // select a random number of consecutive bytes and repeat them a random number of times + + constexpr size_t minimumSize{2u}; + const size_t minimumSeedIndex{0u}; + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); + + if (originalSize < minimumSize) + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 2", RuntimeException::USAGE_ERROR}; + + if (minimumSeedIndex > originalSize - 1u) + throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + + if (originalBuffer == nullptr) + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + + + + // Select random indexes for the start and end of the sequence + const size_t start_lower{0u}; + const size_t start_upper{originalSize - 1u - 1u}; // additional -1 to leave at least one byte at the end + const size_t start_index{rand->randBetween(start_lower, start_upper)}; + + const size_t end_lower{start_index + 1u}; + const size_t end_upper{originalSize - 1u}; + const size_t end_index{rand->randBetween(end_lower, end_upper)}; + + // Get random number of sequence repetitions + const size_t numberOfRepetitions{GetRandomRepetitionLength(rand)}; + + // Calculate the size of the modified buffer + const size_t seq_len{end_index - start_index + 1u}; + const size_t newBufferSize{originalSize + (seq_len * numberOfRepetitions) + 1u}; // +1 because we're appending a null-terminator + + // Allocate the new buffer and set it's elements to zero. + char* newBuffer{newEntry->allocateBuffer(testCaseKey, static_cast(newBufferSize))}; + memset(newBuffer, 0u, newBufferSize); + + // Copy pre-sequence into modified buffer + memcpy(newBuffer, originalBuffer, start_index); + + // Copy post-sequence into modified buffer + memcpy( + newBuffer, + originalBuffer + start_index + (seq_len * numberOfRepetitions), + originalSize - end_index - 1u + ); + + // Fill the rest with the byte sequence + for (size_t i = 1; i < numberOfRepetitions; ++i) { + memcpy( + newBuffer + start_index + (i * seq_len), + originalBuffer + start_index, + seq_len + ); + } +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteSequenceMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteSequenceMutator.hpp new file mode 100644 index 0000000..60c276d --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatByteSequenceMutator.hpp @@ -0,0 +1,57 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "RadamsaByteMutatorBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaRepeatByteSequenceMutator: public MutatorModule, public RadamsaByteMutatorBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaRepeatByteSequenceMutator(std::string name); + virtual ~RadamsaRepeatByteSequenceMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand* rand = VmfRand::getInstance(); +}; +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatPathMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatPathMutator.cpp new file mode 100644 index 0000000..5a0c1e4 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatPathMutator.cpp @@ -0,0 +1,143 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaRepeatPathMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaRepeatPathMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaRepeatPathMutator::build(std::string name) +{ + return new RadamsaRepeatPathMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaRepeatPathMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaRepeatPathMutator::RadamsaRepeatPathMutator object + * + * @param name The of the name module + */ +RadamsaRepeatPathMutator::RadamsaRepeatPathMutator(std::string name) : MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the RadamsaRepeatPathMutator::RadamsaRepeatPathMutator object + * + */ +RadamsaRepeatPathMutator::~RadamsaRepeatPathMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaRepeatPathMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +void RadamsaRepeatPathMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + // Replace a random node's random child with a random amount of recursive copies of itself + + const size_t minimumSize{4u}; // minimal case consists of two single-character nodes + const size_t minimumSeedIndex{0u}; + const size_t minimumNodes{2u}; + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); + + if (originalSize < minimumSize) { + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 4", RuntimeException::USAGE_ERROR}; + } + if (minimumSeedIndex > originalSize - 1u) { + throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + } + if (originalBuffer == nullptr) { + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + } + + const std::string treeStr(originalBuffer, originalSize); + Tree tr(treeStr); + + size_t numNodes = tr.countNodes(tr.root); + if (numNodes < minimumNodes) { + throw RuntimeException{"The number of nodes must be greater than or equal to 2", RuntimeException::USAGE_ERROR}; + } + + const size_t lower{0u}; + size_t upper{numNodes - 1}; + size_t parentIndex; + Node* parent; + do { + parentIndex = this->rand->randBetween(lower, upper); + parent = tr.findNodeByIndex(tr.root, parentIndex); + } while (parent->children.size() <= 0); // find a parent that actually has children + + upper = parent->children.size() - 1; + size_t childIndex{this->rand->randBetween(lower, upper)}; + size_t numReps = this->GetRandomRepetitionLength(this->rand); + + tr.repeatPath(parent, childIndex, numReps); + + const string modTreeStr = tr.toString(tr.root); + const size_t newBufferSize{modTreeStr.length() + 1}; // +1 to implicitly append a null terminator + + char* newBuffer{newEntry->allocateBuffer(testCaseKey, newBufferSize)}; + memset(newBuffer, 0u, newBufferSize); + + std::strcpy(newBuffer, modTreeStr.c_str()); + return; +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatPathMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatPathMutator.hpp new file mode 100644 index 0000000..88a6404 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaRepeatPathMutator.hpp @@ -0,0 +1,57 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "RadamsaTreeMutatorBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaRepeatPathMutator: public MutatorModule, public RadamsaTreeMutatorBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaRepeatPathMutator(std::string name); + virtual ~RadamsaRepeatPathMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand* rand = VmfRand::getInstance(); +}; +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaReplaceLineMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaReplaceLineMutator.cpp new file mode 100644 index 0000000..b6131cd --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaReplaceLineMutator.cpp @@ -0,0 +1,157 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaReplaceLineMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaReplaceLineMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaReplaceLineMutator::build(std::string name) +{ + return new RadamsaReplaceLineMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaReplaceLineMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaReplaceLineMutator::RadamsaReplaceLineMutator object + * + * @param name The of the name module + */ +RadamsaReplaceLineMutator::RadamsaReplaceLineMutator(std::string name) : MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the RadamsaReplaceLineMutator::RadamsaReplaceLineMutator object + * + */ +RadamsaReplaceLineMutator::~RadamsaReplaceLineMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaReplaceLineMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +void RadamsaReplaceLineMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + // Move a random line to a random place in the line ordering + + const size_t minimumSize{2}; // minimal case consists of two newlines + const size_t minimumLines{2}; + const size_t minimumSeedIndex{0u}; + const size_t characterIndex{0u}; + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); + + const size_t numLines{ + GetNumberOfLinesAfterIndex( + originalBuffer, + originalSize, + characterIndex)}; + + if (originalSize < minimumSize) + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 2", RuntimeException::USAGE_ERROR}; + + if (minimumSeedIndex > originalSize - 1u) + throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + + if (originalBuffer == nullptr) + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + + if (numLines < minimumLines) { + throw RuntimeException{"The buffer's minimum number of lines must be greater than or equal to 2", RuntimeException::USAGE_ERROR}; + } + + // parse line info + std::vector lineOrder(numLines); + std::vector lines(numLines); + for(size_t i{0}; i < numLines; ++i) { + lineOrder[i] = i; + lines[i] = GetLineData( + originalBuffer, + originalSize, + i, + numLines); + } + + const size_t original_lineIndex = this->rand->randBetween(characterIndex, numLines - 1); + const size_t new_lineIndex = this->rand->randBetween(characterIndex, numLines - 2); // extra -1 because vector size is one less after orignal is removed + + // swap original with new + const size_t original_value = lineOrder[original_lineIndex]; + lineOrder.erase(lineOrder.begin() + original_lineIndex); + lineOrder.insert(lineOrder.begin() + new_lineIndex, original_value); + + // create new buffer with modified order + const size_t newBufferSize{originalSize + lines[original_lineIndex].Size + 1u}; // +1 to implicitly append null terminator + char* newBuffer{newEntry->allocateBuffer(testCaseKey, static_cast(newBufferSize))}; + memset(newBuffer, 0u, newBufferSize); + for( + size_t i{0}, nextBufferIndex{0}; + i < lineOrder.size(); + nextBufferIndex += lines[lineOrder[i]].Size, ++i + ) { + memcpy( + newBuffer + nextBufferIndex, + originalBuffer + lines[lineOrder[i]].StartIndex, + lines[lineOrder[i]].Size + ); + } +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaReplaceLineMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaReplaceLineMutator.hpp new file mode 100644 index 0000000..1607298 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaReplaceLineMutator.hpp @@ -0,0 +1,57 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "RadamsaLineMutatorBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaReplaceLineMutator: public MutatorModule, public RadamsaLineMutatorBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaReplaceLineMutator(std::string name); + virtual ~RadamsaReplaceLineMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand* rand = VmfRand::getInstance(); +}; +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaReplaceNodeMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaReplaceNodeMutator.cpp new file mode 100644 index 0000000..bfd7500 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaReplaceNodeMutator.cpp @@ -0,0 +1,138 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaReplaceNodeMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaReplaceNodeMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaReplaceNodeMutator::build(std::string name) +{ + return new RadamsaReplaceNodeMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaReplaceNodeMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaReplaceNodeMutator::RadamsaReplaceNodeMutator object + * + * @param name The of the name module + */ +RadamsaReplaceNodeMutator::RadamsaReplaceNodeMutator(std::string name) : MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the RadamsaReplaceNodeMutator::RadamsaReplaceNodeMutator object + * + */ +RadamsaReplaceNodeMutator::~RadamsaReplaceNodeMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaReplaceNodeMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +void RadamsaReplaceNodeMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + // Replaces an random node with another random node + + const size_t minimumSize{4u}; // minimal case consists of two single-character nodes + const size_t minimumSeedIndex{0u}; + const size_t minimumNodes{2u}; + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); + + if (originalSize < minimumSize) { + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 4", RuntimeException::USAGE_ERROR}; + } + if (minimumSeedIndex > originalSize - 1u) { + throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + } + if (originalBuffer == nullptr) { + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + } + + const std::string treeStr(originalBuffer, originalSize); + Tree tr(treeStr); + + size_t numNodes = tr.countNodes(tr.root); + if (numNodes < minimumNodes) { + throw RuntimeException{"The number of nodes must be greater than or equal to 2", RuntimeException::USAGE_ERROR}; + } + + const size_t lower{0u}; + const size_t upper{numNodes - 1}; + size_t nodeIndexToReplace{this->rand->randBetween(lower, upper)}; // not const, because findNodeByIndex will modify it + size_t nodeIndexToCopy{this->rand->randBetween(lower, upper)}; // ^ + + if(nodeIndexToReplace != nodeIndexToCopy) { + Node* toReplace = tr.findNodeByIndex(tr.root, nodeIndexToReplace); + Node* toCopy = tr.findNodeByIndex(tr.root, nodeIndexToCopy); + tr.replaceNode(toReplace, toCopy); + } + + const string modTreeStr = tr.toString(tr.root); + const size_t newBufferSize{modTreeStr.length() + 1}; // +1 to implicitly append a null terminator + + char* newBuffer{newEntry->allocateBuffer(testCaseKey, newBufferSize)}; + memset(newBuffer, 0u, newBufferSize); + + std::strcpy(newBuffer, modTreeStr.c_str()); +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaReplaceNodeMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaReplaceNodeMutator.hpp new file mode 100644 index 0000000..35adeac --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaReplaceNodeMutator.hpp @@ -0,0 +1,57 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "RadamsaTreeMutatorBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaReplaceNodeMutator: public MutatorModule, public RadamsaTreeMutatorBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaReplaceNodeMutator(std::string name); + virtual ~RadamsaReplaceNodeMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand* rand = VmfRand::getInstance(); +}; +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaSwapNodesMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaSwapNodesMutator.cpp new file mode 100644 index 0000000..a9eb35a --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaSwapNodesMutator.cpp @@ -0,0 +1,139 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaSwapNodesMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaSwapNodesMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaSwapNodesMutator::build(std::string name) +{ + return new RadamsaSwapNodesMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaSwapNodesMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaSwapNodesMutator::RadamsaSwapNodesMutator object + * + * @param name The of the name module + */ +RadamsaSwapNodesMutator::RadamsaSwapNodesMutator(std::string name) : MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the RadamsaSwapNodesMutator::RadamsaSwapNodesMutator object + * + */ +RadamsaSwapNodesMutator::~RadamsaSwapNodesMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaSwapNodesMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +void RadamsaSwapNodesMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + // Swaps two random nodes pairwise + + const size_t minimumSize{4u}; // minimal case consists of two single-character nodes + const size_t minimumSeedIndex{0u}; + const size_t minimumNodes{2u}; + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); + + if (originalSize < minimumSize) { + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 4", RuntimeException::USAGE_ERROR}; + } + if (minimumSeedIndex > originalSize - 1u) { + throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + } + if (originalBuffer == nullptr) { + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + } + + const std::string treeStr(originalBuffer, originalSize); + Tree tr(treeStr); + + size_t numNodes = tr.countNodes(tr.root); + if (numNodes < minimumNodes) { + throw RuntimeException{"The number of nodes must be greater than or equal to 2", RuntimeException::USAGE_ERROR}; + } + + const size_t lower{0u}; + const size_t upper{numNodes - 1}; + size_t nodeIndex1{this->rand->randBetween(lower, upper)}; // not const, because findNodeByIndex will modify it + size_t nodeIndex2{this->rand->randBetween(lower, upper)}; // ^ + + if(nodeIndex1 != nodeIndex2) { + Node* node1 = tr.findNodeByIndex(tr.root, nodeIndex1); + Node* node2 = tr.findNodeByIndex(tr.root, nodeIndex2); + tr.swapNodes(node1, node2); + } + + const string modTreeStr = tr.toString(tr.root); + const size_t newBufferSize{modTreeStr.length() + 1}; // +1 to implicitly append a null terminator + + char* newBuffer{newEntry->allocateBuffer(testCaseKey, newBufferSize)}; + memset(newBuffer, 0u, newBufferSize); + + std::strcpy(newBuffer, modTreeStr.c_str()); + return; +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaSwapNodesMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaSwapNodesMutator.hpp new file mode 100644 index 0000000..0f2848f --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaSwapNodesMutator.hpp @@ -0,0 +1,57 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "RadamsaTreeMutatorBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaSwapNodesMutator: public MutatorModule, public RadamsaTreeMutatorBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaSwapNodesMutator(std::string name); + virtual ~RadamsaSwapNodesMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand* rand = VmfRand::getInstance(); +}; +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaTreeMutatorBase.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaTreeMutatorBase.hpp new file mode 100644 index 0000000..2f26edd --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaTreeMutatorBase.hpp @@ -0,0 +1,344 @@ +/* ============================================================================= + * Vader Modular Fuzzer + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-3.0-or-later + * ===========================================================================*/ + +#pragma once + +#include +#include "RadamsaMutatorBase.hpp" +#include "RuntimeException.hpp" +#include "VmfRand.hpp" + +using std::string; + +namespace vmf +{ +/** + * + */ +class RadamsaTreeMutatorBase: public RadamsaMutatorBase +{ +public: + RadamsaTreeMutatorBase() = default; + virtual ~RadamsaTreeMutatorBase() = default; + + struct Node + { + string value; + Node* parent; + std::vector children; + + Node(string v, Node* p = nullptr) : value(v), parent(p) {}; + + // Disable copy constructor and copy assignment + Node(const Node&) = delete; + Node& operator=(const Node&) = delete; + + ~Node() { + // DO NOT delete parent; parent owns this node, not the other way around + + // copying to avoid iterator invalidation via deleting an element while still looping over the vector + std::vector childrenCopy = this->children; + for(Node* child : childrenCopy) { + delete child; + } + + return; + } + + Node* deepCopy(Node* newParent = nullptr) const { + // Create copy of self and children, but as separate objects, and attach to newParent + + Node* selfCopy = new Node(this->value, newParent); + for(Node* child : this->children) { + selfCopy->children.push_back(child->deepCopy(selfCopy)); + } + + // if (newParent) newParent->children.push_back(selfCopy); + + return selfCopy; + } + }; + + struct Tree + { + private: + // parses a Tree from a string in the form ""A(B(C)(D))(E)"" + void buildTree(string treeStr) { + if(treeStr.empty()) { + throw RuntimeException{"Tree string is empty", RuntimeException::UNEXPECTED_ERROR}; + } + + std::stack stk; + string value; + for(size_t i = 0; i < treeStr.length(); ++i) { + char ch = treeStr[i]; + + if(std::isspace(ch)) { + continue; + } + else if(ch == '(') { + if(!value.empty()) { + Node* n; + if(stk.empty()) { + n = insertNode(value); + this->root = n; + } + else { + n = insertNode(value, stk.top()); + } + + stk.push(n); + value.clear(); + } + else { + Node* toPush = nullptr; + // upcomming additional child, re-push root + if(stk.empty() && this->root != nullptr) { + toPush = this->root; + } + // upcomming additional child, re-push the most recently popped node + else if(!stk.empty() && !stk.top()->children.empty()) { + toPush = stk.top()->children.back(); + } + + if(toPush != nullptr) { + stk.push(toPush); + } + else { + throw RuntimeException{"Unexpected open bracket without a parent node", RuntimeException::UNEXPECTED_ERROR}; + } + } + } + else if(ch == ')') { + if(stk.empty()) { + throw RuntimeException{"Unmatched open bracket in tree string", RuntimeException::UNEXPECTED_ERROR}; + } + + if(!value.empty()) { + insertNode(value, stk.top()); + + value.clear(); + } + + stk.pop(); + } + else { + value += ch; + } + } + + if(!stk.empty()) { + throw RuntimeException{"Unmatched open bracket in tree string", RuntimeException::UNEXPECTED_ERROR}; + } + + + // case for TreeStr consisting of a single root node + if(!value.empty() && this->root == nullptr) { + this->root = insertNode(value); + } + + return; + } + + public: + Node* root = nullptr; + + Tree() {}; + Tree(string treeStr) { buildTree(treeStr); } + + // deleting copy constructor and copy assignment to avoid shallow copies + Tree(const Tree&) = delete; + Tree& operator=(const Tree&) = delete; + + // Move constructor + Tree(Tree&& other) noexcept { + root = other.root; + other.root = nullptr; + } + + // Move assignment operator + Tree& operator=(Tree&& other) noexcept { + if(this != &other) { // prevents self-assignment + deleteNode(root); + + root = other.root; + other.root = nullptr; + } + return *this; + } + + ~Tree() { deleteNode(this->root); } + + string toString(Node* n) { + // create a parenthesis-delimited string from subtree n + + if(!n) return ""; + + string treeStr(n->value); + + for(Node* child : n->children) { + treeStr += "("; + treeStr += toString(child); + treeStr += ")"; + } + + return treeStr; + } + + size_t countNodes(Node* n) { + if(!n) return 0u; + + size_t count = 1; // count n itself + for(Node* child : n->children) count += countNodes(child); + + return count; + } + + Node* findNodeByIndex(Node* n, size_t& index) { + // traverse tree in-order, returning index-th node + + if(n == nullptr) return nullptr; + if(index == 0) return n; + + --index; + for(Node* child : n->children) { + Node* result = findNodeByIndex(child, index); + if(result != nullptr) return result; + } + + return nullptr; + } + + Node* insertNode(string value, Node* parent = nullptr) { + // Insert a new node as a child of "parent" + + Node* newNode = new Node(value, parent); + if(parent) parent->children.push_back(newNode); + return newNode; + } + + Node* duplicateNode(Node* original, Node* newParent) { + // Duplicates a node and all of its children + + if(!original) { + throw RuntimeException{"Node to be duplicated must not be nullptr", RuntimeException::USAGE_ERROR}; + } + if(original == this->root) { + throw RuntimeException{"Node to be duplicated must not be root", RuntimeException::USAGE_ERROR}; + } + if(!newParent) { + throw RuntimeException{"Parent of the Node to be duplicated must not be nullptr", RuntimeException::USAGE_ERROR}; + } + + Node* duplicate = insertNode(original->value, newParent); + + for(Node* child : original->children) { + duplicate->children.push_back(duplicateNode(child, duplicate)); + } + + return duplicate; + } + + void replaceNode(Node* toReplace, Node* toCopy) { + // Replace one node's value with another's + + if(!toReplace || !toCopy) { + throw RuntimeException{"Both nodes must not be nullptr", RuntimeException::USAGE_ERROR}; + } + + toReplace->value = toCopy->value; + + return; + } + + void swapNodes(Node* node1, Node* node2) { + // Swap the values of two nodes + + if(!node1 || !node2) { + throw RuntimeException{"Both nodes to be swapped must not be nullptr", RuntimeException::USAGE_ERROR}; + } + + const string temp = node1->value; + node1->value = node2->value; + node2->value = temp; + + return; + } + + void deleteNode(Node* n) { + // deallocate n and its children, and remove n from n->parent->children + + if(n == nullptr) return; + + // copying to avoid iterator invalidation via deleting an element while still looping over the vector + std::vector childrenCopy = n->children; + for(Node* child : childrenCopy) { + deleteNode(child); + } + + // erase self from parent's children + if(n->parent) { + auto& parentChildren = n->parent->children; + auto it = std::find(parentChildren.begin(), parentChildren.end(), n); + if(it != parentChildren.end()) { + parentChildren.erase(it); + } + } + + if(n == this->root) this->root = nullptr; + + delete n; + } + + void repeatPath(Node* parent, size_t childIndex, size_t numReps) { + // Replace a child of "parent" with recursive copies of "parent" + + if (numReps <= 0) return; + + if (parent == nullptr) throw RuntimeException{"Node to be repeated must not be nullptr", RuntimeException::USAGE_ERROR}; + if (childIndex >= parent->children.size()) throw RuntimeException{"childIndex is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + + // custom delete here because we want to preserve the child's entry in parent->children + Node* parentCopy = parent->deepCopy(parent); + Node* toReplace = parent->children[childIndex]; + std::vector childrenCopy = toReplace->children; + for(Node* child : childrenCopy) { + this->deleteNode(child); + } + delete toReplace; + + parent->children[childIndex] = parentCopy; + + this->repeatPath(parent->children[childIndex], childIndex, numReps - 1); + return; + } + }; +}; +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaWidenCodePointMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaWidenCodePointMutator.cpp new file mode 100644 index 0000000..02988d2 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaWidenCodePointMutator.cpp @@ -0,0 +1,138 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ + /** + * + */ +#include "RadamsaWidenCodePointMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(RadamsaWidenCodePointMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* - Pointer to the newly created instance + */ +Module* RadamsaWidenCodePointMutator::build(std::string name) +{ + return new RadamsaWidenCodePointMutator(name); +} + +/** + * @brief Initialization method + * + * @param config - Configuration object + */ +void RadamsaWidenCodePointMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new RadamsaWidenCodePointMutator::RadamsaWidenCodePointMutator object + * + * @param name The of the name module + */ +RadamsaWidenCodePointMutator::RadamsaWidenCodePointMutator(std::string name) : MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the RadamsaWidenCodePointMutator::RadamsaWidenCodePointMutator object + * + */ +RadamsaWidenCodePointMutator::~RadamsaWidenCodePointMutator() +{ + +} + +/** + * @brief Register the storage needs for this module + * + * @param registry - StorageRegistry object + */ +void RadamsaWidenCodePointMutator::registerStorageNeeds(StorageRegistry& registry) +{ + // This module does not register for a test case buffer key, because mutators are told which buffer to write in storage + // by the input generator that calls them +} + +void RadamsaWidenCodePointMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + // Replace a random 6-bit ASCII character with an equivalent 2-byte UTF-8-like sequence + + const size_t minimumSize{1u}; + const size_t minimumSeedIndex{0u}; + const size_t originalSize = baseEntry->getBufferSize(testCaseKey); + char* originalBuffer = baseEntry->getBufferPointer(testCaseKey); + + if (originalSize < minimumSize) { + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; + } + if (minimumSeedIndex > originalSize - 1u) { + throw RuntimeException{"Minimum seed index is out of bounds", RuntimeException::INDEX_OUT_OF_RANGE}; + } + if (originalBuffer == nullptr) { + throw RuntimeException{"Input buffer is null", RuntimeException::UNEXPECTED_ERROR}; + } + + std::vector data(originalBuffer, originalBuffer + originalSize); + + const size_t lower{0}; + const size_t upper{data.size() - 1}; + size_t index; + uint8_t codePoint; + size_t attempts = 0; + const size_t max_attempts = data.size(); + do { + attempts++; + if (attempts > max_attempts) { + throw RuntimeException{"Unable to locate a valid ASCII byte", RuntimeException::USAGE_ERROR}; + } + + index = this->rand->randBetween(lower, upper); + codePoint = data[index]; + } while (codePoint < 32 || codePoint > 126); // ensure codePoint is printable ascii + + data[index] = 0b11000000; // set 2-byte utf prefix (110xxxxx) + data.insert(data.begin() + index + 1, codePoint | 0b10000000); // set continuation byte prefix (10xxxxxx) + + const size_t newBufferSize{data.size() + 1}; // +1 to implicitly append a null terminator + char* newBuffer{newEntry->allocateBuffer(testCaseKey, newBufferSize)}; + memset(newBuffer, 0u, newBufferSize); + memcpy(newBuffer, data.data(), data.size()); + + return; +} \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaWidenCodePointMutator.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaWidenCodePointMutator.hpp new file mode 100644 index 0000000..e85c117 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaWidenCodePointMutator.hpp @@ -0,0 +1,57 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2024 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "RadamsaByteMutatorBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaWidenCodePointMutator: public MutatorModule, public RadamsaByteMutatorBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaWidenCodePointMutator(std::string name); + virtual ~RadamsaWidenCodePointMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + private: + VmfRand* rand = VmfRand::getInstance(); +}; +} \ No newline at end of file diff --git a/SamplePackage/CMakeLists.txt b/SamplePackage/CMakeLists.txt new file mode 100644 index 0000000..93c92d3 --- /dev/null +++ b/SamplePackage/CMakeLists.txt @@ -0,0 +1,26 @@ +#=============================================================================== +# Vader Modular Fuzzer (VMF) +# Copyright (c) 2021-2025 The Charles Stark Draper Laboratory, Inc. +# +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 (only) as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# @license GPL-2.0-only +#=============================================================================== + +add_subdirectory(vmf/src) + +#install sample configuration files +install(DIRECTORY test DESTINATION + DESTINATION ${CMAKE_INSTALL_PREFIX} ) + diff --git a/SamplePackage/README.md b/SamplePackage/README.md index 015a0ed..6d4399e 100644 --- a/SamplePackage/README.md +++ b/SamplePackage/README.md @@ -4,9 +4,15 @@ This document gives an overview of the SamplePackage extension package for VMF. +This sample shows how to write a VMF mutator module. You can put multiple VMF modules into +a single shared library. + +The module here doesn't do anything useful. It just shows how to set up your build process to +integrate with VMF. + == Building and installing -Build instructions +Build instructions (see top level project [README.md](../README.md)) == License diff --git a/SamplePackage/vmf/src/CMakeLists.txt b/SamplePackage/vmf/src/CMakeLists.txt index da98d21..117657c 100644 --- a/SamplePackage/vmf/src/CMakeLists.txt +++ b/SamplePackage/vmf/src/CMakeLists.txt @@ -1,17 +1,8 @@ #=============================================================================== # Vader Modular Fuzzer (VMF) -# Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. -# -# -# Effort sponsored by the U.S. Government under Other Transaction number -# W9124P-19-9-0001 between AMTC and the Government. The U.S. Government -# Is authorized to reproduce and distribute reprints for Governmental purposes -# notwithstanding any copyright notation thereon. -# -# The views and conclusions contained herein are those of the authors and -# should not be interpreted as necessarily representing the official policies -# or endorsements, either expressed or implied, of the U.S. Government. -# +# Copyright (c) 2021-2025 The Charles Stark Draper Laboratory, Inc. +# +# # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 (only) as # published by the Free Software Foundation. diff --git a/SamplePackage/vmf/src/modules/CMakeLists.txt b/SamplePackage/vmf/src/modules/CMakeLists.txt index 3a67f54..faa9b43 100644 --- a/SamplePackage/vmf/src/modules/CMakeLists.txt +++ b/SamplePackage/vmf/src/modules/CMakeLists.txt @@ -1,17 +1,8 @@ #=============================================================================== # Vader Modular Fuzzer (VMF) -# Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. -# -# -# Effort sponsored by the U.S. Government under Other Transaction number -# W9124P-19-9-0001 between AMTC and the Government. The U.S. Government -# Is authorized to reproduce and distribute reprints for Governmental purposes -# notwithstanding any copyright notation thereon. -# -# The views and conclusions contained herein are those of the authors and -# should not be interpreted as necessarily representing the official policies -# or endorsements, either expressed or implied, of the U.S. Government. -# +# Copyright (c) 2021-2025 The Charles Stark Draper Laboratory, Inc. +# +# # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 (only) as # published by the Free Software Foundation. @@ -32,23 +23,39 @@ add_library(SampleModule SHARED common/mutator/MyMutator.cpp ) +#Set flag to export all symbols for windows builds +set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) + +# windows needs an additional import to make the logger work +if(WIN32) + target_compile_definitions(SampleModule PRIVATE PLOG_IMPORT) +endif() + # Build-time dependencies for SampleModule link_directories(SampleModule PRIVATE ) # Build-time dependencies for SampleModule target_link_libraries(SampleModule PRIVATE + vmf_framework ) # Build-time dependencies for SampleModule target_include_directories(SampleModule PRIVATE - ${VMF_INSTALL}/include - ${VMF_INSTALL}/include/vmf - ${VMF_INSTALL}/include/plog + ${CMAKE_INSTALL_PREFIX}/include + ${CMAKE_INSTALL_PREFIX}/include/vmf + ${CMAKE_INSTALL_PREFIX}/include/plog ${PROJECT_SOURCE_DIR}/src/module ) # Install SampleModule library in VMF plugins directory install(TARGETS SampleModule - LIBRARY DESTINATION "${VMF_INSTALL}/plugins") + LIBRARY DESTINATION "${CMAKE_INSTALL_PREFIX}/plugins") +#On windows the /plugins directory above is ignored, and everything ends up in /lib and /bin +if(WIN32) + cmake_path(SET WIN_LIB_FILE ${CMAKE_INSTALL_PREFIX}/lib/SampleModule.lib) + cmake_path(SET WIN_DLL_FILE ${CMAKE_INSTALL_PREFIX}/bin/SampleModule.dll) + install(FILES ${WIN_LIB_FILE} ${WIN_DLL_FILE} + DESTINATION ${CMAKE_INSTALL_PREFIX}/plugins) +endif() diff --git a/SamplePackage/vmf/src/modules/common/mutator/MyMutator.cpp b/SamplePackage/vmf/src/modules/common/mutator/MyMutator.cpp index 022d443..472821f 100644 --- a/SamplePackage/vmf/src/modules/common/mutator/MyMutator.cpp +++ b/SamplePackage/vmf/src/modules/common/mutator/MyMutator.cpp @@ -1,17 +1,8 @@ /* ============================================================================= * Vader Modular Fuzzer (VMF) - * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * Copyright (c) 2021-2025 The Charles Stark Draper Laboratory, Inc. * - * - * Effort sponsored by the U.S. Government under Other Transaction number - * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government - * Is authorized to reproduce and distribute reprints for Governmental purposes - * notwithstanding any copyright notation thereon. - * - * The views and conclusions contained herein are those of the authors and - * should not be interpreted as necessarily representing the official policies - * or endorsements, either expressed or implied, of the U.S. Government. - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 (only) as * published by the Free Software Foundation. @@ -78,13 +69,12 @@ MyMutator::~MyMutator() /** * @brief Registers storage needs - * This class uses only the "TEST_CASE" key * * @param registry */ void MyMutator::registerStorageNeeds(StorageRegistry& registry) { - testCaseKey = registry.registerKey("TEST_CASE", StorageRegistry::BUFFER, StorageRegistry::READ_WRITE); + //This module has no direct needs, because mutators are told where to write in storage by the input generator that calls them } /** @@ -94,13 +84,14 @@ void MyMutator::registerStorageNeeds(StorageRegistry& registry) * * @param storage reference to storage * @param baseEntry the base entry to use for mutation - * @return StorageEntry* + * @param newEntry the test case to write to + * @param testCaseKey the field to write to in the new entry * @throws RuntimeException if baseEntry has an empty test case buffer. */ -void MyMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +StorageEntry* MyMutator::createTestCase(StorageModule& storage, StorageEntry* baseEntry) { int inputSize = baseEntry->getBufferSize(testCaseKey); -// char* inputBuffer = baseEntry->getBufferPointer(testCaseKey); + if (inputSize <= 0) { throw RuntimeException( @@ -113,4 +104,5 @@ void MyMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, LOG_INFO << "Not really mutating here, just pretending"; char* outputBuffer = newEntry->allocateBuffer(testCaseKey, 23); strcpy(outputBuffer, "foobar"); + } diff --git a/SamplePackage/vmf/src/modules/common/mutator/MyMutator.hpp b/SamplePackage/vmf/src/modules/common/mutator/MyMutator.hpp index 3c99c79..08f5a75 100644 --- a/SamplePackage/vmf/src/modules/common/mutator/MyMutator.hpp +++ b/SamplePackage/vmf/src/modules/common/mutator/MyMutator.hpp @@ -1,17 +1,8 @@ /* ============================================================================= * Vader Modular Fuzzer (VMF) - * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * Copyright (c) 2021-2025 The Charles Stark Draper Laboratory, Inc. * - * - * Effort sponsored by the U.S. Government under Other Transaction number - * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government - * Is authorized to reproduce and distribute reprints for Governmental purposes - * notwithstanding any copyright notation thereon. - * - * The views and conclusions contained herein are those of the authors and - * should not be interpreted as necessarily representing the official policies - * or endorsements, either expressed or implied, of the U.S. Government. - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 (only) as * published by the Free Software Foundation. @@ -46,7 +37,7 @@ class MyMutator : public MutatorModule virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); private: - int testCaseKey; + }; #endif diff --git a/SamplePackage/vmf/src/modules/common/mutator/README.md b/SamplePackage/vmf/src/modules/common/mutator/README.md deleted file mode 100644 index ddf6926..0000000 --- a/SamplePackage/vmf/src/modules/common/mutator/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Sample module - -This sample shows how to write a VMF mutator module. You can put multiple VMF modules into -a single shared library. - -The module here doesn't do anything useful. It just shows how to set up your build process to -integrate with VMF. - diff --git a/dockerfiles/Dockerfile b/dockerfiles/Dockerfile index a94533d..da78158 100644 --- a/dockerfiles/Dockerfile +++ b/dockerfiles/Dockerfile @@ -13,12 +13,9 @@ RUN apt-get update \ RUN apt-get update \ && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends --fix-missing \ graphviz \ - clang-16 \ clang \ doxygen \ libcurl4-openssl-dev \ - llvm-16 \ - llvm-16-dev \ llvm \ llvm-dev \ lld \ @@ -44,32 +41,36 @@ RUN set -ex \ FROM aflpp AS vmf # Clone, build, install VMF +# TODO temp fix until we update for 5.0.0 RUN set -ex \ && cd /usr/local/src \ - && git clone --depth 1 https://github.com/draperlaboratory/vadermodularfuzzer.git VaderModularFuzzer\ + && git clone https://github.com/draperlaboratory/vadermodularfuzzer.git VaderModularFuzzer\ && cd VaderModularFuzzer \ + && git checkout 4a8b07b6fb4b53ee11f6dee0c0a67d1d4ec7c38d \ && mkdir -p build \ && cd build \ - && cmake -DCMAKE_INSTALL_PREFIX=/usr/local .. \ + && cmake .. \ && make -j \ && make install \ && set +ex -# Copy, build, install VmfExperimental +# Copy VmfExperimental COPY . /usr/local/src/VmfExperimental RUN set -ex \ && cd /usr/local/src/VmfExperimental \ && mkdir build \ && cd build \ - && cmake -DVMF_INSTALL=/usr/local .. \ - && make && make install \ + && cmake -DCMAKE_INSTALL_PREFIX=/usr/local/src/VaderModularFuzzer/build/vmf_install .. \ + && make -j \ + && make install \ && set +ex -# Create experimental config file -RUN set -ex \ - && cd /usr/local/test/config \ - && cp /usr/local/src/VmfExperimental/Radamsa/test/config/experimentalModules.yaml /usr/local/test/config/ \ - && set +ex +# # Create experimental config file +# RUN set -ex \ +# && cd /usr/local/test/config \ +# && cp /usr/local/src/VmfExperimental/Radamsa/test/config/experimentalModules.yaml /usr/local/test/config/ \ +# && set +ex -CMD bash +WORKDIR /usr/local/src/VmfExperimental/build +ENTRYPOINT [ "ctest", "--output-on-failure" ] diff --git a/dockerfiles/Dockerfile.kali b/dockerfiles/Dockerfile.kali deleted file mode 100644 index a94533d..0000000 --- a/dockerfiles/Dockerfile.kali +++ /dev/null @@ -1,75 +0,0 @@ -FROM kalilinux/kali-last-release AS deps - -RUN apt-get update \ - && DEBIAN_FRONTEND="noninteractive" apt-get install -y --no-install-recommends --fix-missing \ - ca-certificates \ - curl \ - gdb \ - git \ - gnupg \ - lsb-release \ - zip - -RUN apt-get update \ - && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends --fix-missing \ - graphviz \ - clang-16 \ - clang \ - doxygen \ - libcurl4-openssl-dev \ - llvm-16 \ - llvm-16-dev \ - llvm \ - llvm-dev \ - lld \ - python3-dev \ - python3-pip \ - python3-setuptools \ - build-essential \ - cmake - -ENV LLVM_CONFIG=llvm-config-16 - -FROM deps AS aflpp - -# Clone and build AFL++ -RUN set -ex \ - && cd /usr/local/src \ - && git clone --depth 1 -b v4.10c https://github.com/AFLplusplus/AFLplusplus.git \ - && cd AFLplusplus \ - && make all \ - && make install \ - && set +ex - -FROM aflpp AS vmf - -# Clone, build, install VMF -RUN set -ex \ - && cd /usr/local/src \ - && git clone --depth 1 https://github.com/draperlaboratory/vadermodularfuzzer.git VaderModularFuzzer\ - && cd VaderModularFuzzer \ - && mkdir -p build \ - && cd build \ - && cmake -DCMAKE_INSTALL_PREFIX=/usr/local .. \ - && make -j \ - && make install \ - && set +ex - -# Copy, build, install VmfExperimental -COPY . /usr/local/src/VmfExperimental - -RUN set -ex \ - && cd /usr/local/src/VmfExperimental \ - && mkdir build \ - && cd build \ - && cmake -DVMF_INSTALL=/usr/local .. \ - && make && make install \ - && set +ex - -# Create experimental config file -RUN set -ex \ - && cd /usr/local/test/config \ - && cp /usr/local/src/VmfExperimental/Radamsa/test/config/experimentalModules.yaml /usr/local/test/config/ \ - && set +ex - -CMD bash diff --git a/test/unittest/CMakeLists.txt b/test/unittest/CMakeLists.txt index b8e93c4..dab4649 100644 --- a/test/unittest/CMakeLists.txt +++ b/test/unittest/CMakeLists.txt @@ -31,8 +31,8 @@ find_package(Threads REQUIRED) SET(TEST_SRCS - ${VMF_INSTALL}/../../test/unittest/ModuleTestHelper.cpp - ${VMF_INSTALL}/../../test/unittest/TestConfigInterface.cpp + ${CMAKE_INSTALL_PREFIX}/../../test/unittest/ModuleTestHelper.cpp + ${CMAKE_INSTALL_PREFIX}/../../test/unittest/TestConfigInterface.cpp ../../Radamsa/test/RadamsaDecrementByteMutatorTest.cpp ../../Radamsa/test/RadamsaDropByteMutatorTest.cpp ../../Radamsa/test/RadamsaFlipByteMutatorTest.cpp @@ -47,6 +47,25 @@ SET(TEST_SRCS ../../Radamsa/test/RadamsaCopyLineCloseByMutatorTest.cpp ../../Radamsa/test/RadamsaRepeatLineMutatorTest.cpp ../../Radamsa/test/RadamsaSwapLineMutatorTest.cpp + ../../Radamsa/test/RadamsaRepeatByteSequenceMutatorTest.cpp + ../../Radamsa/test/RadamsaDeleteByteSequenceMutatorTest.cpp + ../../Radamsa/test/RadamsaPermuteLinesMutatorTest.cpp + ../../Radamsa/test/RadamsaInsertLineMutatorTest.cpp + ../../Radamsa/test/RadamsaReplaceLineMutatorTest.cpp + ../../Radamsa/test/RadamsaTreeMutatorBaseTest.cpp + ../../Radamsa/test/RadamsaDeleteNodeMutatorTest.cpp + ../../Radamsa/test/RadamsaDuplicateNodeMutatorTest.cpp + ../../Radamsa/test/RadamsaReplaceNodeMutatorTest.cpp + ../../Radamsa/test/RadamsaSwapNodesMutatorTest.cpp + ../../Radamsa/test/RadamsaRepeatPathMutatorTest.cpp + ../../Radamsa/test/RadamsaWidenCodePointMutatorTest.cpp + ../../Radamsa/test/RadamsaInsertUnicodeMutatorTest.cpp + ../../Radamsa/test/RadamsaModifyTextNumberMutatorTest.cpp + ../../Radamsa/test/RadamsaFuse_helpers.cpp + ../../Radamsa/test/RadamsaFuseThisMutatorTest.cpp + ../../Radamsa/test/RadamsaFuseNextMutatorTest.cpp + ../../Radamsa/test/RadamsaFuseOldMutatorTest.cpp + ../../Radamsa/test/RadamsaAsciiBadMutatorTest.cpp ) add_executable(VmfTest ${TEST_SRCS}) @@ -54,18 +73,19 @@ add_executable(VmfTest ${TEST_SRCS}) set_target_properties(VmfTest PROPERTIES LINKER_LANGUAGE CXX) target_include_directories(VmfTest PUBLIC - ${VMF_INSTALL}/include - ${VMF_INSTALL}/../../vmf/dependencies/googletest/googletest/include - ${VMF_INSTALL}/../../test/unittest - ${VMF_INSTALL}/../../vmf/src/framework/baseclasses - ${VMF_INSTALL}/../../vmf/src/framework/util + ${CMAKE_INSTALL_PREFIX}/include + ${CMAKE_INSTALL_PREFIX}/../../vmf + ${CMAKE_INSTALL_PREFIX}/../../vmf/dependencies/googletest/googletest/include + ${CMAKE_INSTALL_PREFIX}/../../test/unittest + ${CMAKE_INSTALL_PREFIX}/../../vmf/src/framework/baseclasses + ${CMAKE_INSTALL_PREFIX}/../../vmf/src/framework/util ../../Radamsa/vmf/src/modules/common/mutator ) target_link_directories(VmfTest PUBLIC - ${VMF_INSTALL}/lib - ${VMF_INSTALL}/plugins - ${VMF_INSTALL}/../lib + ${CMAKE_INSTALL_PREFIX}/lib + ${CMAKE_INSTALL_PREFIX}/plugins + ${CMAKE_INSTALL_PREFIX}/../lib ) target_link_libraries(VmfTest From 05ae40f1edbf0bb2533655b0687abd1c4f81a3ee Mon Sep 17 00:00:00 2001 From: GabeClark99 <54868591+GabeClark99@users.noreply.github.com> Date: Tue, 17 Jun 2025 13:01:21 -0500 Subject: [PATCH 29/31] Update for VMF 5.0.1 (#8) * VMF v4.0.0 compatibility * Add Determinism module set AFLDeterministicFeedback: removes testcase execution time from fitness, and ignores hangs which alleviates some determinism issues DeterministicTesterOutput: computes a running checksum of all generated testcase contents and IDs * VMF 5.0.0 Release * VMF 5 Fixes Use latest VMF version Fixes for latest VMF version - explicit casts for VmfRand::randBetween(int, int) - add yaml-cpp --------- Co-authored-by: Joshua Weader Co-authored-by: Dharsee, Komail --- .../src/modules/common/mutator/RadamsaAsciiBadMutator.cpp | 8 ++++---- .../src/modules/common/mutator/RadamsaByteMutatorBase.hpp | 4 ++-- .../common/mutator/RadamsaModifyTextNumberMutator.cpp | 8 ++++---- .../vmf/src/modules/common/mutator/MyMutator.cpp | 2 +- dockerfiles/Dockerfile | 4 ++-- test/unittest/CMakeLists.txt | 1 + 6 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaAsciiBadMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaAsciiBadMutator.cpp index d4c3160..0178654 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaAsciiBadMutator.cpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaAsciiBadMutator.cpp @@ -188,14 +188,14 @@ struct Text { vector out; out.reserve(repeatCount * 8); for (int i = 0; i < repeatCount; ++i) { - const vector& s = sillyStrings[rand->randBetween(0, sillyStrings.size() - 1)]; + const vector& s = sillyStrings[rand->randBetween(0, int(sillyStrings.size() - 1))]; out.insert(out.end(), s.begin(), s.end()); } return out; } void mutateTextData(vector& data, VmfRand* rand) { - size_t byteIndex = rand->randBetween(0, data.size()); + size_t byteIndex = rand->randBetween(0, int(data.size())); int mutationType = rand->randBetween(0, 2); switch (mutationType) { case 0: { @@ -273,11 +273,11 @@ struct Ascii { } if(textChunkIndices.empty()) return; - const size_t chunkIndex = rand->randBetween(0, textChunkIndices.size() - 1); + const size_t chunkIndex = rand->randBetween(0, int(textChunkIndices.size() - 1)); vector& textElems = get>( chunks[textChunkIndices[chunkIndex]].value ); - const size_t elemIndex = rand->randBetween(0, textElems.size() - 1); + const size_t elemIndex = rand->randBetween(0, int(textElems.size() - 1)); textElems[elemIndex].mutate(rand); return; diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaByteMutatorBase.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaByteMutatorBase.hpp index 9a3dea7..05ad426 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaByteMutatorBase.hpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaByteMutatorBase.hpp @@ -201,8 +201,8 @@ class RadamsaByteMutatorBase: public RadamsaMutatorBase ) { if (a.empty() || b.empty()) return nullopt; - size_t aIndex = rand->randBetween(0, a.size() - 1); // -1 because randBetween is max inclusive - size_t bIndex = rand->randBetween(0, b.size() - 1); + size_t aIndex = rand->randBetween(0, int(a.size() - 1)); // -1 because randBetween is max inclusive + size_t bIndex = rand->randBetween(0, int(b.size() - 1)); vector aElem = a[aIndex]; vector bElem = b[bIndex]; return pair, vector>(aElem, bElem); diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaModifyTextNumberMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaModifyTextNumberMutator.cpp index a294c6d..7b0018d 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaModifyTextNumberMutator.cpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaModifyTextNumberMutator.cpp @@ -117,7 +117,7 @@ void RadamsaModifyTextNumberMutator::mutateTestCase(StorageModule& storage, Stor throw RuntimeException{"The amount of ASCII numbers must be greater than or equal 1", RuntimeException::USAGE_ERROR}; } - NumInfo toMutate = dataNums[this->rand->randBetween(0, dataNums.size() - 1)]; + NumInfo toMutate = dataNums[this->rand->randBetween(0, int(dataNums.size() - 1))]; const vector interestingNums = this->generateInterestingNumbers(); unsigned int newValue; @@ -134,15 +134,15 @@ void RadamsaModifyTextNumberMutator::mutateTestCase(StorageModule& storage, Stor case 5: case 6: newValue = interestingNums[ - this->rand->randBetween(0, interestingNums.size() - 1) + this->rand->randBetween(0, int(interestingNums.size() - 1)) ]; break; case 7: newValue = toMutate.value + interestingNums[ - this->rand->randBetween(0, interestingNums.size() - 1) + this->rand->randBetween(0, int(interestingNums.size() - 1)) ]; break; case 8: { unsigned int val = interestingNums[ - this->rand->randBetween(0, interestingNums.size() - 1) + this->rand->randBetween(0, int(interestingNums.size() - 1)) ]; newValue = (toMutate.value > val) ? toMutate.value - val : 0; break; diff --git a/SamplePackage/vmf/src/modules/common/mutator/MyMutator.cpp b/SamplePackage/vmf/src/modules/common/mutator/MyMutator.cpp index 472821f..7adec58 100644 --- a/SamplePackage/vmf/src/modules/common/mutator/MyMutator.cpp +++ b/SamplePackage/vmf/src/modules/common/mutator/MyMutator.cpp @@ -88,7 +88,7 @@ void MyMutator::registerStorageNeeds(StorageRegistry& registry) * @param testCaseKey the field to write to in the new entry * @throws RuntimeException if baseEntry has an empty test case buffer. */ -StorageEntry* MyMutator::createTestCase(StorageModule& storage, StorageEntry* baseEntry) +void MyMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) { int inputSize = baseEntry->getBufferSize(testCaseKey); diff --git a/dockerfiles/Dockerfile b/dockerfiles/Dockerfile index da78158..0ab8b0c 100644 --- a/dockerfiles/Dockerfile +++ b/dockerfiles/Dockerfile @@ -23,7 +23,8 @@ RUN apt-get update \ python3-pip \ python3-setuptools \ build-essential \ - cmake + cmake \ + libyaml-cpp-dev ENV LLVM_CONFIG=llvm-config-16 @@ -46,7 +47,6 @@ RUN set -ex \ && cd /usr/local/src \ && git clone https://github.com/draperlaboratory/vadermodularfuzzer.git VaderModularFuzzer\ && cd VaderModularFuzzer \ - && git checkout 4a8b07b6fb4b53ee11f6dee0c0a67d1d4ec7c38d \ && mkdir -p build \ && cd build \ && cmake .. \ diff --git a/test/unittest/CMakeLists.txt b/test/unittest/CMakeLists.txt index dab4649..ccedd9a 100644 --- a/test/unittest/CMakeLists.txt +++ b/test/unittest/CMakeLists.txt @@ -96,5 +96,6 @@ target_link_libraries(VmfTest CoreModules Threads::Threads Radamsa + yaml-cpp ) gtest_discover_tests(VmfTest) From 7084dbee031dcfa6e0198d9e8fc506f690397a9e Mon Sep 17 00:00:00 2001 From: Gabriel Clark Date: Thu, 19 Jun 2025 10:46:29 -0500 Subject: [PATCH 30/31] Postponing a few mutators minor changes to kali dockerfile --- Radamsa/test/config/experimentalModules.yaml | 40 ++++++++++++-------- dockerfiles/Dockerfile | 15 ++++---- 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/Radamsa/test/config/experimentalModules.yaml b/Radamsa/test/config/experimentalModules.yaml index fec73f3..75c863f 100644 --- a/Radamsa/test/config/experimentalModules.yaml +++ b/Radamsa/test/config/experimentalModules.yaml @@ -13,26 +13,36 @@ vmfModules: - className: StatsOutput GeneticAlgorithmInputGenerator: children: - - className: AFLFlipBitMutator - - className: AFLFlip2BitMutator - - className: AFLFlip4BitMutator - - className: AFLFlipByteMutator - - className: AFLFlip2ByteMutator - - className: AFLFlip4ByteMutator - - className: AFLRandomByteAddSubMutator - - className: AFLRandomByteMutator - - className: AFLDeleteMutator - - className: AFLCloneMutator - - className: AFLSpliceMutator - + - className: RadamsaCopyLineCloseByMutator + - className: RadamsaDecrementByteMutator + - className: RadamsaDeleteByteSequenceMutator + - className: RadamsaDeleteLineMutator + - className: RadamsaDeleteNodeMutator + - className: RadamsaDeleteSequentialLinesMutator - className: RadamsaDropByteMutator + - className: RadamsaDuplicateLineMutator + # - className: RadamsaDuplicateNodeMutator - className: RadamsaFlipByteMutator + - className: RadamsaFuseNextMutator + - className: RadamsaFuseOldMutator + - className: RadamsaFuseThisMutator + - className: RadamsaIncrementByteMutator - className: RadamsaInsertByteMutator - - className: RadamsaRepeatByteMutator + # - className: RadamsaInsertLineMutator + - className: RadamsaInsertUnicodeMutator + # - className: RadamsaModifyTextNumberMutator - className: RadamsaPermuteByteMutator - - className: RadamsaIncrementByteMutator - - className: RadamsaDecrementByteMutator + # - className: RadamsaPermuteLinesMutator - className: RadamsaRandomizeByteMutator + - className: RadamsaRepeatByteMutator + - className: RadamsaRepeatByteSequenceMutator + - className: RadamsaRepeatLineMutator + # - className: RadamsaRepeatPathMutator + # - className: RadamsaReplaceLineMutator + # - className: RadamsaReplaceNodeMutator + # - className: RadamsaSwapLineMutator + # - className: RadamsaSwapNodesMutator + # - className: RadamsaWidenCodePointMutator # Modules-specific parameters #(The SUT-specific portions of these all defined using YAML anchors) diff --git a/dockerfiles/Dockerfile b/dockerfiles/Dockerfile index 0ab8b0c..d5dfef7 100644 --- a/dockerfiles/Dockerfile +++ b/dockerfiles/Dockerfile @@ -66,11 +66,12 @@ RUN set -ex \ && make install \ && set +ex -# # Create experimental config file -# RUN set -ex \ -# && cd /usr/local/test/config \ -# && cp /usr/local/src/VmfExperimental/Radamsa/test/config/experimentalModules.yaml /usr/local/test/config/ \ -# && set +ex +# Create experimental config file +RUN set -ex \ + && cd /usr/local/src/ \ + && cp VmfExperimental/Radamsa/test/config/experimentalModules.yaml VaderModularFuzzer/build/vmf_install/test/config/experimentalModules.yaml \ + && set +ex -WORKDIR /usr/local/src/VmfExperimental/build -ENTRYPOINT [ "ctest", "--output-on-failure" ] +# WORKDIR /usr/local/src/VmfExperimental/build +WORKDIR /usr/local/src/VaderModularFuzzer/build/vmf_install +ENTRYPOINT [ "./bin/vader", "-c", "test/config/experimentalModules.yaml", "-c", "test/haystackSUT/haystack_stdin.yaml" ] From 242963d57302479baf4a92af930cf7085964a09f Mon Sep 17 00:00:00 2001 From: GabeClark99 <54868591+GabeClark99@users.noreply.github.com> Date: Fri, 27 Jun 2025 13:19:45 -0500 Subject: [PATCH 31/31] AFL++ Mutators (#9) * Added AFLPlusPlus Mutators * Fixed CMakeLists format * Fixed CMakeLists * Fixed CMakeLists * Added AFL dependencies * Fixed CMakeLists * Added LibAFL-legacy dependency * LibAFL-legacy dependency * Adjusted LibAFL-legacy dependency * LibAFL-legacy * external dependencies * include external * vmf dependency * Testing rand.h * rand.h test * test rand.h * rand.h test * Include LibAFL-legacy * LibAFL-legacy test * LibAFL-legacy test * LibAFL-legacy test * LibAFL-legacy test * Include AFL-legacy * Test LibAFL-legacy * LibAFL-legacy * Updated for modern releases --------- Co-authored-by: mbohler --- AFLPlusPlus/CMakeLists.txt | 74 +++ AFLPlusPlus/README.md | 14 + AFLPlusPlus/data/README.md | 4 + AFLPlusPlus/docs/README.md | 26 + AFLPlusPlus/src/module/AFLCloneMutator.cpp | 170 ++++++ AFLPlusPlus/src/module/AFLCloneMutator.hpp | 92 +++ .../src/module/AFLDWordAddSubMutator.cpp | 137 +++++ .../src/module/AFLDWordAddSubMutator.hpp | 92 +++ AFLPlusPlus/src/module/AFLDeleteMutator.cpp | 183 ++++++ AFLPlusPlus/src/module/AFLDeleteMutator.hpp | 95 +++ AFLPlusPlus/src/module/AFLFlip2BitMutator.cpp | 135 ++++ AFLPlusPlus/src/module/AFLFlip2BitMutator.hpp | 89 +++ .../src/module/AFLFlip2ByteMutator.cpp | 134 ++++ .../src/module/AFLFlip2ByteMutator.hpp | 92 +++ AFLPlusPlus/src/module/AFLFlip4BitMutator.cpp | 141 +++++ AFLPlusPlus/src/module/AFLFlip4BitMutator.hpp | 92 +++ .../src/module/AFLFlip4ByteMutator.cpp | 142 +++++ .../src/module/AFLFlip4ByteMutator.hpp | 89 +++ AFLPlusPlus/src/module/AFLFlipBitMutator.cpp | 129 ++++ AFLPlusPlus/src/module/AFLFlipBitMutator.hpp | 89 +++ AFLPlusPlus/src/module/AFLFlipByteMutator.cpp | 128 ++++ AFLPlusPlus/src/module/AFLFlipByteMutator.hpp | 89 +++ .../src/module/AFLInteresting16Mutator.cpp | 139 +++++ .../src/module/AFLInteresting16Mutator.hpp | 91 +++ .../src/module/AFLInteresting32Mutator.cpp | 144 +++++ .../src/module/AFLInteresting32Mutator.hpp | 91 +++ .../src/module/AFLInteresting8Mutator.cpp | 134 ++++ .../src/module/AFLInteresting8Mutator.hpp | 91 +++ .../src/module/AFLOverwriteCopyMutator.cpp | 140 +++++ .../src/module/AFLOverwriteCopyMutator.hpp | 89 +++ .../src/module/AFLOverwriteFixedMutator.cpp | 145 +++++ .../src/module/AFLOverwriteFixedMutator.hpp | 92 +++ .../src/module/AFLRandomByteAddSubMutator.cpp | 130 ++++ .../src/module/AFLRandomByteAddSubMutator.hpp | 93 +++ .../src/module/AFLRandomByteMutator.cpp | 130 ++++ .../src/module/AFLRandomByteMutator.hpp | 90 +++ AFLPlusPlus/src/module/AFLSpliceMutator.cpp | 159 +++++ AFLPlusPlus/src/module/AFLSpliceMutator.hpp | 90 +++ .../src/module/AFLWordAddSubMutator.cpp | 137 +++++ .../src/module/AFLWordAddSubMutator.hpp | 92 +++ AFLPlusPlus/src/module/README.md | 8 + AFLPlusPlus/src/module/config.h | 576 ++++++++++++++++++ AFLPlusPlus/test/README.md | 6 + CMakeLists.txt | 1 + Radamsa/test/config/experimentalModules.yaml | 53 -- .../common/mutator/RadamsaAsciiBadMutator.cpp | 1 - dockerfiles/Dockerfile | 2 +- test/config/experimentalModules.yaml | 72 +++ 48 files changed, 4977 insertions(+), 55 deletions(-) create mode 100644 AFLPlusPlus/CMakeLists.txt create mode 100644 AFLPlusPlus/README.md create mode 100644 AFLPlusPlus/data/README.md create mode 100644 AFLPlusPlus/docs/README.md create mode 100644 AFLPlusPlus/src/module/AFLCloneMutator.cpp create mode 100644 AFLPlusPlus/src/module/AFLCloneMutator.hpp create mode 100644 AFLPlusPlus/src/module/AFLDWordAddSubMutator.cpp create mode 100644 AFLPlusPlus/src/module/AFLDWordAddSubMutator.hpp create mode 100644 AFLPlusPlus/src/module/AFLDeleteMutator.cpp create mode 100644 AFLPlusPlus/src/module/AFLDeleteMutator.hpp create mode 100644 AFLPlusPlus/src/module/AFLFlip2BitMutator.cpp create mode 100644 AFLPlusPlus/src/module/AFLFlip2BitMutator.hpp create mode 100644 AFLPlusPlus/src/module/AFLFlip2ByteMutator.cpp create mode 100644 AFLPlusPlus/src/module/AFLFlip2ByteMutator.hpp create mode 100644 AFLPlusPlus/src/module/AFLFlip4BitMutator.cpp create mode 100644 AFLPlusPlus/src/module/AFLFlip4BitMutator.hpp create mode 100644 AFLPlusPlus/src/module/AFLFlip4ByteMutator.cpp create mode 100644 AFLPlusPlus/src/module/AFLFlip4ByteMutator.hpp create mode 100644 AFLPlusPlus/src/module/AFLFlipBitMutator.cpp create mode 100644 AFLPlusPlus/src/module/AFLFlipBitMutator.hpp create mode 100644 AFLPlusPlus/src/module/AFLFlipByteMutator.cpp create mode 100644 AFLPlusPlus/src/module/AFLFlipByteMutator.hpp create mode 100644 AFLPlusPlus/src/module/AFLInteresting16Mutator.cpp create mode 100644 AFLPlusPlus/src/module/AFLInteresting16Mutator.hpp create mode 100644 AFLPlusPlus/src/module/AFLInteresting32Mutator.cpp create mode 100644 AFLPlusPlus/src/module/AFLInteresting32Mutator.hpp create mode 100644 AFLPlusPlus/src/module/AFLInteresting8Mutator.cpp create mode 100644 AFLPlusPlus/src/module/AFLInteresting8Mutator.hpp create mode 100644 AFLPlusPlus/src/module/AFLOverwriteCopyMutator.cpp create mode 100644 AFLPlusPlus/src/module/AFLOverwriteCopyMutator.hpp create mode 100644 AFLPlusPlus/src/module/AFLOverwriteFixedMutator.cpp create mode 100644 AFLPlusPlus/src/module/AFLOverwriteFixedMutator.hpp create mode 100644 AFLPlusPlus/src/module/AFLRandomByteAddSubMutator.cpp create mode 100644 AFLPlusPlus/src/module/AFLRandomByteAddSubMutator.hpp create mode 100644 AFLPlusPlus/src/module/AFLRandomByteMutator.cpp create mode 100644 AFLPlusPlus/src/module/AFLRandomByteMutator.hpp create mode 100644 AFLPlusPlus/src/module/AFLSpliceMutator.cpp create mode 100644 AFLPlusPlus/src/module/AFLSpliceMutator.hpp create mode 100644 AFLPlusPlus/src/module/AFLWordAddSubMutator.cpp create mode 100644 AFLPlusPlus/src/module/AFLWordAddSubMutator.hpp create mode 100644 AFLPlusPlus/src/module/README.md create mode 100644 AFLPlusPlus/src/module/config.h create mode 100644 AFLPlusPlus/test/README.md delete mode 100644 Radamsa/test/config/experimentalModules.yaml create mode 100644 test/config/experimentalModules.yaml diff --git a/AFLPlusPlus/CMakeLists.txt b/AFLPlusPlus/CMakeLists.txt new file mode 100644 index 0000000..6f83645 --- /dev/null +++ b/AFLPlusPlus/CMakeLists.txt @@ -0,0 +1,74 @@ +#=============================================================================== +# Vader Modular Fuzzer (VMF) +# Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. +# +# +# Effort sponsored by the U.S. Government under Other Transaction number +# W9124P-19-9-0001 between AMTC and the Government. The U.S. Government +# Is authorized to reproduce and distribute reprints for Governmental purposes +# notwithstanding any copyright notation thereon. +# +# The views and conclusions contained herein are those of the authors and +# should not be interpreted as necessarily representing the official policies +# or endorsements, either expressed or implied, of the U.S. Government. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 (only) as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# @license GPL-2.0-only +#=============================================================================== + +# Create AFLPlusPlus library +add_library(AFLPlusPlus SHARED + src/module/AFLCloneMutator.cpp + src/module/AFLDeleteMutator.cpp + src/module/AFLDWordAddSubMutator.cpp + src/module/AFLFlip2BitMutator.cpp + src/module/AFLFlip2ByteMutator.cpp + src/module/AFLFlip4BitMutator.cpp + src/module/AFLFlip4ByteMutator.cpp + src/module/AFLFlipBitMutator.cpp + src/module/AFLFlipByteMutator.cpp + src/module/AFLInteresting8Mutator.cpp + src/module/AFLInteresting16Mutator.cpp + src/module/AFLInteresting32Mutator.cpp + src/module/AFLOverwriteCopyMutator.cpp + src/module/AFLOverwriteFixedMutator.cpp + src/module/AFLRandomByteAddSubMutator.cpp + src/module/AFLRandomByteMutator.cpp + src/module/AFLSpliceMutator.cpp + src/module/AFLWordAddSubMutator.cpp +) + +# Build-time dependencies for AFLPlusPlus +link_directories(AFLPlusPlus PRIVATE +) + +# Build-time dependencies for AFLPlusPlus +target_link_libraries(AFLPlusPlus PRIVATE + # ${CMAKE_INSTALL_PREFIX}/bin/vader + vmf_framework + # ${CMAKE_INSTALL_PREFIX}/../../submodules/LibAFL-legacy +) + +# Build-time dependencies for AFLPlusPlus +target_include_directories(AFLPlusPlus PRIVATE + ${CMAKE_INSTALL_PREFIX}/include + ${CMAKE_INSTALL_PREFIX}/include/vmf + ${CMAKE_INSTALL_PREFIX}/include/plog + ${PROJECT_SOURCE_DIR}/src/module +) + +# Install AFLPlusPlus library in VMF plugins directory +install(TARGETS AFLPlusPlus + LIBRARY DESTINATION "${CMAKE_INSTALL_PREFIX}/plugins") + diff --git a/AFLPlusPlus/README.md b/AFLPlusPlus/README.md new file mode 100644 index 0000000..015a0ed --- /dev/null +++ b/AFLPlusPlus/README.md @@ -0,0 +1,14 @@ += SamplePackage README + +== Overview + +This document gives an overview of the SamplePackage extension package for VMF. + +== Building and installing + +Build instructions + +== License + +This module is licensed under the GNU General Public License version 2 (GPLv2) + diff --git a/AFLPlusPlus/data/README.md b/AFLPlusPlus/data/README.md new file mode 100644 index 0000000..c896a2d --- /dev/null +++ b/AFLPlusPlus/data/README.md @@ -0,0 +1,4 @@ += SamplePackage data + +Put any necessary data files for your modules in this directory + diff --git a/AFLPlusPlus/docs/README.md b/AFLPlusPlus/docs/README.md new file mode 100644 index 0000000..555132f --- /dev/null +++ b/AFLPlusPlus/docs/README.md @@ -0,0 +1,26 @@ += SamplePackage documentation + +== Configuration parameters + +These modules use the following configuration parameters. + +### `SamplePackage.param1` + +Value type: `` + +Status: Optional + +Default value: local directory + +Usage: Specifies the directory that all VMF outputs will be put into, including log files and test case data. + +### `vmfFramework.logLevel` + +Value type: `string` + +Status: Optional + +Default value: foo + +Usage: Specifies the level of foobar used by this module. + diff --git a/AFLPlusPlus/src/module/AFLCloneMutator.cpp b/AFLPlusPlus/src/module/AFLCloneMutator.cpp new file mode 100644 index 0000000..383c670 --- /dev/null +++ b/AFLPlusPlus/src/module/AFLCloneMutator.cpp @@ -0,0 +1,170 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +/***** + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ + +#include "AFLCloneMutator.hpp" +#include "AFLDeleteMutator.hpp" //For static choose_block_len method +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(AFLCloneMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* + */ +Module* AFLCloneMutator::build(std::string name) +{ + return new AFLCloneMutator(name); +} + +/** + * @brief Initialization method + * + * @param config + */ +void AFLCloneMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new AFLCloneMutator::AFLCloneMutator object + * + * @param name the name of the module + */ +AFLCloneMutator::AFLCloneMutator(std::string name) : + MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the AFLCloneMutator::AFLCloneMutator object + * + */ +AFLCloneMutator::~AFLCloneMutator() +{ + +} + +/** + * @brief Registers storage needs + * This class uses only the "TEST_CASE" key + * + * @param registry + */ +void AFLCloneMutator::registerStorageNeeds(StorageRegistry& registry) +{ + testCaseKey = registry.registerKey("TEST_CASE", StorageRegistry::BUFFER, StorageRegistry::READ_WRITE); +} + +void AFLCloneMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + + int size = baseEntry->getBufferSize(testCaseKey); + char* buffer = baseEntry->getBufferPointer(testCaseKey); + + if(size <= 0) + { + throw RuntimeException("AFLCloneMutator mutate called with zero sized buffer", RuntimeException::USAGE_ERROR); + } + + //The variable actually_clone determines which strategy is used. + int actually_clone = rand->randBelow(4); + int clone_from; + int clone_len; + int clone_to = rand->randBelow(size); + + if (actually_clone) { + //Clone a small block of the original data + + clone_len = AFLDeleteMutator::choose_block_len(rand, size); + clone_from = rand->randBelow(size - clone_len + 1); + + int newSize = clone_len + size; + char* newBuff = newEntry->allocateBuffer(testCaseKey, newSize); + + //Copies a random number of bytes (clone_to) from the original buffer + memcpy((void*)newBuff, (void*)buffer, clone_to); + + //Insert some bytes in the middle (cloning from part of the original buffer) + memcpy(newBuff + clone_to, buffer + clone_from, clone_len); + + //Now copy the rest of the original byte buffer + memcpy(newBuff + clone_to + clone_len, buffer + clone_to, size - clone_to); + + } else { + //Clone a large block of the original value + + clone_len = AFLDeleteMutator::choose_block_len(rand, HAVOC_BLK_XL); //This constant is 32768 + int randomByte = rand->randBelow(255); + + int newSize = clone_len + size; + char* newBuff = newEntry->allocateBuffer(testCaseKey, newSize); + + //Insert clone_len bytes at a location clone_to, the inserted bytes + //will contain the value in the just determined randomByte + + //First copy clone_to bytes from the original buffer + memcpy((void*)newBuff, (void*)buffer, clone_to); + + //Now copy the new random byte clone_len times + memset(newBuff + clone_to, randomByte, clone_len); + + //Now copy the rest of the original buffer + memcpy(newBuff + clone_to + clone_len, buffer + clone_to, size - clone_to); + } + + return; +} \ No newline at end of file diff --git a/AFLPlusPlus/src/module/AFLCloneMutator.hpp b/AFLPlusPlus/src/module/AFLCloneMutator.hpp new file mode 100644 index 0000000..013be1e --- /dev/null +++ b/AFLPlusPlus/src/module/AFLCloneMutator.hpp @@ -0,0 +1,92 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +// main includes +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "VmfRand.hpp" + +// external project includes. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wwrite-strings" +#pragma GCC diagnostic pop + +namespace vmf +{ +/** + * @brief This mutator inserts a random number of additional cloned bytes. + * + * The majority (75%) of the time this is a small duplication of the original buffer, + * but some (25%) of the time it will be a larger insertion of a repeated random byte. + * + * This module is draws heavily upon the libAFL mutator.c + * + * Uses the specified AFL-style mutation algorithm to mutate the provided + * input. createTestCase is the main mutation method. + * + * See https://github.com/AFLplusplus/LibAFL-legacy/blob/dev/src/mutator.c + * + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ +class AFLCloneMutator: public MutatorModule +{ +public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + AFLCloneMutator(std::string name); + virtual ~AFLCloneMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + +private: + int testCaseKey; + VmfRand* rand = VmfRand::getInstance(); +}; +} diff --git a/AFLPlusPlus/src/module/AFLDWordAddSubMutator.cpp b/AFLPlusPlus/src/module/AFLDWordAddSubMutator.cpp new file mode 100644 index 0000000..613b271 --- /dev/null +++ b/AFLPlusPlus/src/module/AFLDWordAddSubMutator.cpp @@ -0,0 +1,137 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +/***** + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ + +#include "AFLDWordAddSubMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; +using u32 = uint32_t; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(AFLDWordAddSubMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* + */ +Module* AFLDWordAddSubMutator::build(std::string name) +{ + return new AFLDWordAddSubMutator(name); +} + +/** + * @brief Initialization method + * + * @param config + */ +void AFLDWordAddSubMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new AFLDWordAddSubMutator::AFLDWordAddSubMutator object + * + * @param name the name of the module + */ +AFLDWordAddSubMutator::AFLDWordAddSubMutator(std::string name) : + MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the AFLDWordAddSubMutator::AFLDWordAddSubMutator object + * + */ +AFLDWordAddSubMutator::~AFLDWordAddSubMutator() +{ + +} + +/** + * @brief Registers storage needs + * This class uses only the "TEST_CASE" key + * + * @param registry + */ +void AFLDWordAddSubMutator::registerStorageNeeds(StorageRegistry& registry) +{ + testCaseKey = registry.registerKey("TEST_CASE", StorageRegistry::BUFFER, StorageRegistry::READ_WRITE); +} + +void AFLDWordAddSubMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + + int size = baseEntry->getBufferSize(testCaseKey); + char* buffer = baseEntry->getBufferPointer(testCaseKey); + + if(size <= 0) + { + throw RuntimeException("AFLDWordAddSubMutator mutate called with zero sized buffer", RuntimeException::USAGE_ERROR); + } + + // Copy base entry to new entry + char* newBuff = newEntry->allocateBuffer(testCaseKey, size); + memcpy((void*)newBuff, (void*)buffer, size); + + if(size < 4) + { + return; + } + + int byte = rand->randBelow(size - 3); + *(u32 *)(newBuff + byte) -= 1 + (u32)rand->randBelow(ARITH_MAX); + *(u32 *)(newBuff + byte) += 1 + (u32)rand->randBelow(ARITH_MAX); + + return; +} \ No newline at end of file diff --git a/AFLPlusPlus/src/module/AFLDWordAddSubMutator.hpp b/AFLPlusPlus/src/module/AFLDWordAddSubMutator.hpp new file mode 100644 index 0000000..31989f2 --- /dev/null +++ b/AFLPlusPlus/src/module/AFLDWordAddSubMutator.hpp @@ -0,0 +1,92 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +// main includes +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "VmfRand.hpp" + +// external project includes. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wwrite-strings" +#pragma GCC diagnostic pop + +namespace vmf +{ +/** + * @brief This mutator adds and subtracts bounded random values to a random double in the buffer + * + * Note that ARITH_MAX is set to 35, so the random value is signicantly + * bounded. + * + * This module is draws heavily upon the libAFL mutator.c + * + * Uses the specified AFL-style mutation algorithm to mutate the provided + * input. createTestCase is the main mutation method. + * + * See https://github.com/AFLplusplus/LibAFL-legacy/blob/dev/src/mutator.c + * + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ +class AFLDWordAddSubMutator: public MutatorModule +{ +public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + AFLDWordAddSubMutator(std::string name); + virtual ~AFLDWordAddSubMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + +private: + int testCaseKey; + VmfRand* rand = VmfRand::getInstance(); +}; +} diff --git a/AFLPlusPlus/src/module/AFLDeleteMutator.cpp b/AFLPlusPlus/src/module/AFLDeleteMutator.cpp new file mode 100644 index 0000000..4afced7 --- /dev/null +++ b/AFLPlusPlus/src/module/AFLDeleteMutator.cpp @@ -0,0 +1,183 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +/***** + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ + +#include "AFLDeleteMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(AFLDeleteMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* + */ +Module* AFLDeleteMutator::build(std::string name) +{ + return new AFLDeleteMutator(name); +} + +/** + * @brief Initialization method + * + * @param config + */ +void AFLDeleteMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new AFLDeleteMutator::AFLDeleteMutator object + * + * @param name the name of the module + */ +AFLDeleteMutator::AFLDeleteMutator(std::string name) : + MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the AFLDeleteMutator::AFLDeleteMutator object + * + */ +AFLDeleteMutator::~AFLDeleteMutator() +{ + +} + +/** + * @brief Registers storage needs + * This class uses only the "TEST_CASE" key + * + * @param registry + */ +void AFLDeleteMutator::registerStorageNeeds(StorageRegistry& registry) +{ + testCaseKey = registry.registerKey("TEST_CASE", StorageRegistry::BUFFER, StorageRegistry::READ_WRITE); +} + +void AFLDeleteMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + + int size = baseEntry->getBufferSize(testCaseKey); + char* buffer = baseEntry->getBufferPointer(testCaseKey); + + if(size <= 0) + { + throw RuntimeException("AFLDeleteMutator mutate called with zero sized buffer", RuntimeException::USAGE_ERROR); + } + + if (size < 2) { + char* newBuff = newEntry->allocateBuffer(testCaseKey, size); + memcpy((void*)newBuff, (void*)buffer, size); + return; //This is the libAFL implementation + } + + int del_len = choose_block_len(rand, size - 1); + int del_from = rand->randBelow(size - del_len + 1); + + int newSize = size - del_len; + + char* newBuff = newEntry->allocateBuffer(testCaseKey, newSize); + memcpy((void*)newBuff, (void*)buffer, del_from); + memcpy(newBuff + del_from, buffer + del_from + del_len, newSize - del_from); + + return; +} + +/** + * @brief Helper method to select a random block length + * + * This code was copied from mutator.c, as it was unclear how to call this + * since it is not in the mutator.h header file + * + * @param rand + * @param limit + * @return size_t + */ +size_t AFLDeleteMutator::choose_block_len(VmfRand* rand, size_t limit) { + + size_t min_value, max_value; + switch (rand->randBelow(3)) { + + case 0: + min_value = 1; + max_value = HAVOC_BLK_SMALL; + break; + case 1: + min_value = HAVOC_BLK_SMALL; + max_value = HAVOC_BLK_MEDIUM; + break; + default: + if (rand->randBelow(10)) { + + min_value = HAVOC_BLK_MEDIUM; + max_value = HAVOC_BLK_LARGE; + + } else { + + min_value = HAVOC_BLK_LARGE; + max_value = HAVOC_BLK_XL; + + } + + } + + if (min_value >= limit) { + min_value = 1; + } + + return rand->randBetween(min_value, std::min(max_value, limit)); +} \ No newline at end of file diff --git a/AFLPlusPlus/src/module/AFLDeleteMutator.hpp b/AFLPlusPlus/src/module/AFLDeleteMutator.hpp new file mode 100644 index 0000000..f5c8cce --- /dev/null +++ b/AFLPlusPlus/src/module/AFLDeleteMutator.hpp @@ -0,0 +1,95 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +// main includes +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "VmfRand.hpp" +#include "config.h" + +// external project includes. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wwrite-strings" +#pragma GCC diagnostic pop + +namespace vmf +{ +/** + * @brief This mutator deletes a random chunk from the test case buffer + * + * Note: If the base test case buffer is smaller than 2 bytes, no + * mutation will occur (instead the input will just be duplicated) + * + * This module is draws heavily upon the libAFL mutator.c + * + * Uses the specified AFL-style mutation algorithm to mutate the provided + * input. createTestCase is the main mutation method. + * + * See https://github.com/AFLplusplus/LibAFL-legacy/blob/dev/src/mutator.c + * + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ +class AFLDeleteMutator: public MutatorModule +{ +public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + AFLDeleteMutator(std::string name); + virtual ~AFLDeleteMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + + static size_t choose_block_len(VmfRand* rand, size_t limit); + +private: + int testCaseKey; + VmfRand* rand = VmfRand::getInstance(); +}; +} diff --git a/AFLPlusPlus/src/module/AFLFlip2BitMutator.cpp b/AFLPlusPlus/src/module/AFLFlip2BitMutator.cpp new file mode 100644 index 0000000..6e09937 --- /dev/null +++ b/AFLPlusPlus/src/module/AFLFlip2BitMutator.cpp @@ -0,0 +1,135 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +/***** + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ + +#include "AFLFlip2BitMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(AFLFlip2BitMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* + */ +Module* AFLFlip2BitMutator::build(std::string name) +{ + return new AFLFlip2BitMutator(name); +} + +/** + * @brief Initialization method + * + * @param config + */ +void AFLFlip2BitMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new AFLFlip2BitMutator::AFLFlip2BitMutator object + * + * @param name the name of the module + */ +AFLFlip2BitMutator::AFLFlip2BitMutator(std::string name) : + MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the AFLFlip2BitMutator::AFLFlip2BitMutator object + * + */ +AFLFlip2BitMutator::~AFLFlip2BitMutator() +{ + +} + +/** + * @brief Registers storage needs + * This class uses only the "TEST_CASE" key + * + * @param registry + */ +void AFLFlip2BitMutator::registerStorageNeeds(StorageRegistry& registry) +{ + testCaseKey = registry.registerKey("TEST_CASE", StorageRegistry::BUFFER, StorageRegistry::READ_WRITE); +} + +void AFLFlip2BitMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + + int size = baseEntry->getBufferSize(testCaseKey); + char* buffer = baseEntry->getBufferPointer(testCaseKey); + + if(size <= 0) + { + throw RuntimeException("AFLFlip2BitMutator mutate called with zero sized buffer", RuntimeException::USAGE_ERROR); + } + + int bit = rand->randBelow((size * 8) - 1) + 1; + char* newBuff = newEntry->allocateBuffer(testCaseKey, size); + memcpy((void*)newBuff, (void*)buffer, size); + + if ((size << 3) - bit < 2) { + //Return without mutating -- the buffer is too small + return; //Note: This is the libAFL implementation + } + newBuff[bit >> 3] ^= (1 << ((bit - 1) % 8)); + bit++; + newBuff[bit >> 3] ^= (1 << ((bit - 1) % 8)); + + return; +} \ No newline at end of file diff --git a/AFLPlusPlus/src/module/AFLFlip2BitMutator.hpp b/AFLPlusPlus/src/module/AFLFlip2BitMutator.hpp new file mode 100644 index 0000000..85216bd --- /dev/null +++ b/AFLPlusPlus/src/module/AFLFlip2BitMutator.hpp @@ -0,0 +1,89 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +// main includes +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "VmfRand.hpp" + +// external project includes. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wwrite-strings" +#pragma GCC diagnostic pop + +namespace vmf +{ +/** + * @brief This mutator flips a random pair of bits in the test case buffer + * + * This module is draws heavily upon the libAFL mutator.c + * + * Uses the specified AFL-style mutation algorithm to mutate the provided + * input. createTestCase is the main mutation method. + * + * See https://github.com/AFLplusplus/LibAFL-legacy/blob/dev/src/mutator.c + * + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ +class AFLFlip2BitMutator: public MutatorModule +{ +public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + AFLFlip2BitMutator(std::string name); + virtual ~AFLFlip2BitMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + +private: + int testCaseKey; + VmfRand* rand = VmfRand::getInstance(); +}; +} diff --git a/AFLPlusPlus/src/module/AFLFlip2ByteMutator.cpp b/AFLPlusPlus/src/module/AFLFlip2ByteMutator.cpp new file mode 100644 index 0000000..19a9393 --- /dev/null +++ b/AFLPlusPlus/src/module/AFLFlip2ByteMutator.cpp @@ -0,0 +1,134 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +/***** + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ + +#include "AFLFlip2ByteMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(AFLFlip2ByteMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* + */ +Module* AFLFlip2ByteMutator::build(std::string name) +{ + return new AFLFlip2ByteMutator(name); +} + +/** + * @brief Initialization method + * + * @param config + */ +void AFLFlip2ByteMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new AFLFlip2ByteMutator::AFLFlip2ByteMutator object + * + * @param name the name of the module + */ +AFLFlip2ByteMutator::AFLFlip2ByteMutator(std::string name) : + MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the AFLFlip2ByteMutator::AFLFlip2ByteMutator object + * + */ +AFLFlip2ByteMutator::~AFLFlip2ByteMutator() +{ + +} + +/** + * @brief Registers storage needs + * This class uses only the "TEST_CASE" key + * + * @param registry + */ +void AFLFlip2ByteMutator::registerStorageNeeds(StorageRegistry& registry) +{ + testCaseKey = registry.registerKey("TEST_CASE", StorageRegistry::BUFFER, StorageRegistry::READ_WRITE); +} + +void AFLFlip2ByteMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + + int size = baseEntry->getBufferSize(testCaseKey); + char* buffer = baseEntry->getBufferPointer(testCaseKey); + + if(size <= 0) + { + throw RuntimeException("AFLFlip2ByteMutator mutate called with zero sized buffer", RuntimeException::USAGE_ERROR); + } + + int byte = rand->randBelow(size - 1); + char* newBuff = newEntry->allocateBuffer(testCaseKey, size); + memcpy((void*)newBuff, (void*)buffer, size); + + if (size >= 2) { + newBuff[byte] ^= 0xff; + newBuff[byte + 1] ^= 0xff; + } + //Otherwise return without mutating -- the buffer is too small + //This is the libAFL implementation + + return; +} \ No newline at end of file diff --git a/AFLPlusPlus/src/module/AFLFlip2ByteMutator.hpp b/AFLPlusPlus/src/module/AFLFlip2ByteMutator.hpp new file mode 100644 index 0000000..7f2ee6d --- /dev/null +++ b/AFLPlusPlus/src/module/AFLFlip2ByteMutator.hpp @@ -0,0 +1,92 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +// main includes +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "VmfRand.hpp" + +// external project includes. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wwrite-strings" +#pragma GCC diagnostic pop + +namespace vmf +{ +/** + * @brief This mutator flips a random pair of bytes in the test case buffer + * + * Note: If the base test case buffer is smaller than 2 bytes, no + * mutation will occur (instead the input will just be duplicated) + * + * This module is draws heavily upon the libAFL mutator.c + * + * Uses the specified AFL-style mutation algorithm to mutate the provided + * input. createTestCase is the main mutation method. + * + * See https://github.com/AFLplusplus/LibAFL-legacy/blob/dev/src/mutator.c + * + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ +class AFLFlip2ByteMutator: public MutatorModule +{ +public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + AFLFlip2ByteMutator(std::string name); + virtual ~AFLFlip2ByteMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + +private: + int testCaseKey; + VmfRand* rand = VmfRand::getInstance(); +}; +} diff --git a/AFLPlusPlus/src/module/AFLFlip4BitMutator.cpp b/AFLPlusPlus/src/module/AFLFlip4BitMutator.cpp new file mode 100644 index 0000000..d1cbf55 --- /dev/null +++ b/AFLPlusPlus/src/module/AFLFlip4BitMutator.cpp @@ -0,0 +1,141 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +/***** + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ + +#include "AFLFlip4BitMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(AFLFlip4BitMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* + */ +Module* AFLFlip4BitMutator::build(std::string name) +{ + return new AFLFlip4BitMutator(name); +} + +/** + * @brief Initialization method + * + * @param config + */ +void AFLFlip4BitMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new AFLFlip4BitMutator::AFLFlip4BitMutator object + * + * @param name the name of the module + */ +AFLFlip4BitMutator::AFLFlip4BitMutator(std::string name) : + MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the AFLFlip4BitMutator::AFLFlip4BitMutator object + * + */ +AFLFlip4BitMutator::~AFLFlip4BitMutator() +{ + +} + +/** + * @brief Registers storage needs + * This class uses only the "TEST_CASE" key + * + * @param registry + */ +void AFLFlip4BitMutator::registerStorageNeeds(StorageRegistry& registry) +{ + testCaseKey = registry.registerKey("TEST_CASE", StorageRegistry::BUFFER, StorageRegistry::READ_WRITE); +} + +void AFLFlip4BitMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + + int size = baseEntry->getBufferSize(testCaseKey); + char* buffer = baseEntry->getBufferPointer(testCaseKey); + + if(size <= 0) + { + throw RuntimeException("AFLFlip4BitMutator mutate called with zero sized buffer", RuntimeException::USAGE_ERROR); + } + + int bit = rand->randBelow((size << 3) - 1) + 1; + char* newBuff = newEntry->allocateBuffer(testCaseKey, size); + memcpy((void*)newBuff, (void*)buffer, size); + + if ((size << 3) - bit < 4) { + //Return without mutating -- the buffer is too small + return; //This is the libAFL implementation + } + + newBuff[bit >> 3] ^= (1 << ((bit - 1) % 8)); + bit++; + newBuff[bit >> 3] ^= (1 << ((bit - 1) % 8)); + bit++; + newBuff[bit >> 3] ^= (1 << ((bit - 1) % 8)); + bit++; + newBuff[bit >> 3] ^= (1 << ((bit - 1) % 8)); + + + return; +} \ No newline at end of file diff --git a/AFLPlusPlus/src/module/AFLFlip4BitMutator.hpp b/AFLPlusPlus/src/module/AFLFlip4BitMutator.hpp new file mode 100644 index 0000000..dc132f8 --- /dev/null +++ b/AFLPlusPlus/src/module/AFLFlip4BitMutator.hpp @@ -0,0 +1,92 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +// main includes +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "VmfRand.hpp" + +// external project includes. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wwrite-strings" +#pragma GCC diagnostic pop + +namespace vmf +{ +/** + * @brief This mutator flips a random set of 4 bits in the test case buffer + * + * Note: If the base test case buffer is smaller than 4 bytes, no + * mutation will occur (instead the input will just be duplicated) + * + * This module is draws heavily upon the libAFL mutator.c + * + * Uses the specified AFL-style mutation algorithm to mutate the provided + * input. createTestCase is the main mutation method. + * + * See https://github.com/AFLplusplus/LibAFL-legacy/blob/dev/src/mutator.c + * + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ +class AFLFlip4BitMutator: public MutatorModule +{ +public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + AFLFlip4BitMutator(std::string name); + virtual ~AFLFlip4BitMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + +private: + int testCaseKey; + VmfRand* rand = VmfRand::getInstance(); +}; +} diff --git a/AFLPlusPlus/src/module/AFLFlip4ByteMutator.cpp b/AFLPlusPlus/src/module/AFLFlip4ByteMutator.cpp new file mode 100644 index 0000000..2413db7 --- /dev/null +++ b/AFLPlusPlus/src/module/AFLFlip4ByteMutator.cpp @@ -0,0 +1,142 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +/***** + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ + +#include "AFLFlip4ByteMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(AFLFlip4ByteMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* + */ +Module* AFLFlip4ByteMutator::build(std::string name) +{ + return new AFLFlip4ByteMutator(name); +} + +/** + * @brief Initialization method + * + * @param config + */ +void AFLFlip4ByteMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new AFLFlip4ByteMutator::AFLFlip4ByteMutator object + * + * @param name the name of the module + */ +AFLFlip4ByteMutator::AFLFlip4ByteMutator(std::string name) : + MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the AFLFlip4ByteMutator::AFLFlip4ByteMutator object + * + */ +AFLFlip4ByteMutator::~AFLFlip4ByteMutator() +{ + +} + +/** + * @brief Registers storage needs + * This class uses only the "TEST_CASE" key + * + * @param registry + */ +void AFLFlip4ByteMutator::registerStorageNeeds(StorageRegistry& registry) +{ + testCaseKey = registry.registerKey("TEST_CASE", StorageRegistry::BUFFER, StorageRegistry::READ_WRITE); +} + +void AFLFlip4ByteMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + + int size = baseEntry->getBufferSize(testCaseKey); + char* buffer = baseEntry->getBufferPointer(testCaseKey); + + if(size <= 0) + { + throw RuntimeException("AFLFlip4ByteMutator mutate called with zero sized buffer", RuntimeException::USAGE_ERROR); + } + + char* newBuff = newEntry->allocateBuffer(testCaseKey, size); + memcpy((void*)newBuff, (void*)buffer, size); + + if (size < 4) { + //The buffer is too small for this mutation approach + return; //This is the libAFL implementation + } + + int byte = rand->randBelow(size - 3); + + if (byte == -1) { + return; //This is the libAFL implementation + } + + newBuff[byte] ^= 0xff; + newBuff[byte + 1] ^= 0xff; + newBuff[byte + 2] ^= 0xff; + newBuff[byte + 3] ^= 0xff; + + return; +} \ No newline at end of file diff --git a/AFLPlusPlus/src/module/AFLFlip4ByteMutator.hpp b/AFLPlusPlus/src/module/AFLFlip4ByteMutator.hpp new file mode 100644 index 0000000..2c9c4df --- /dev/null +++ b/AFLPlusPlus/src/module/AFLFlip4ByteMutator.hpp @@ -0,0 +1,89 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +// main includes +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "VmfRand.hpp" + +// external project includes. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wwrite-strings" +#pragma GCC diagnostic pop + +namespace vmf +{ +/** + * @brief This mutator flips a set of 4 bytes in the test case buffer + * + * This module is draws heavily upon the libAFL mutator.c + * + * Uses the specified AFL-style mutation algorithm to mutate the provided + * input. createTestCase is the main mutation method. + * + * See https://github.com/AFLplusplus/LibAFL-legacy/blob/dev/src/mutator.c + * + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ +class AFLFlip4ByteMutator: public MutatorModule +{ +public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + AFLFlip4ByteMutator(std::string name); + virtual ~AFLFlip4ByteMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + +private: + int testCaseKey; + VmfRand* rand = VmfRand::getInstance(); +}; +} diff --git a/AFLPlusPlus/src/module/AFLFlipBitMutator.cpp b/AFLPlusPlus/src/module/AFLFlipBitMutator.cpp new file mode 100644 index 0000000..6e438de --- /dev/null +++ b/AFLPlusPlus/src/module/AFLFlipBitMutator.cpp @@ -0,0 +1,129 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +/***** + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ + +#include "AFLFlipBitMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(AFLFlipBitMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* + */ +Module* AFLFlipBitMutator::build(std::string name) +{ + return new AFLFlipBitMutator(name); +} + +/** + * @brief Initialization method + * + * @param config + */ +void AFLFlipBitMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new AFLFlipBitMutator::AFLFlipBitMutator object + * + * @param name the name of the module + */ +AFLFlipBitMutator::AFLFlipBitMutator(std::string name) : + MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the AFLFlipBitMutator::AFLFlipBitMutator object + * + */ +AFLFlipBitMutator::~AFLFlipBitMutator() +{ + +} + +/** + * @brief Registers storage needs + * This class uses only the "TEST_CASE" key + * + * @param registry + */ +void AFLFlipBitMutator::registerStorageNeeds(StorageRegistry& registry) +{ + testCaseKey = registry.registerKey("TEST_CASE", StorageRegistry::BUFFER, StorageRegistry::READ_WRITE); +} + +void AFLFlipBitMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + + int size = baseEntry->getBufferSize(testCaseKey); + char* buffer = baseEntry->getBufferPointer(testCaseKey); + + if(size <= 0) + { + throw RuntimeException("AFLFlipBitMutator mutate called with zero sized buffer", RuntimeException::USAGE_ERROR); + } + + int bit = rand->randBelow(size * 8 - 1) + 1; + char* newBuff = newEntry->allocateBuffer(testCaseKey, size); + memcpy((void*)newBuff, (void*)buffer, size); + + newBuff[(bit >> 3)] ^= (1 << ((bit - 1) % 8)); + + return; +} \ No newline at end of file diff --git a/AFLPlusPlus/src/module/AFLFlipBitMutator.hpp b/AFLPlusPlus/src/module/AFLFlipBitMutator.hpp new file mode 100644 index 0000000..44210ed --- /dev/null +++ b/AFLPlusPlus/src/module/AFLFlipBitMutator.hpp @@ -0,0 +1,89 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +// main includes +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "VmfRand.hpp" + +// external project includes. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wwrite-strings" +#pragma GCC diagnostic pop + +namespace vmf +{ +/** + * @brief This mutator flips a random single bit in the test case buffer + * + * This module is draws heavily upon the libAFL mutator.c + * + * Uses the specified AFL-style mutation algorithm to mutate the provided + * input. createTestCase is the main mutation method. + * + * See https://github.com/AFLplusplus/LibAFL-legacy/blob/dev/src/mutator.c + * + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ +class AFLFlipBitMutator: public MutatorModule +{ +public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + AFLFlipBitMutator(std::string name); + virtual ~AFLFlipBitMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + +private: + int testCaseKey; + VmfRand* rand = VmfRand::getInstance(); +}; +} diff --git a/AFLPlusPlus/src/module/AFLFlipByteMutator.cpp b/AFLPlusPlus/src/module/AFLFlipByteMutator.cpp new file mode 100644 index 0000000..2470fd5 --- /dev/null +++ b/AFLPlusPlus/src/module/AFLFlipByteMutator.cpp @@ -0,0 +1,128 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +/***** + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ + +#include "AFLFlipByteMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(AFLFlipByteMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* + */ +Module* AFLFlipByteMutator::build(std::string name) +{ + return new AFLFlipByteMutator(name); +} + +/** + * @brief Initialization method + * + * @param config + */ +void AFLFlipByteMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new AFLFlipByteMutator::AFLFlipByteMutator object + * + * @param name the name of the module + */ +AFLFlipByteMutator::AFLFlipByteMutator(std::string name) : + MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the AFLFlipByteMutator::AFLFlipByteMutator object + * + */ +AFLFlipByteMutator::~AFLFlipByteMutator() +{ + +} + +/** + * @brief Registers storage needs + * This class uses only the "TEST_CASE" key + * + * @param registry + */ +void AFLFlipByteMutator::registerStorageNeeds(StorageRegistry& registry) +{ + testCaseKey = registry.registerKey("TEST_CASE", StorageRegistry::BUFFER, StorageRegistry::READ_WRITE); +} + +void AFLFlipByteMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + + int size = baseEntry->getBufferSize(testCaseKey); + char* buffer = baseEntry->getBufferPointer(testCaseKey); + + if(size <= 0) + { + throw RuntimeException("AFLFlipByteMutator mutate called with zero sized buffer", RuntimeException::USAGE_ERROR); + } + + int byte = rand->randBelow(size); + char* newBuff = newEntry->allocateBuffer(testCaseKey, size); + memcpy((void*)newBuff, (void*)buffer, size); + newBuff[byte] ^= 0xff; + + return; +} \ No newline at end of file diff --git a/AFLPlusPlus/src/module/AFLFlipByteMutator.hpp b/AFLPlusPlus/src/module/AFLFlipByteMutator.hpp new file mode 100644 index 0000000..ad9ee76 --- /dev/null +++ b/AFLPlusPlus/src/module/AFLFlipByteMutator.hpp @@ -0,0 +1,89 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +// main includes +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "VmfRand.hpp" + +// external project includes. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wwrite-strings" +#pragma GCC diagnostic pop + +namespace vmf +{ +/** + * @brief This mutator flips a random byte in the test case buffer + * + * This module is draws heavily upon the libAFL mutator.c + * + * Uses the specified AFL-style mutation algorithm to mutate the provided + * input. createTestCase is the main mutation method. + * + * See https://github.com/AFLplusplus/LibAFL-legacy/blob/dev/src/mutator.c + * + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ +class AFLFlipByteMutator: public MutatorModule +{ +public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + AFLFlipByteMutator(std::string name); + virtual ~AFLFlipByteMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + +private: + int testCaseKey; + VmfRand* rand = VmfRand::getInstance(); +}; +} diff --git a/AFLPlusPlus/src/module/AFLInteresting16Mutator.cpp b/AFLPlusPlus/src/module/AFLInteresting16Mutator.cpp new file mode 100644 index 0000000..3f36305 --- /dev/null +++ b/AFLPlusPlus/src/module/AFLInteresting16Mutator.cpp @@ -0,0 +1,139 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +/***** + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ + +#include "AFLInteresting16Mutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; +using u16 = uint16_t; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(AFLInteresting16Mutator); + +// From AFL++ macro +const int16_t AFLInteresting16Mutator::interesting_16[] = {INTERESTING_8, INTERESTING_16}; + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* + */ +Module* AFLInteresting16Mutator::build(std::string name) +{ + return new AFLInteresting16Mutator(name); +} + +/** + * @brief Initialization method + * + * @param config + */ +void AFLInteresting16Mutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new AFLInteresting16Mutator::AFLInteresting16Mutator object + * + * @param name the name of the module + */ +AFLInteresting16Mutator::AFLInteresting16Mutator(std::string name) : + MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the AFLInteresting16Mutator::AFLInteresting16Mutator object + * + */ +AFLInteresting16Mutator::~AFLInteresting16Mutator() +{ + +} + +/** + * @brief Registers storage needs + * This class uses only the "TEST_CASE" key + * + * @param registry + */ +void AFLInteresting16Mutator::registerStorageNeeds(StorageRegistry& registry) +{ + testCaseKey = registry.registerKey("TEST_CASE", StorageRegistry::BUFFER, StorageRegistry::READ_WRITE); +} + +void AFLInteresting16Mutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + + int size = baseEntry->getBufferSize(testCaseKey); + char* buffer = baseEntry->getBufferPointer(testCaseKey); + + if(size <= 0) + { + throw RuntimeException("AFLInteresting16Mutator mutate called with zero sized buffer", RuntimeException::USAGE_ERROR); + } + + // Copy base entry to new entry + char* newBuff = newEntry->allocateBuffer(testCaseKey, size); + memcpy((void*)newBuff, (void*)buffer, size); + + if (size < 2) { + return; + } + + // Pick a random byte and replace it with an interesting value + int item = rand->randBelow(sizeof(AFLInteresting16Mutator::interesting_16) >> 1); + *(u16 *)(newBuff + rand->randBelow(size - 1)) = AFLInteresting16Mutator::interesting_16[item]; + + return; +} \ No newline at end of file diff --git a/AFLPlusPlus/src/module/AFLInteresting16Mutator.hpp b/AFLPlusPlus/src/module/AFLInteresting16Mutator.hpp new file mode 100644 index 0000000..7ddf244 --- /dev/null +++ b/AFLPlusPlus/src/module/AFLInteresting16Mutator.hpp @@ -0,0 +1,91 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +// main includes +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "VmfRand.hpp" +#include "config.h" + +// external project includes. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wwrite-strings" +#pragma GCC diagnostic pop + +namespace vmf +{ +/** + * @brief This mutator sets a word to an interesting value. + * + * This module is draws heavily upon the libAFL mutator.c + * + * Uses the specified AFL-style mutation algorithm to mutate the provided + * input. createTestCase is the main mutation method. + * + * See https://github.com/AFLplusplus/LibAFL-legacy/blob/dev/src/mutator.c + * + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ +class AFLInteresting16Mutator: public MutatorModule +{ +public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + AFLInteresting16Mutator(std::string name); + virtual ~AFLInteresting16Mutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + +private: + int testCaseKey; + VmfRand* rand = VmfRand::getInstance(); + static const int16_t interesting_16[]; +}; +} diff --git a/AFLPlusPlus/src/module/AFLInteresting32Mutator.cpp b/AFLPlusPlus/src/module/AFLInteresting32Mutator.cpp new file mode 100644 index 0000000..f944340 --- /dev/null +++ b/AFLPlusPlus/src/module/AFLInteresting32Mutator.cpp @@ -0,0 +1,144 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +/***** + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ + +#include "AFLInteresting32Mutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; +using u32 = uint32_t; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(AFLInteresting32Mutator); + +// From AFL++ macro (github.com/AFLplusplus/AFLplusplus/blob/stable/include/config.h) +const int64_t AFLInteresting32Mutator::interesting_32[] = +{ + INTERESTING_8, + INTERESTING_16, + INTERESTING_32 +}; + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* + */ +Module* AFLInteresting32Mutator::build(std::string name) +{ + return new AFLInteresting32Mutator(name); +} + +/** + * @brief Initialization method + * + * @param config + */ +void AFLInteresting32Mutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new AFLInteresting32Mutator::AFLInteresting32Mutator object + * + * @param name the name of the module + */ +AFLInteresting32Mutator::AFLInteresting32Mutator(std::string name) : + MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the AFLInteresting32Mutator::AFLInteresting32Mutator object + * + */ +AFLInteresting32Mutator::~AFLInteresting32Mutator() +{ + +} + +/** + * @brief Registers storage needs + * This class uses only the "TEST_CASE" key + * + * @param registry + */ +void AFLInteresting32Mutator::registerStorageNeeds(StorageRegistry& registry) +{ + testCaseKey = registry.registerKey("TEST_CASE", StorageRegistry::BUFFER, StorageRegistry::READ_WRITE); +} + +void AFLInteresting32Mutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + + int size = baseEntry->getBufferSize(testCaseKey); + char* buffer = baseEntry->getBufferPointer(testCaseKey); + + if(size <= 0) + { + throw RuntimeException("AFLInteresting32Mutator mutate called with zero sized buffer", RuntimeException::USAGE_ERROR); + } + + // Copy base entry to new entry + char* newBuff = newEntry->allocateBuffer(testCaseKey, size); + memcpy((void*)newBuff, (void*)buffer, size); + + if (size < 4) { + return; + } + + // Pick a random byte and replace it with an interesting value + int item = rand->randBelow(sizeof(AFLInteresting32Mutator::interesting_32) >> 2); + *(u32 *) (newBuff + rand->randBelow(size - 3)) = AFLInteresting32Mutator::interesting_32[item]; + + return; +} \ No newline at end of file diff --git a/AFLPlusPlus/src/module/AFLInteresting32Mutator.hpp b/AFLPlusPlus/src/module/AFLInteresting32Mutator.hpp new file mode 100644 index 0000000..9df9164 --- /dev/null +++ b/AFLPlusPlus/src/module/AFLInteresting32Mutator.hpp @@ -0,0 +1,91 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +// main includes +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "VmfRand.hpp" +#include "config.h" + +// external project includes. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wwrite-strings" +#pragma GCC diagnostic pop + +namespace vmf +{ +/** + * @brief This mutator sets a dword to an interesting value. + * + * This module is draws heavily upon the libAFL mutator.c + * + * Uses the specified AFL-style mutation algorithm to mutate the provided + * input. createTestCase is the main mutation method. + * + * See https://github.com/AFLplusplus/LibAFL-legacy/blob/dev/src/mutator.c + * + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ +class AFLInteresting32Mutator: public MutatorModule +{ +public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + AFLInteresting32Mutator(std::string name); + virtual ~AFLInteresting32Mutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + +private: + int testCaseKey; + VmfRand* rand = VmfRand::getInstance(); + static const int64_t interesting_32[]; +}; +} diff --git a/AFLPlusPlus/src/module/AFLInteresting8Mutator.cpp b/AFLPlusPlus/src/module/AFLInteresting8Mutator.cpp new file mode 100644 index 0000000..be55e4e --- /dev/null +++ b/AFLPlusPlus/src/module/AFLInteresting8Mutator.cpp @@ -0,0 +1,134 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +/***** + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ + +#include "AFLInteresting8Mutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(AFLInteresting8Mutator); + +// From AFL++ macro +const int8_t AFLInteresting8Mutator::interesting_8[] = {INTERESTING_8}; + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* + */ +Module* AFLInteresting8Mutator::build(std::string name) +{ + return new AFLInteresting8Mutator(name); +} + +/** + * @brief Initialization method + * + * @param config + */ +void AFLInteresting8Mutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new AFLInteresting8Mutator::AFLInteresting8Mutator object + * + * @param name the name of the module + */ +AFLInteresting8Mutator::AFLInteresting8Mutator(std::string name) : + MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the AFLInteresting8Mutator::AFLInteresting8Mutator object + * + */ +AFLInteresting8Mutator::~AFLInteresting8Mutator() +{ + +} + +/** + * @brief Registers storage needs + * This class uses only the "TEST_CASE" key + * + * @param registry + */ +void AFLInteresting8Mutator::registerStorageNeeds(StorageRegistry& registry) +{ + testCaseKey = registry.registerKey("TEST_CASE", StorageRegistry::BUFFER, StorageRegistry::READ_WRITE); +} + +void AFLInteresting8Mutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + + int size = baseEntry->getBufferSize(testCaseKey); + char* buffer = baseEntry->getBufferPointer(testCaseKey); + + if(size <= 0) + { + throw RuntimeException("AFLInteresting8Mutator mutate called with zero sized buffer", RuntimeException::USAGE_ERROR); + } + + // Copy base entry to new entry + char* newBuff = newEntry->allocateBuffer(testCaseKey, size); + memcpy((void*)newBuff, (void*)buffer, size); + + // Pick a random byte and replace it with an interesting value + int item = rand->randBelow(sizeof(AFLInteresting8Mutator::interesting_8)); + newBuff[rand->randBelow(size)] = AFLInteresting8Mutator::interesting_8[item]; + + return; +} \ No newline at end of file diff --git a/AFLPlusPlus/src/module/AFLInteresting8Mutator.hpp b/AFLPlusPlus/src/module/AFLInteresting8Mutator.hpp new file mode 100644 index 0000000..b782d7e --- /dev/null +++ b/AFLPlusPlus/src/module/AFLInteresting8Mutator.hpp @@ -0,0 +1,91 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +// main includes +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "VmfRand.hpp" +#include "config.h" + +// external project includes. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wwrite-strings" +#pragma GCC diagnostic pop + +namespace vmf +{ +/** + * @brief This mutator sets a byte to an interesting value. + * + * This module is draws heavily upon the libAFL mutator.c + * + * Uses the specified AFL-style mutation algorithm to mutate the provided + * input. createTestCase is the main mutation method. + * + * See https://github.com/AFLplusplus/LibAFL-legacy/blob/dev/src/mutator.c + * + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ +class AFLInteresting8Mutator: public MutatorModule +{ +public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + AFLInteresting8Mutator(std::string name); + virtual ~AFLInteresting8Mutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + +private: + int testCaseKey; + VmfRand* rand = VmfRand::getInstance(); + static const int8_t interesting_8[]; +}; +} diff --git a/AFLPlusPlus/src/module/AFLOverwriteCopyMutator.cpp b/AFLPlusPlus/src/module/AFLOverwriteCopyMutator.cpp new file mode 100644 index 0000000..acd06bf --- /dev/null +++ b/AFLPlusPlus/src/module/AFLOverwriteCopyMutator.cpp @@ -0,0 +1,140 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +/***** + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ + +#include "AFLOverwriteCopyMutator.hpp" +#include "AFLDeleteMutator.hpp" //For static choose_block_len method +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; +using u32 = uint32_t; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(AFLOverwriteCopyMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* + */ +Module* AFLOverwriteCopyMutator::build(std::string name) +{ + return new AFLOverwriteCopyMutator(name); +} + +/** + * @brief Initialization method + * + * @param config + */ +void AFLOverwriteCopyMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new AFLOverwriteCopyMutator::AFLOverwriteCopyMutator object + * + * @param name the name of the module + */ +AFLOverwriteCopyMutator::AFLOverwriteCopyMutator(std::string name) : + MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the AFLOverwriteCopyMutator::AFLOverwriteCopyMutator object + * + */ +AFLOverwriteCopyMutator::~AFLOverwriteCopyMutator() +{ + +} + +/** + * @brief Registers storage needs + * This class uses only the "TEST_CASE" key + * + * @param registry + */ +void AFLOverwriteCopyMutator::registerStorageNeeds(StorageRegistry& registry) +{ + testCaseKey = registry.registerKey("TEST_CASE", StorageRegistry::BUFFER, StorageRegistry::READ_WRITE); +} + +void AFLOverwriteCopyMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + + int size = baseEntry->getBufferSize(testCaseKey); + char* buffer = baseEntry->getBufferPointer(testCaseKey); + + if(size <= 0) + { + throw RuntimeException("AFLOverwriteCopyMutator mutate called with zero sized buffer", RuntimeException::USAGE_ERROR); + } + char* newBuff = newEntry->allocateBuffer(testCaseKey, size); + // Copy base entry to new entry + memcpy((void*)newBuff, (void*)buffer, size); + + if (size < 2) { + return; + } + + u32 copy_len = AFLDeleteMutator::choose_block_len(rand, size - 1); + u32 copy_from = rand->randBelow((unsigned long)(size - copy_len + 1)); + u32 copy_to = rand->randBelow((unsigned long)(size - copy_len + 1)); + + if (copy_from != copy_to) { + memmove(newBuff + copy_to, newBuff + copy_from, copy_len); + } + + return; +} \ No newline at end of file diff --git a/AFLPlusPlus/src/module/AFLOverwriteCopyMutator.hpp b/AFLPlusPlus/src/module/AFLOverwriteCopyMutator.hpp new file mode 100644 index 0000000..58f68ec --- /dev/null +++ b/AFLPlusPlus/src/module/AFLOverwriteCopyMutator.hpp @@ -0,0 +1,89 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +// main includes +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "VmfRand.hpp" + +// external project includes. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wwrite-strings" +#pragma GCC diagnostic pop + +namespace vmf +{ +/** + * @brief This mutator overwrites bytes with another randomly selected chunk of bytes. + * + * This module is draws heavily upon the libAFL mutator.c + * + * Uses the specified AFL-style mutation algorithm to mutate the provided + * input. createTestCase is the main mutation method. + * + * See https://github.com/AFLplusplus/LibAFL-legacy/blob/dev/src/mutator.c + * + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ +class AFLOverwriteCopyMutator: public MutatorModule +{ +public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + AFLOverwriteCopyMutator(std::string name); + virtual ~AFLOverwriteCopyMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + +private: + int testCaseKey; + VmfRand* rand = VmfRand::getInstance(); +}; +} diff --git a/AFLPlusPlus/src/module/AFLOverwriteFixedMutator.cpp b/AFLPlusPlus/src/module/AFLOverwriteFixedMutator.cpp new file mode 100644 index 0000000..3561d94 --- /dev/null +++ b/AFLPlusPlus/src/module/AFLOverwriteFixedMutator.cpp @@ -0,0 +1,145 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +/***** + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ + +#include "AFLOverwriteFixedMutator.hpp" +#include "AFLDeleteMutator.hpp" //For static choose_block_len method +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; +using u32 = uint32_t; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(AFLOverwriteFixedMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* + */ +Module* AFLOverwriteFixedMutator::build(std::string name) +{ + return new AFLOverwriteFixedMutator(name); +} + +/** + * @brief Initialization method + * + * @param config + */ +void AFLOverwriteFixedMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new AFLOverwriteFixedMutator::AFLOverwriteFixedMutator object + * + * @param name the name of the module + */ +AFLOverwriteFixedMutator::AFLOverwriteFixedMutator(std::string name) : + MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the AFLOverwriteFixedMutator::AFLOverwriteFixedMutator object + * + */ +AFLOverwriteFixedMutator::~AFLOverwriteFixedMutator() +{ + +} + +/** + * @brief Registers storage needs + * This class uses only the "TEST_CASE" key + * + * @param registry + */ +void AFLOverwriteFixedMutator::registerStorageNeeds(StorageRegistry& registry) +{ + testCaseKey = registry.registerKey("TEST_CASE", StorageRegistry::BUFFER, StorageRegistry::READ_WRITE); +} + +void AFLOverwriteFixedMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + + int size = baseEntry->getBufferSize(testCaseKey); + char* buffer = baseEntry->getBufferPointer(testCaseKey); + + if(size <= 0) + { + throw RuntimeException("AFLOverwriteFixedMutator mutate called with zero sized buffer", RuntimeException::USAGE_ERROR); + } + char* newBuff = newEntry->allocateBuffer(testCaseKey, size); + // Copy base entry to new entry + memcpy((void*)newBuff, (void*)buffer, size); + + if (size < 2) { + return; + } + + // Choose a random block length + u32 copy_len = AFLDeleteMutator::choose_block_len(rand, size - 1); + // Choose a random location to copy the block to + u32 copy_to = rand->randBelow((unsigned long)(size - copy_len + 1)); + // Choose a random strategy with 50% chance of each + u32 strat = rand->randBelow(2); + // Copy from the location before the copy_to location or 0 if copy_to is 0 + u32 copy_from = copy_to ? copy_to - 1 : 0; + // Either repeat the byte at the copy_from location or choose a random byte + u32 item = strat ? rand->randBelow(256) : buffer[copy_from]; + + memset(newBuff + copy_to, item, copy_len); + + return; +} \ No newline at end of file diff --git a/AFLPlusPlus/src/module/AFLOverwriteFixedMutator.hpp b/AFLPlusPlus/src/module/AFLOverwriteFixedMutator.hpp new file mode 100644 index 0000000..d36eeb3 --- /dev/null +++ b/AFLPlusPlus/src/module/AFLOverwriteFixedMutator.hpp @@ -0,0 +1,92 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +// main includes +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "VmfRand.hpp" + +// external project includes. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wwrite-strings" +#pragma GCC diagnostic pop + +namespace vmf +{ +/** + * @brief This mutator overwrites bytes with fixed bytes. + * + * There is a 50% chance that the bytes will be overwritten with a randomly chosen byte + * and a 50% chance that the bytes will be overwritten with a fixed byte chosen from the buffer + * + * This module is draws heavily upon the libAFL mutator.c + * + * Uses the specified AFL-style mutation algorithm to mutate the provided + * input. createTestCase is the main mutation method. + * + * See https://github.com/AFLplusplus/LibAFL-legacy/blob/dev/src/mutator.c + * + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ +class AFLOverwriteFixedMutator: public MutatorModule +{ +public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + AFLOverwriteFixedMutator(std::string name); + virtual ~AFLOverwriteFixedMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + +private: + int testCaseKey; + VmfRand* rand = VmfRand::getInstance(); +}; +} diff --git a/AFLPlusPlus/src/module/AFLRandomByteAddSubMutator.cpp b/AFLPlusPlus/src/module/AFLRandomByteAddSubMutator.cpp new file mode 100644 index 0000000..d826599 --- /dev/null +++ b/AFLPlusPlus/src/module/AFLRandomByteAddSubMutator.cpp @@ -0,0 +1,130 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +/***** + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ + +#include "AFLRandomByteAddSubMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; +using u8 = uint8_t; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(AFLRandomByteAddSubMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* + */ +Module* AFLRandomByteAddSubMutator::build(std::string name) +{ + return new AFLRandomByteAddSubMutator(name); +} + +/** + * @brief Initialization method + * + * @param config + */ +void AFLRandomByteAddSubMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new AFLRandomByteAddSubMutator::AFLRandomByteAddSubMutator object + * + * @param name the name of the module + */ +AFLRandomByteAddSubMutator::AFLRandomByteAddSubMutator(std::string name) : + MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the AFLRandomByteAddSubMutator::AFLRandomByteAddSubMutator object + * + */ +AFLRandomByteAddSubMutator::~AFLRandomByteAddSubMutator() +{ + +} + +/** + * @brief Registers storage needs + * This class uses only the "TEST_CASE" key + * + * @param registry + */ +void AFLRandomByteAddSubMutator::registerStorageNeeds(StorageRegistry& registry) +{ + testCaseKey = registry.registerKey("TEST_CASE", StorageRegistry::BUFFER, StorageRegistry::READ_WRITE); +} + +void AFLRandomByteAddSubMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + + int size = baseEntry->getBufferSize(testCaseKey); + char* buffer = baseEntry->getBufferPointer(testCaseKey); + + if(size <= 0) + { + throw RuntimeException("AFLRandomByteAddSubMutator mutate called with zero sized buffer", RuntimeException::USAGE_ERROR); + } + + int byte = rand->randBelow(size); + char* newBuff = newEntry->allocateBuffer(testCaseKey, size); + memcpy((void*)newBuff, (void*)buffer, size); + newBuff[byte] -= 1 + (u8)rand->randBelow(ARITH_MAX); + newBuff[byte] += 1 + (u8)rand->randBelow(ARITH_MAX); + + return; +} \ No newline at end of file diff --git a/AFLPlusPlus/src/module/AFLRandomByteAddSubMutator.hpp b/AFLPlusPlus/src/module/AFLRandomByteAddSubMutator.hpp new file mode 100644 index 0000000..1dd0dc7 --- /dev/null +++ b/AFLPlusPlus/src/module/AFLRandomByteAddSubMutator.hpp @@ -0,0 +1,93 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +// main includes +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "VmfRand.hpp" + +// external project includes. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wwrite-strings" +#pragma GCC diagnostic pop + +namespace vmf +{ +/** + * @brief This mutator adds and subtracts bounded random values to a random byte in the buffer + * + * Note that ARITH_MAX is set to 35, so the random value is signicantly + * bounded. + * + * This module is draws heavily upon the libAFL mutator.c + * + * Uses the specified AFL-style mutation algorithm to mutate the provided + * input. createTestCase is the main mutation method. + * + * See https://github.com/AFLplusplus/LibAFL-legacy/blob/dev/src/mutator.c + * + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ +class AFLRandomByteAddSubMutator: public MutatorModule +{ +public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + AFLRandomByteAddSubMutator(std::string name); + virtual ~AFLRandomByteAddSubMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + +private: + int testCaseKey; + // afl_rand_t rand; //todo deleteme + VmfRand* rand = VmfRand::getInstance(); +}; +} diff --git a/AFLPlusPlus/src/module/AFLRandomByteMutator.cpp b/AFLPlusPlus/src/module/AFLRandomByteMutator.cpp new file mode 100644 index 0000000..ea0872a --- /dev/null +++ b/AFLPlusPlus/src/module/AFLRandomByteMutator.cpp @@ -0,0 +1,130 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +/***** + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ + +#include "AFLRandomByteMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; +using u8 = uint8_t; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(AFLRandomByteMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* + */ +Module* AFLRandomByteMutator::build(std::string name) +{ + return new AFLRandomByteMutator(name); +} + +/** + * @brief Initialization method + * + * @param config + */ +void AFLRandomByteMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new AFLRandomByteMutator::AFLRandomByteMutator object + * + * @param name the name of the module + */ +AFLRandomByteMutator::AFLRandomByteMutator(std::string name) : + MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the AFLRandomByteMutator::AFLRandomByteMutator object + * + */ +AFLRandomByteMutator::~AFLRandomByteMutator() +{ + +} + +/** + * @brief Registers storage needs + * This class uses only the "TEST_CASE" key + * + * @param registry + */ +void AFLRandomByteMutator::registerStorageNeeds(StorageRegistry& registry) +{ + testCaseKey = registry.registerKey("TEST_CASE", StorageRegistry::BUFFER, StorageRegistry::READ_WRITE); +} + +void AFLRandomByteMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + + int size = baseEntry->getBufferSize(testCaseKey); + char* buffer = baseEntry->getBufferPointer(testCaseKey); + + if(size <= 0) + { + throw RuntimeException("AFLRandomByteMutator mutate called with zero sized buffer", RuntimeException::USAGE_ERROR); + } + + char* newBuff = newEntry->allocateBuffer(testCaseKey, size); + memcpy((void*)newBuff, (void*)buffer, size); + + int idx = rand->randBelow(size); + newBuff[idx] ^= 1 + (u8)rand->randBelow(255); + + return; +} \ No newline at end of file diff --git a/AFLPlusPlus/src/module/AFLRandomByteMutator.hpp b/AFLPlusPlus/src/module/AFLRandomByteMutator.hpp new file mode 100644 index 0000000..f5987f3 --- /dev/null +++ b/AFLPlusPlus/src/module/AFLRandomByteMutator.hpp @@ -0,0 +1,90 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +// main includes +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "VmfRand.hpp" + +// external project includes. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wwrite-strings" +#pragma GCC diagnostic pop + +namespace vmf +{ +/** + * @brief This mutator adds to a random byte in the test case buffer + * This version can add a random value up to 255 to the byte. + * + * This module is draws heavily upon the libAFL mutator.c + * + * Uses the specified AFL-style mutation algorithm to mutate the provided + * input. createTestCase is the main mutation method. + * + * See https://github.com/AFLplusplus/LibAFL-legacy/blob/dev/src/mutator.c + * + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ +class AFLRandomByteMutator: public MutatorModule +{ +public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + AFLRandomByteMutator(std::string name); + virtual ~AFLRandomByteMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + +private: + int testCaseKey; + VmfRand* rand = VmfRand::getInstance(); +}; +} diff --git a/AFLPlusPlus/src/module/AFLSpliceMutator.cpp b/AFLPlusPlus/src/module/AFLSpliceMutator.cpp new file mode 100644 index 0000000..8dab038 --- /dev/null +++ b/AFLPlusPlus/src/module/AFLSpliceMutator.cpp @@ -0,0 +1,159 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +/***** + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ + +#include "AFLSpliceMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(AFLSpliceMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* + */ +Module* AFLSpliceMutator::build(std::string name) +{ + return new AFLSpliceMutator(name); +} + +/** + * @brief Initialization method + * + * @param config + */ +void AFLSpliceMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new AFLSpliceMutator::AFLSpliceMutator object + * + * @param name the name of the module + */ +AFLSpliceMutator::AFLSpliceMutator(std::string name) : + MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the AFLSpliceMutator::AFLSpliceMutator object + * + */ +AFLSpliceMutator::~AFLSpliceMutator() +{ + +} + +/** + * @brief Registers storage needs + * This class uses only the "TEST_CASE" key + * + * @param registry + */ +void AFLSpliceMutator::registerStorageNeeds(StorageRegistry& registry) +{ + testCaseKey = registry.registerKey("TEST_CASE", StorageRegistry::BUFFER, StorageRegistry::READ_WRITE); + normalTag = registry.registerTag("RAN_SUCCESSFULLY", StorageRegistry::READ_ONLY); +} + +void AFLSpliceMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + + int size = baseEntry->getBufferSize(testCaseKey); + char* buffer = baseEntry->getBufferPointer(testCaseKey); + int baseID = baseEntry->getID(); + + if(size <= 0) + { + throw RuntimeException("AFLSpliceMutator mutate called with zero sized buffer", RuntimeException::USAGE_ERROR); + } + + // get a random second test case that will be spliced + StorageEntry* secondEntry = nullptr; + int randIndex = 0; + + std::unique_ptr entries = storage.getNewEntriesByTag(normalTag); + int maxIndex = entries->getSize(); + // make sure that random case is not the same as the base case + int secondID = baseID; + int count=0; + while((secondID == baseID)&&(count<3)) + { + randIndex = rand->randBelow(maxIndex); + secondEntry = entries->setIndexTo(randIndex); + secondID = secondEntry->getID(); + count++; //We need to prevent an infinite loop in case there are only a few test cases in the queue + } + char* secondBuffer = secondEntry->getBufferPointer(testCaseKey); + int secondSize = secondEntry->getBufferSize(testCaseKey); + + // test cases may not be the same size, bound splice point based on the smaller testcase + int minSize = std::min(size, secondSize); + + //pick random splice point, from 1 to second to last byte. + //TODO(VADER-609): Consider limiting splice range to where bytes differ. + int splitAt = rand->randBelow(minSize - 1) + 1; + + // secondSize is the size of the new testcase: we copy splitAt bytes from the first, + // and (secondSize - splitAt) from the second. splitAt + secondSize - splitAt = secondSize. + char* newBuff = newEntry->allocateBuffer(testCaseKey, secondSize); + // copy from first test case + memcpy((void*)newBuff, (void*)buffer, splitAt); + // copy from second test case + memcpy((newBuff + splitAt), (secondBuffer + splitAt), (secondSize - splitAt)); + + return; +} \ No newline at end of file diff --git a/AFLPlusPlus/src/module/AFLSpliceMutator.hpp b/AFLPlusPlus/src/module/AFLSpliceMutator.hpp new file mode 100644 index 0000000..b296aba --- /dev/null +++ b/AFLPlusPlus/src/module/AFLSpliceMutator.hpp @@ -0,0 +1,90 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +// main includes +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "VmfRand.hpp" + +// external project includes. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wwrite-strings" +#pragma GCC diagnostic pop + +namespace vmf +{ +/** + * @brief This mutator splices two test cases together + * + * This module is draws heavily upon the libAFL mutator.c + * + * Uses the specified AFL-style mutation algorithm to mutate the provided + * input. createTestCase is the main mutation method. + * + * See https://github.com/AFLplusplus/LibAFL-legacy/blob/dev/src/mutator.c + * + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ +class AFLSpliceMutator: public MutatorModule +{ +public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + AFLSpliceMutator(std::string name); + virtual ~AFLSpliceMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + +private: + int testCaseKey; + int normalTag; + VmfRand* rand = VmfRand::getInstance(); +}; +} diff --git a/AFLPlusPlus/src/module/AFLWordAddSubMutator.cpp b/AFLPlusPlus/src/module/AFLWordAddSubMutator.cpp new file mode 100644 index 0000000..e0758ae --- /dev/null +++ b/AFLPlusPlus/src/module/AFLWordAddSubMutator.cpp @@ -0,0 +1,137 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +/***** + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ + +#include "AFLWordAddSubMutator.hpp" +#include "RuntimeException.hpp" +#include +#include + +using namespace vmf; +using u16 = uint16_t; + +#include "ModuleFactory.hpp" +REGISTER_MODULE(AFLWordAddSubMutator); + +/** + * @brief Builder method to support the ModuleFactory + * Constructs an instance of this class + * @return Module* + */ +Module* AFLWordAddSubMutator::build(std::string name) +{ + return new AFLWordAddSubMutator(name); +} + +/** + * @brief Initialization method + * + * @param config + */ +void AFLWordAddSubMutator::init(ConfigInterface& config) +{ + +} + +/** + * @brief Construct a new AFLWordAddSubMutator::AFLWordAddSubMutator object + * + * @param name the name of the module + */ +AFLWordAddSubMutator::AFLWordAddSubMutator(std::string name) : + MutatorModule(name) +{ + // rand->randInit(); +} + +/** + * @brief Destroy the AFLWordAddSubMutator::AFLWordAddSubMutator object + * + */ +AFLWordAddSubMutator::~AFLWordAddSubMutator() +{ + +} + +/** + * @brief Registers storage needs + * This class uses only the "TEST_CASE" key + * + * @param registry + */ +void AFLWordAddSubMutator::registerStorageNeeds(StorageRegistry& registry) +{ + testCaseKey = registry.registerKey("TEST_CASE", StorageRegistry::BUFFER, StorageRegistry::READ_WRITE); +} + +void AFLWordAddSubMutator::mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey) +{ + + int size = baseEntry->getBufferSize(testCaseKey); + char* buffer = baseEntry->getBufferPointer(testCaseKey); + + if(size <= 0) + { + throw RuntimeException("AFLWordAddSubMutator mutate called with zero sized buffer", RuntimeException::USAGE_ERROR); + } + + // Copy base entry to new entry + char* newBuff = newEntry->allocateBuffer(testCaseKey, size); + memcpy((void*)newBuff, (void*)buffer, size); + + if(size < 2) + { + return; + } + + int byte = rand->randBelow(size - 1); + *(u16 *)(newBuff + byte) -= 1 + (u16)rand->randBelow(ARITH_MAX); + *(u16 *)(newBuff + byte) += 1 + (u16)rand->randBelow(ARITH_MAX); + + return; +} \ No newline at end of file diff --git a/AFLPlusPlus/src/module/AFLWordAddSubMutator.hpp b/AFLPlusPlus/src/module/AFLWordAddSubMutator.hpp new file mode 100644 index 0000000..a0727cf --- /dev/null +++ b/AFLPlusPlus/src/module/AFLWordAddSubMutator.hpp @@ -0,0 +1,92 @@ +/* ============================================================================= + * Vader Modular Fuzzer (VMF) + * Copyright (c) 2021-2023 The Charles Stark Draper Laboratory, Inc. + * + * + * Effort sponsored by the U.S. Government under Other Transaction number + * W9124P-19-9-0001 between AMTC and the Government. The U.S. Government + * Is authorized to reproduce and distribute reprints for Governmental purposes + * notwithstanding any copyright notation thereon. + * + * The views and conclusions contained herein are those of the authors and + * should not be interpreted as necessarily representing the official policies + * or endorsements, either expressed or implied, of the U.S. Government. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (only) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * @license GPL-2.0-only + * ===========================================================================*/ +#pragma once + +// main includes +#include "MutatorModule.hpp" +#include "StorageEntry.hpp" +#include "RuntimeException.hpp" +#include "VmfRand.hpp" + +// external project includes. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wwrite-strings" +#pragma GCC diagnostic pop + +namespace vmf +{ +/** + * @brief This mutator adds and subtracts bounded random values to a random word in the buffer + * + * Note that ARITH_MAX is set to 35, so the random value is signicantly + * bounded. + * + * This module is draws heavily upon the libAFL mutator.c + * + * Uses the specified AFL-style mutation algorithm to mutate the provided + * input. createTestCase is the main mutation method. + * + * See https://github.com/AFLplusplus/LibAFL-legacy/blob/dev/src/mutator.c + * + * The following includes code copied from the LibAFL_Legacy repository. + * + * american fuzzy lop++ - fuzzer header + * ------------------------------------ + * Originally written by Michal Zalewski + * Now maintained by Marc Heuse , + * Heiko Eißfeldt , + * Andrea Fioraldi , + * Dominik Maier + * Copyright 2016, 2017 Google Inc. All rights reserved. + * Copyright 2019-2020 AFLplusplus Project. All rights reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * http://www.apache.org/licenses/LICENSE-2.0 + * This is the Library based on AFL++ which can be used to build + * customized fuzzers for a specific target while taking advantage of + * a lot of features that AFL++ already provides. + */ +class AFLWordAddSubMutator: public MutatorModule +{ +public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + AFLWordAddSubMutator(std::string name); + virtual ~AFLWordAddSubMutator(); + virtual void registerStorageNeeds(StorageRegistry& registry); + virtual void mutateTestCase(StorageModule& storage, StorageEntry* baseEntry, StorageEntry* newEntry, int testCaseKey); + +private: + int testCaseKey; + VmfRand* rand = VmfRand::getInstance(); +}; +} diff --git a/AFLPlusPlus/src/module/README.md b/AFLPlusPlus/src/module/README.md new file mode 100644 index 0000000..ddf6926 --- /dev/null +++ b/AFLPlusPlus/src/module/README.md @@ -0,0 +1,8 @@ +# Sample module + +This sample shows how to write a VMF mutator module. You can put multiple VMF modules into +a single shared library. + +The module here doesn't do anything useful. It just shows how to set up your build process to +integrate with VMF. + diff --git a/AFLPlusPlus/src/module/config.h b/AFLPlusPlus/src/module/config.h new file mode 100644 index 0000000..6adf4cc --- /dev/null +++ b/AFLPlusPlus/src/module/config.h @@ -0,0 +1,576 @@ +/* + american fuzzy lop++ - vaguely configurable bits + ------------------------------------------------ + + Originally written by Michal Zalewski + + Now maintained by Marc Heuse , + Dominik Maier + Andrea Fioraldi , + Heiko Eissfeldt , + + Copyright 2016, 2017 Google Inc. All rights reserved. + Copyright 2019-2024 AFLplusplus Project. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + https://www.apache.org/licenses/LICENSE-2.0 + + */ + + #ifndef _HAVE_CONFIG_H + #define _HAVE_CONFIG_H + + /* Version string: */ + + // c = release, a = volatile github dev, e = experimental branch + #define VERSION "++4.33a" + + /****************************************************** + * * + * Settings that may be of interest to power users: * + * * + ******************************************************/ + + /* Default shared memory map size. Most targets just need a coverage map + between 20-250kb. Plus there is an auto-detection feature in afl-fuzz. + However if a target has problematic constructors and init arrays then + this can fail. Hence afl-fuzz deploys a larger default map. The largest + map seen so far is the xlsx fuzzer for libreoffice which is 5MB. + At runtime this value can be overridden via AFL_MAP_SIZE. + Default: 8MB (defined in bytes) */ + #define DEFAULT_SHMEM_SIZE (8 * 1024 * 1024) + + /* Default time until when no more coverage finds are happening afl-fuzz + switches to exploitation mode. It automatically switches back when new + coverage is found. + Default: 300 (seconds) */ + #define STRATEGY_SWITCH_TIME 1000 + + /* Default file permission umode when creating files (default: 0600) */ + #define DEFAULT_PERMISSION 0600 + + #ifdef __APPLE__ + #include + #if TARGET_OS_IOS + #undef DEFAULT_PERMISSION + #define DEFAULT_PERMISSION 0666 + #endif + #endif + #ifdef __ANDROID__ + #undef DEFAULT_PERMISSION + #define DEFAULT_PERMISSION 0666 + #endif + + /* SkipDet's global configuration */ + + #define MINIMAL_BLOCK_SIZE 64 + #define SMALL_DET_TIME (60 * 1000 * 1000U) + #define MAXIMUM_INF_EXECS (16 * 1024U) + #define MAXIMUM_QUICK_EFF_EXECS (64 * 1024U) + #define THRESHOLD_DEC_TIME (20 * 60 * 1000U) + + /* Set the Prob of selecting eff_bytes 3 times more than original, + Now disabled */ + #define EFF_HAVOC_RATE 3 + + /* CMPLOG/REDQUEEN TUNING + * + * Here you can modify tuning and solving options for CMPLOG. + * Note that these are run-time options for afl-fuzz, no target + * recompilation required. + * + */ + + /* If a redqueen pass finds more than one solution, try to combine them? */ + #define CMPLOG_COMBINE + + /* Minimum % of the corpus to perform cmplog on. Default: 10% */ + #define CMPLOG_CORPUS_PERCENT 5U + + /* Number of potential positions from which we decide if cmplog becomes + useless, default 12288 */ + #define CMPLOG_POSITIONS_MAX (12 * 1024) + + /* Maximum allowed fails per CMP value. Default: 96 */ + #define CMPLOG_FAIL_MAX 96 + + /* + * Effective fuzzing with selective feeding inputs + */ + + #define MAX_EXTRA_SAN_BINARY 4 + + /* -------------------------------------*/ + /* Now non-cmplog configuration options */ + /* -------------------------------------*/ + + /* If a persistent target keeps state and found crashes are not reproducible + then enable this option and set the AFL_PERSISTENT_RECORD env variable + to a number. These number of testcases prior and including the crash case + will be kept and written to the crash/ directory as RECORD:... files. + Note that every crash will be written, not only unique ones! */ + + // #define AFL_PERSISTENT_RECORD + + /* Adds support in compiler-rt to replay persistent records in @@-style + * harnesses */ + + // #define AFL_PERSISTENT_REPLAY_ARGPARSE + + /* console output colors: There are three ways to configure its behavior + * 1. default: colored outputs fixed on: defined USE_COLOR && defined + * ALWAYS_COLORED The env var. AFL_NO_COLOR will have no effect + * 2. defined USE_COLOR && !defined ALWAYS_COLORED + * -> depending on env var AFL_NO_COLOR=1 colors can be switched off + * at run-time. Default is to use colors. + * 3. colored outputs fixed off: !defined USE_COLOR + * The env var. AFL_NO_COLOR will have no effect + */ + + /* Comment out to disable terminal colors (note that this makes afl-analyze + a lot less nice): */ + + #define USE_COLOR + + #ifdef USE_COLOR + /* Comment in to always enable terminal colors */ + /* Comment out to enable runtime controlled terminal colors via AFL_NO_COLOR + */ + #define ALWAYS_COLORED 1 + #endif + + /* StatsD config + Config can be adjusted via AFL_STATSD_HOST and AFL_STATSD_PORT environment + variable. + */ + #define STATSD_UPDATE_SEC 1 + #define STATSD_DEFAULT_PORT 8125 + #define STATSD_DEFAULT_HOST "127.0.0.1" + + /* If you want to have the original afl internal memory corruption checks. + Disabled by default for speed. it is better to use "make ASAN_BUILD=1". */ + + // #define _WANT_ORIGINAL_AFL_ALLOC + + /* Comment out to disable fancy boxes and use poor man's 7-bit UI: */ + + #ifndef DISABLE_FANCY + #define FANCY_BOXES + #endif + + /* Default timeout for fuzzed code (milliseconds). This is the upper bound, + also used for detecting hangs; the actual value is auto-scaled: */ + + #define EXEC_TIMEOUT 1000U + + /* Timeout rounding factor when auto-scaling (milliseconds): */ + + #define EXEC_TM_ROUND 20U + + /* 64bit arch MACRO */ + #if (defined(__x86_64__) || defined(__arm64__) || defined(__aarch64__) || \ + (defined(__riscv) && __riscv_xlen == 64) || defined(__powerpc64le__) || \ + defined(__s390x__) || defined(__loongarch64)) + #define WORD_SIZE_64 1 + #endif + + /* Default memory limit for child process (MB) 0 = disabled : */ + + #define MEM_LIMIT 0U + + /* Default memory limit when running in QEMU mode (MB) 0 = disabled : */ + + #define MEM_LIMIT_QEMU 0U + + /* Default memory limit when running in Unicorn mode (MB) 0 = disabled : */ + + #define MEM_LIMIT_UNICORN 0U + + /* Number of calibration cycles per every new test case (and for test + cases that show variable behavior): */ + + #define CAL_CYCLES_FAST 3U + #define CAL_CYCLES 7U + #define CAL_CYCLES_LONG 12U + + /* Number of subsequent timeouts before abandoning an input file: */ + + #define TMOUT_LIMIT 250U + + /* Maximum number of unique hangs or crashes to record: */ + + #define KEEP_UNIQUE_HANG 512U + #define KEEP_UNIQUE_CRASH 25600U + + /* Baseline number of random tweaks during a single 'havoc' stage: */ + + #define HAVOC_CYCLES 256U + #define HAVOC_CYCLES_INIT 1024U + + /* Maximum multiplier for the above (should be a power of two, beware + of 32-bit int overflows): */ + + #define HAVOC_MAX_MULT 64U + #define HAVOC_MAX_MULT_MOPT 64U + + /* Absolute minimum number of havoc cycles (after all adjustments): */ + + #define HAVOC_MIN 12U + + /* Power Schedule Divisor */ + #define POWER_BETA 1U + #define MAX_FACTOR (POWER_BETA * 32) + + /* Maximum stacking for havoc-stage tweaks. The actual value is calculated + like this: + + n = random between 1 and HAVOC_STACK_POW2 + stacking = 2^n + + In other words, the default (n = 4) produces 2, 4, 8, 16 + stacked tweaks: */ + + #define HAVOC_STACK_POW2 4U + + /* Caps on block sizes for cloning and deletion operations. Each of these + ranges has a 33% probability of getting picked, except for the first + two cycles where smaller blocks are favored: */ + + #define HAVOC_BLK_SMALL 32U + #define HAVOC_BLK_MEDIUM 128U + #define HAVOC_BLK_LARGE 1500U + + /* Extra-large blocks, selected very rarely (<5% of the time): */ + + #define HAVOC_BLK_XL 32768U + + /* Probabilities of skipping non-favored entries in the queue, expressed as + percentages: */ + + #define SKIP_TO_NEW_PROB 99 /* ...when there are new, pending favorites */ + #define SKIP_NFAV_OLD_PROB 95 /* ...no new favs, cur entry already fuzzed */ + #define SKIP_NFAV_NEW_PROB 75 /* ...no new favs, cur entry not fuzzed yet */ + + /* Splicing cycle count: */ + + #define SPLICE_CYCLES 15 + + /* Nominal per-splice havoc cycle length: */ + + #define SPLICE_HAVOC 32 + + /* Maximum offset for integer addition / subtraction stages: */ + + #define ARITH_MAX 35 + + /* Limits for the test case trimmer. The absolute minimum chunk size; and + the starting and ending divisors for chopping up the input file: */ + + #define TRIM_MIN_BYTES 4 + #define TRIM_START_STEPS 16 + #define TRIM_END_STEPS 1024 + + /* Maximum size of input file, in bytes (keep under 100MB, default 1MB): + (note that if this value is changed, several areas in afl-cc.c, afl-fuzz.c + and afl-fuzz-state.c have to be changed as well! */ + + #define MAX_FILE (1 * 1024 * 1024L) + + /* The same, for the test case minimizer: */ + + #define TMIN_MAX_FILE (10 * 1024 * 1024L) + + /* Block normalization steps for afl-tmin: */ + + #define TMIN_SET_MIN_SIZE 4 + #define TMIN_SET_STEPS 128 + + /* Maximum dictionary token size (-x), in bytes: */ + + #define MAX_DICT_FILE 128 + + /* Length limits for auto-detected dictionary tokens: */ + + #define MIN_AUTO_EXTRA 3 + #define MAX_AUTO_EXTRA 32 + + /* Maximum number of user-specified dictionary tokens to use in deterministic + steps; past this point, the "extras/user" step will be still carried out, + but with proportionally lower odds: */ + + #define MAX_DET_EXTRAS 256 + + /* Maximum number of auto-extracted dictionary tokens to actually use in fuzzing + (first value), and to keep in memory as candidates. The latter should be much + higher than the former. */ + + #define USE_AUTO_EXTRAS 4096 + #define MAX_AUTO_EXTRAS (USE_AUTO_EXTRAS * 8) + + /* Scaling factor for the effector map used to skip some of the more + expensive deterministic steps. The actual divisor is set to + 2^EFF_MAP_SCALE2 bytes: */ + + #define EFF_MAP_SCALE2 3 + + /* Minimum input file length at which the effector logic kicks in: */ + + #define EFF_MIN_LEN 128 + + /* Maximum effector density past which everything is just fuzzed + unconditionally (%): */ + + #define EFF_MAX_PERC 90 + + /* UI refresh frequency (Hz): */ + + #define UI_TARGET_HZ 5 + + /* Fuzzer stats file, queue stats and plot update intervals (sec): */ + + #define STATS_UPDATE_SEC 60 + #define PLOT_UPDATE_SEC 5 + #define QUEUE_UPDATE_SEC 1800 + + /* Smoothing divisor for CPU load and exec speed stats (1 - no smoothing). */ + + #define AVG_SMOOTHING 16 + + /* Max length of sync id (the id after -M and -S) */ + + #define SYNC_ID_MAX_LEN 50 + + /* Sync interval (every n havoc cycles): */ + + #define SYNC_INTERVAL 8 + + /* Sync time (minimum time between syncing in ms, time is halfed for -M main + nodes) - default is 20 minutes: */ + + #define SYNC_TIME (20 * 60 * 1000) + + /* Output directory reuse grace period (minutes): */ + + #define OUTPUT_GRACE 25 + + /* Uncomment to use simple file names (id_NNNNNN): */ + + // #define SIMPLE_FILES + + /* List of interesting values to use in fuzzing. */ + + #define INTERESTING_8 \ + -128, /* Overflow signed 8-bit when decremented */ \ + -1, /* */ \ + 0, /* */ \ + 1, /* */ \ + 16, /* One-off with common buffer size */ \ + 32, /* One-off with common buffer size */ \ + 64, /* One-off with common buffer size */ \ + 100, /* One-off with common buffer size */ \ + 127 /* Overflow signed 8-bit when incremented */ + + #define INTERESTING_8_LEN 9 + + #define INTERESTING_16 \ + -32768, /* Overflow signed 16-bit when decremented */ \ + -129, /* Overflow signed 8-bit */ \ + 128, /* Overflow signed 8-bit */ \ + 255, /* Overflow unsig 8-bit when incremented */ \ + 256, /* Overflow unsig 8-bit */ \ + 512, /* One-off with common buffer size */ \ + 1000, /* One-off with common buffer size */ \ + 1024, /* One-off with common buffer size */ \ + 4096, /* One-off with common buffer size */ \ + 32767 /* Overflow signed 16-bit when incremented */ + + #define INTERESTING_16_LEN 10 + + #define INTERESTING_32 \ + -2147483648LL, /* Overflow signed 32-bit when decremented */ \ + -100663046, /* Large negative number (endian-agnostic) */ \ + -32769, /* Overflow signed 16-bit */ \ + 32768, /* Overflow signed 16-bit */ \ + 65535, /* Overflow unsig 16-bit when incremented */ \ + 65536, /* Overflow unsig 16 bit */ \ + 100663045, /* Large positive number (endian-agnostic) */ \ + 2139095040, /* float infinite */ \ + 2147483647 /* Overflow signed 32-bit when incremented */ + + #define INTERESTING_32_LEN 9 + + /*********************************************************** + * * + * Really exotic stuff you probably don't want to touch: * + * * + ***********************************************************/ + + /* Call count interval between reseeding the PRNG from /dev/urandom: */ + + #define RESEED_RNG 2500000 + + /* The default maximum testcase cache size in MB, 0 = disable. + A value between 50 and 250 is a good default value. Note that the + number of entries will be auto assigned if not specified via the + AFL_TESTCACHE_ENTRIES env variable */ + + #define TESTCASE_CACHE_SIZE 50 + + /* Maximum line length passed from GCC to 'as' and used for parsing + configuration files: */ + + #define MAX_LINE 8192 + + /* Environment variable used to pass SHM ID to the called program. */ + + #define SHM_ENV_VAR "__AFL_SHM_ID" + + /* Environment variable used to pass shared memory fuzz map id + and the mapping size to the called program. */ + + #define SHM_FUZZ_ENV_VAR "__AFL_SHM_FUZZ_ID" + #define SHM_FUZZ_MAP_SIZE_ENV_VAR "__AFL_SHM_FUZZ_MAP_SIZE" + + /* Default size of the shared memory fuzz map. + We add 4 byte for one u32 length field. */ + #define SHM_FUZZ_MAP_SIZE_DEFAULT (MAX_FILE + 4) + + /* Other less interesting, internal-only variables. */ + + #define CLANG_ENV_VAR "__AFL_CLANG_MODE" + #define AS_LOOP_ENV_VAR "__AFL_AS_LOOPCHECK" + #define PERSIST_ENV_VAR "__AFL_PERSISTENT" + #define DEFER_ENV_VAR "__AFL_DEFER_FORKSRV" + + /* In-code signatures for deferred and persistent mode. */ + + #define PERSIST_SIG "##SIG_AFL_PERSISTENT##" + #define DEFER_SIG "##SIG_AFL_DEFER_FORKSRV##" + + /* Distinctive bitmap signature used to indicate failed execution: */ + + #define EXEC_FAIL_SIG 0xfee1dead + + /* Distinctive exit code used to indicate MSAN trip condition: */ + + #define MSAN_ERROR 86 + + /* Distinctive exit code used to indicate LSAN trip condition: */ + + #define LSAN_ERROR 23 + + /* Designated file descriptors for forkserver commands (the application will + use FORKSRV_FD and FORKSRV_FD + 1): */ + + #define FORKSRV_FD 198 + + /* Fork server init timeout multiplier: we'll wait the user-selected + timeout plus this much for the fork server to spin up. */ + + #define FORK_WAIT_MULT 10 + + /* Calibration timeout adjustments, to be a bit more generous when resuming + fuzzing sessions or trying to calibrate already-added internal finds. + The first value is a percentage, the other is in milliseconds: */ + + #define CAL_TMOUT_PERC 125 + #define CAL_TMOUT_ADD 50 + + /* Number of chances to calibrate a case before giving up: */ + + #define CAL_CHANCES 3 + + /* Map size for the traced binary (2^MAP_SIZE_POW2). Must be greater than + 2; you probably want to keep it under 18 or so for performance reasons + (adjusting AFL_INST_RATIO when compiling is probably a better way to solve + problems with complex programs). You need to recompile the target binary + after changing this - otherwise, SEGVs may ensue. */ + + #define MAP_SIZE_POW2 16 + + /* Do not change this unless you really know what you are doing. */ + + #define MAP_SIZE (1U << MAP_SIZE_POW2) + #if MAP_SIZE <= 2097152 + #define MAP_INITIAL_SIZE (2 << 20) // = 2097152 + #else + #define MAP_INITIAL_SIZE MAP_SIZE + #endif + + /* Maximum allocator request size (keep well under INT_MAX): */ + + #define MAX_ALLOC 0x40000000 + + /* A made-up hashing seed: */ + + #define HASH_CONST 0xa5b35705 + + /* Constants for afl-gotcpu to control busy loop timing: */ + + #define CTEST_TARGET_MS 5000 + #define CTEST_CORE_TRG_MS 1000 + #define CTEST_BUSY_CYCLES (10 * 1000 * 1000) + + /* Enable NeverZero counters in QEMU mode */ + + #define AFL_QEMU_NOT_ZERO + + /* AFL RedQueen */ + + #define CMPLOG_SHM_ENV_VAR "__AFL_CMPLOG_SHM_ID" + + /* ASAN SHM ID */ + #define AFL_ASAN_FUZZ_SHM_ENV_VAR "__AFL_ASAN_SHM_ID" + + /* CPU Affinity lockfile env var */ + + #define CPU_AFFINITY_ENV_VAR "__AFL_LOCKFILE" + + /* Uncomment this to use inferior block-coverage-based instrumentation. Note + that you need to recompile the target binary for this to have any effect: */ + + // #define COVERAGE_ONLY + + /* Uncomment this to ignore hit counts and output just one bit per tuple. + As with the previous setting, you will need to recompile the target + binary: */ + + // #define SKIP_COUNTS + + /* Uncomment this to use instrumentation data to record newly discovered paths, + but do not use them as seeds for fuzzing. This is useful for conveniently + measuring coverage that could be attained by a "dumb" fuzzing algorithm: */ + + // #define IGNORE_FINDS + + /* Text mutations */ + + /* Minimum length of a queue input to be evaluated for "is_ascii"? */ + + #define AFL_TXT_MIN_LEN 12 + + /* Maximum length of a queue input to be evaluated for "is_ascii"? */ + + #define AFL_TXT_MAX_LEN 65535 + + /* What is the minimum percentage of ascii characters present to be classified + as "is_ascii"? */ + + #define AFL_TXT_MIN_PERCENT 99 + + /* How often to perform ASCII mutations 0 = disable, 1-8 are good values */ + + #define AFL_TXT_BIAS 6 + + /* Maximum length of a string to tamper with */ + + #define AFL_TXT_STRING_MAX_LEN 1024 + + /* Maximum mutations on a string */ + + #define AFL_TXT_STRING_MAX_MUTATIONS 6 + + #endif /* ! _HAVE_CONFIG_H */ \ No newline at end of file diff --git a/AFLPlusPlus/test/README.md b/AFLPlusPlus/test/README.md new file mode 100644 index 0000000..cb3a52c --- /dev/null +++ b/AFLPlusPlus/test/README.md @@ -0,0 +1,6 @@ += SamplePackage tests + +== Overview + +This directory contains unit and integration tests for the SamplePackage modules. + diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f5da9e..91a8788 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,6 +63,7 @@ add_subdirectory(${PROJECT_SOURCE_DIR}/test) # Add in extension package directories add_subdirectory(${PROJECT_SOURCE_DIR}/Determinism) +add_subdirectory(${PROJECT_SOURCE_DIR}/AFLPlusPlus) add_subdirectory(${PROJECT_SOURCE_DIR}/Radamsa) #add_subdirectory(${PROJECT_SOURCE_DIR}/SamplePackage) diff --git a/Radamsa/test/config/experimentalModules.yaml b/Radamsa/test/config/experimentalModules.yaml deleted file mode 100644 index 75c863f..0000000 --- a/Radamsa/test/config/experimentalModules.yaml +++ /dev/null @@ -1,53 +0,0 @@ -vmfModules: - storage: #a storage module must be specified - className: SimpleStorage - controller: #a controller module must be specified - className: IterativeController - children: - - className: DirectoryBasedSeedGen - - className: GeneticAlgorithmInputGenerator - - className: AFLForkserverExecutor - - className: AFLFeedback - - className: SaveCorpusOutput - - className: ComputeStats - - className: StatsOutput - GeneticAlgorithmInputGenerator: - children: - - className: RadamsaCopyLineCloseByMutator - - className: RadamsaDecrementByteMutator - - className: RadamsaDeleteByteSequenceMutator - - className: RadamsaDeleteLineMutator - - className: RadamsaDeleteNodeMutator - - className: RadamsaDeleteSequentialLinesMutator - - className: RadamsaDropByteMutator - - className: RadamsaDuplicateLineMutator - # - className: RadamsaDuplicateNodeMutator - - className: RadamsaFlipByteMutator - - className: RadamsaFuseNextMutator - - className: RadamsaFuseOldMutator - - className: RadamsaFuseThisMutator - - className: RadamsaIncrementByteMutator - - className: RadamsaInsertByteMutator - # - className: RadamsaInsertLineMutator - - className: RadamsaInsertUnicodeMutator - # - className: RadamsaModifyTextNumberMutator - - className: RadamsaPermuteByteMutator - # - className: RadamsaPermuteLinesMutator - - className: RadamsaRandomizeByteMutator - - className: RadamsaRepeatByteMutator - - className: RadamsaRepeatByteSequenceMutator - - className: RadamsaRepeatLineMutator - # - className: RadamsaRepeatPathMutator - # - className: RadamsaReplaceLineMutator - # - className: RadamsaReplaceNodeMutator - # - className: RadamsaSwapLineMutator - # - className: RadamsaSwapNodesMutator - # - className: RadamsaWidenCodePointMutator - -# Modules-specific parameters -#(The SUT-specific portions of these all defined using YAML anchors) -AFLForkserverExecutor: - sutArgv: *SUT_ARGV - -DirectoryBasedSeedGen: - inputDir: *INPUT_DIR \ No newline at end of file diff --git a/Radamsa/vmf/src/modules/common/mutator/RadamsaAsciiBadMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaAsciiBadMutator.cpp index 0178654..4c2ee3a 100644 --- a/Radamsa/vmf/src/modules/common/mutator/RadamsaAsciiBadMutator.cpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaAsciiBadMutator.cpp @@ -43,7 +43,6 @@ using std::holds_alternative; using std::string; using std::variant; - #include "ModuleFactory.hpp" REGISTER_MODULE(RadamsaAsciiBadMutator); diff --git a/dockerfiles/Dockerfile b/dockerfiles/Dockerfile index d5dfef7..6c78486 100644 --- a/dockerfiles/Dockerfile +++ b/dockerfiles/Dockerfile @@ -69,7 +69,7 @@ RUN set -ex \ # Create experimental config file RUN set -ex \ && cd /usr/local/src/ \ - && cp VmfExperimental/Radamsa/test/config/experimentalModules.yaml VaderModularFuzzer/build/vmf_install/test/config/experimentalModules.yaml \ + && cp VmfExperimental/test/config/experimentalModules.yaml VaderModularFuzzer/build/vmf_install/test/config/experimentalModules.yaml \ && set +ex # WORKDIR /usr/local/src/VmfExperimental/build diff --git a/test/config/experimentalModules.yaml b/test/config/experimentalModules.yaml new file mode 100644 index 0000000..b8802b8 --- /dev/null +++ b/test/config/experimentalModules.yaml @@ -0,0 +1,72 @@ +vmfModules: + storage: #a storage module must be specified + className: SimpleStorage + controller: #a controller module must be specified + className: IterativeController + children: + - className: DirectoryBasedSeedGen + - className: GeneticAlgorithmInputGenerator + - className: AFLForkserverExecutor + - className: AFLFeedback + - className: SaveCorpusOutput + - className: ComputeStats + - className: StatsOutput + GeneticAlgorithmInputGenerator: + children: + # - className: RadamsaCopyLineCloseByMutator + # - className: RadamsaDecrementByteMutator + # - className: RadamsaDeleteByteSequenceMutator + # - className: RadamsaDeleteLineMutator + # - className: RadamsaDeleteNodeMutator + # - className: RadamsaDeleteSequentialLinesMutator + # - className: RadamsaDropByteMutator + # - className: RadamsaDuplicateLineMutator + # # - className: RadamsaDuplicateNodeMutator + # - className: RadamsaFlipByteMutator + # - className: RadamsaFuseNextMutator + # - className: RadamsaFuseOldMutator + # - className: RadamsaFuseThisMutator + # - className: RadamsaIncrementByteMutator + # - className: RadamsaInsertByteMutator + # # - className: RadamsaInsertLineMutator + # - className: RadamsaInsertUnicodeMutator + # # - className: RadamsaModifyTextNumberMutator + # - className: RadamsaPermuteByteMutator + # # - className: RadamsaPermuteLinesMutator + # - className: RadamsaRandomizeByteMutator + # - className: RadamsaRepeatByteMutator + # - className: RadamsaRepeatByteSequenceMutator + # - className: RadamsaRepeatLineMutator + # # - className: RadamsaRepeatPathMutator + # # - className: RadamsaReplaceLineMutator + # # - className: RadamsaReplaceNodeMutator + # # - className: RadamsaSwapLineMutator + # # - className: RadamsaSwapNodesMutator + # # - className: RadamsaWidenCodePointMutator + - className: AFLCloneMutator + - className: AFLDWordAddSubMutator + - className: AFLDeleteMutator + - className: AFLFlip2BitMutator + - className: AFLFlip2ByteMutator + - className: AFLFlip4BitMutator + - className: AFLFlip4ByteMutator + - className: AFLFlipBitMutator + - className: AFLFlipByteMutator + - className: AFLInteresting16Mutator + - className: AFLInteresting32Mutator + - className: AFLInteresting8Mutator + - className: AFLOverwriteCopyMutator + - className: AFLOverwriteFixedMutator + - className: AFLRandomByteAddSubMutator + - className: AFLRandomByteMutator + - className: AFLSpliceMutator + - className: AFLWordAddSubMutator + + +# Modules-specific parameters +#(The SUT-specific portions of these all defined using YAML anchors) +AFLForkserverExecutor: + sutArgv: *SUT_ARGV + +DirectoryBasedSeedGen: + inputDir: *INPUT_DIR \ No newline at end of file