diff --git a/.gitignore b/.gitignore index 47d6822..524a5e8 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ *.obj *.*~ *.exe +*.swp # Vader */VaderWin/.vs/* 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/Radamsa/vmf/src/modules/common/mutator/radamsaMutator.hpp b/AFLPlusPlus/src/module/AFLDeleteMutator.hpp similarity index 50% rename from Radamsa/vmf/src/modules/common/mutator/radamsaMutator.hpp rename to AFLPlusPlus/src/module/AFLDeleteMutator.hpp index 4cf16b6..f5c8cce 100644 --- a/Radamsa/vmf/src/modules/common/mutator/radamsaMutator.hpp +++ b/AFLPlusPlus/src/module/AFLDeleteMutator.hpp @@ -1,8 +1,17 @@ /* ============================================================================= * Vader Modular Fuzzer (VMF) - * Copyright (c) 2021-2025 The Charles Stark Draper Laboratory, Inc. - * - * + * 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. @@ -19,22 +28,31 @@ * ===========================================================================*/ #pragma once -// VMF Includes +// main includes #include "MutatorModule.hpp" #include "StorageEntry.hpp" #include "RuntimeException.hpp" -#include "byteMutations.hpp" -#include "lineMutations.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::modules::radamsa +namespace vmf { /** - * @brief This module is draws heavily upon the libAFL mutator.c + * @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. mutateTestCase is the main mutation method. - * + * 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. @@ -56,68 +74,22 @@ namespace vmf::modules::radamsa * 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 +class AFLDeleteMutator: public MutatorModule { 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"))); } + 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 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 normalTag_{INVALID_NORMAL_TAG_}; - AlgorithmType algorithmType_{AlgorithmType::ByteMutations_DropByte}; - - std::default_random_engine RANDOM_NUMBER_GENERATOR_; - + 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 aa4dc48..91a8788 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,10 +38,32 @@ 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() +add_subdirectory(${PROJECT_SOURCE_DIR}/test) + # ---- TAILOR SPECIFIC EXTENSION PACKAGES HERE ---- # 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/README.md b/README.md index a0a3f12..3383be2 100644 --- a/README.md +++ b/README.md @@ -26,8 +26,7 @@ VaderModularFuzzer repository: 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 `-DCMAKE_INSTALL_PREFIX=/path/to/VMF`. @@ -75,8 +74,38 @@ 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 +``` + +### 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/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/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/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 new file mode 100644 index 0000000..39ad5fd --- /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 + 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 + ) << "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/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/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/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/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/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/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/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/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/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/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..933e976 --- /dev/null +++ b/Radamsa/test/RadamsaRepeatByteMutatorTest.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 "gtest/gtest.h" +#include "ModuleTestHelper.hpp" +#include "SimpleStorage.hpp" +#include "RadamsaRepeatByteMutator.hpp" +#include "RuntimeException.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; +using vmf::RuntimeException; + +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, 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(); + 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/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/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/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/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/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/test/byteMutationTest.cpp b/Radamsa/test/byteMutationTest.cpp deleted file mode 100644 index dbf5d37..0000000 --- a/Radamsa/test/byteMutationTest.cpp +++ /dev/null @@ -1,705 +0,0 @@ -/* ============================================================================= - * 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 - * ===========================================================================*/ - -// VMF Includes -#include "byteMutationTest.h" - -namespace vmf::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)); -} -} diff --git a/Radamsa/test/byteMutationTest.h b/Radamsa/test/byteMutationTest.h deleted file mode 100644 index 11d392d..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 vmf::test::modules::radamsa::mutations -{ -class ByteMutationTest : public ::testing::Test, - public ::vmf::radamsa::mutations::ByteMutations -{ -public: - virtual ~ByteMutationTest() = default; - - ByteMutationTest() : ::vmf::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", - vmf::StorageRegistry::INT, - vmf::StorageRegistry::ASCENDING)}; - std::unique_ptr metadata{std::make_unique()}; - - const int testCaseKey{ - registry->registerKey( - "TEST_CASE", - vmf::StorageRegistry::BUFFER, - vmf::StorageRegistry::READ_WRITE)}; - - storage->configure(registry.get(), metadata.get()); - - vmf::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_; -}; -} diff --git a/Radamsa/test/lineMutationTest.cpp b/Radamsa/test/lineMutationTest.cpp deleted file mode 100644 index f6cd4a8..0000000 --- a/Radamsa/test/lineMutationTest.cpp +++ /dev/null @@ -1,4637 +0,0 @@ -/* ============================================================================= - * 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 - * ===========================================================================*/ - -// VMF Includes -#include "lineMutationTest.h" - -namespace vmf::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); - } -} -} diff --git a/Radamsa/test/lineMutationTest.h b/Radamsa/test/lineMutationTest.h deleted file mode 100644 index 0a40566..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 vmf::test::modules::radamsa::mutations -{ -class LineMutationTest : public ::testing::Test, - public ::vmf::radamsa::mutations::LineMutations -{ -public: - virtual ~LineMutationTest() = default; - - LineMutationTest() : ::vmf::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", - vmf::StorageRegistry::INT, - vmf::StorageRegistry::ASCENDING)}; - std::unique_ptr metadata{std::make_unique()}; - - const int testCaseKey{ - registry->registerKey( - "TEST_CASE", - vmf::StorageRegistry::BUFFER, - vmf::StorageRegistry::READ_WRITE)}; - - storage->configure(registry.get(), metadata.get()); - - vmf::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_; -}; -} diff --git a/Radamsa/test/mutationBaseTest.cpp b/Radamsa/test/mutationBaseTest.cpp deleted file mode 100644 index 0687902..0000000 --- a/Radamsa/test/mutationBaseTest.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* ============================================================================= - * 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 - * ===========================================================================*/ - -// VMF Includes -#include "mutationBaseTest.h" - -namespace vmf::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); - } -} -} diff --git a/Radamsa/test/mutationBaseTest.h b/Radamsa/test/mutationBaseTest.h deleted file mode 100644 index e4504c0..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 vmf::test::modules::radamsa::mutations -{ -class MutationBaseTest : public ::testing::Test, - public ::vmf::radamsa::mutations::MutationBase -{ -public: - virtual ~MutationBaseTest() = default; - - MutationBaseTest() : ::vmf::radamsa::mutations::MutationBase{randomNumberGenerator_} {} - -protected: - -private: - std::default_random_engine randomNumberGenerator_; -}; -} diff --git a/Radamsa/test/radamsaMutatorTest.cpp b/Radamsa/test/radamsaMutatorTest.cpp deleted file mode 100644 index c210087..0000000 --- a/Radamsa/test/radamsaMutatorTest.cpp +++ /dev/null @@ -1,483 +0,0 @@ -/* ============================================================================= - * 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 - * ===========================================================================*/ - -// Google Test Includes -#include "gtest/gtest.h" - -// VMF Includes -#include "radamsaMutatorTest.hpp" - -namespace vmf::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: \"vmf::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: \"vmf::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: \"vmf::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: \"vmf::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: \"vmf::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: \"vmf::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: \"vmf::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: \"vmf::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: \"vmf::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: \"vmf::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: \"vmf::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: \"vmf::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: \"vmf::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: \"vmf::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: \"vmf::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(mutateTestCase(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); - } -} -} diff --git a/Radamsa/vmf/src/modules/CMakeLists.txt b/Radamsa/vmf/src/modules/CMakeLists.txt index ebd1328..d4fb121 100644 --- a/Radamsa/vmf/src/modules/CMakeLists.txt +++ b/Radamsa/vmf/src/modules/CMakeLists.txt @@ -20,9 +20,37 @@ # 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 + common/mutator/RadamsaRepeatByteMutator.cpp + common/mutator/RadamsaPermuteByteMutator.cpp + 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 + 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 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..4c2ee3a --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaAsciiBadMutator.cpp @@ -0,0 +1,390 @@ +/* ============================================================================= + * 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, 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, int(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, int(textChunkIndices.size() - 1)); + vector& textElems = get>( + chunks[textChunkIndices[chunkIndex]].value + ); + const size_t elemIndex = rand->randBetween(0, int(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 new file mode 100644 index 0000000..05ad426 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaByteMutatorBase.hpp @@ -0,0 +1,294 @@ +/* ============================================================================= + * 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 "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 +{ +/** + * + */ +class RadamsaByteMutatorBase: public RadamsaMutatorBase +{ +public: + 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}; + + 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. + } + + 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, 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); + } + + 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/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 new file mode 100644 index 0000000..cc01b52 --- /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..0cd9c6b --- /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 "RadamsaByteMutatorBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaDecrementByteMutator: public MutatorModule, public RadamsaByteMutatorBase +{ + 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 = VmfRand::getInstance(); +}; +} \ 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/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/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/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 new file mode 100644 index 0000000..56131e9 --- /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}; + 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 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..9d5fe92 --- /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 "RadamsaByteMutatorBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaDropByteMutator: public MutatorModule, public RadamsaByteMutatorBase +{ + 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 = 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/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 new file mode 100644 index 0000000..8ffdd5e --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.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 "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}; + 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 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( + 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{ + 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. + 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..a9da1b2 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaFlipByteMutator.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 RadamsaFlipByteMutator: public MutatorModule, public RadamsaByteMutatorBase +{ + public: + + static Module* build(std::string name); + virtual void init(ConfigInterface& config); + + RadamsaFlipByteMutator(std::string name); + virtual ~RadamsaFlipByteMutator(); + 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/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/RadamsaIncrementByteMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaIncrementByteMutator.cpp new file mode 100644 index 0000000..577b4b8 --- /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..2de3830 --- /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 "RadamsaByteMutatorBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaIncrementByteMutator: public MutatorModule, public RadamsaByteMutatorBase +{ + 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 = 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 new file mode 100644 index 0000000..12e8efe --- /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}; + 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 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..43d2f7f --- /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 "RadamsaByteMutatorBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaInsertByteMutator: public MutatorModule, public RadamsaByteMutatorBase +{ + 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 = 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/lineMutations.hpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaLineMutatorBase.hpp similarity index 53% rename from Radamsa/vmf/src/modules/common/mutator/lineMutations.hpp rename to Radamsa/vmf/src/modules/common/mutator/RadamsaLineMutatorBase.hpp index 743a600..1703657 100644 --- a/Radamsa/vmf/src/modules/common/mutator/lineMutations.hpp +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaLineMutatorBase.hpp @@ -17,52 +17,18 @@ * * @license GPL-2.0-only * ===========================================================================*/ -#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. mutateTestCase 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 @@ -76,8 +42,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}; @@ -161,9 +131,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}; @@ -186,10 +159,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; } @@ -210,7 +180,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 @@ -287,25 +259,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) && @@ -319,85 +292,147 @@ 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}; + + 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}; - size_t GetRandomLogValue(const size_t maximumValue); + 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 IsBinarish( + const char* const buffer, + const size_t size) +{ + constexpr size_t minimumSize{1u}; - size_t GetRandomN_Bit(const size_t n); + if (size < minimumSize) + throw RuntimeException{"The buffer's minimum size must be greater than or equal to 1", RuntimeException::USAGE_ERROR}; -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); + constexpr size_t binarishPeekSize{8u}; - bool Rad_LineInsElsewhere(const size_t index); + 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}; - bool Rad_LineReplaceElsewhere(const size_t index); + return nBitValue; + } }; } 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..7b0018d --- /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, int(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, int(interestingNums.size() - 1)) + ]; break; + case 7: + newValue = toMutate.value + interestingNums[ + this->rand->randBetween(0, int(interestingNums.size() - 1)) + ]; break; + case 8: { + unsigned int val = interestingNums[ + this->rand->randBetween(0, int(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 new file mode 100644 index 0000000..ba62c36 --- /dev/null +++ b/Radamsa/vmf/src/modules/common/mutator/RadamsaMutatorBase.hpp @@ -0,0 +1,63 @@ +/* ============================================================================= + * 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: +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/RadamsaPermuteByteMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaPermuteByteMutator.cpp new file mode 100644 index 0000000..b90085d --- /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..695fcf7 --- /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 "RadamsaByteMutatorBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaPermuteByteMutator: public MutatorModule, public RadamsaByteMutatorBase +{ + 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 = VmfRand::getInstance(); +}; +} \ 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/RadamsaRandomizeByteMutator.cpp b/Radamsa/vmf/src/modules/common/mutator/RadamsaRandomizeByteMutator.cpp new file mode 100644 index 0000000..2f7f111 --- /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..bd84588 --- /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 "RadamsaByteMutatorBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaRandomizeByteMutator: public MutatorModule, public RadamsaByteMutatorBase +{ + 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 = 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 new file mode 100644 index 0000000..f44fad7 --- /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{GetRandomRepetitionLength(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..25ffcdc --- /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 "RadamsaByteMutatorBase.hpp" +#include "VmfRand.hpp" + +namespace vmf +{ +/** + * + */ +class RadamsaRepeatByteMutator: public MutatorModule, public RadamsaByteMutatorBase +{ + 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 = VmfRand::getInstance(); +}; +} \ No newline at end of file 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/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/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/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/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/Radamsa/vmf/src/modules/common/mutator/byteMutations.cpp b/Radamsa/vmf/src/modules/common/mutator/byteMutations.cpp deleted file mode 100644 index 299d26a..0000000 --- a/Radamsa/vmf/src/modules/common/mutator/byteMutations.cpp +++ /dev/null @@ -1,466 +0,0 @@ -/* ============================================================================= - * 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 - * ===========================================================================*/ -/***** - * 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())); -} 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 96c78a6..0000000 --- a/Radamsa/vmf/src/modules/common/mutator/byteMutations.hpp +++ /dev/null @@ -1,131 +0,0 @@ -/* ============================================================================= - * 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 - -// 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. mutateTestCase 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 c9cc8ee..0000000 --- a/Radamsa/vmf/src/modules/common/mutator/lineMutations.cpp +++ /dev/null @@ -1,920 +0,0 @@ -/* ============================================================================= - * 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 - * ===========================================================================*/ -/***** - * 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!!!"; - } - } -} 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 cd750fb..0000000 --- a/Radamsa/vmf/src/modules/common/mutator/mutationBase.hpp +++ /dev/null @@ -1,76 +0,0 @@ -/* ============================================================================= - * 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 - -// C++ Includes -#include -#include -#include -#include - -namespace vmf::radamsa::mutations -{ -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 - { - constexpr size_t MINIMUM_UPPER_LIMIT{0x2u}; - constexpr size_t MAXIMUM_UPPER_LIMIT{0x20000u}; - - size_t randomStop{GetRandomValueWithinBounds(0u, MINIMUM_UPPER_LIMIT)}; - size_t randomUpperLimit{MINIMUM_UPPER_LIMIT}; - - while(randomStop != 0u) - { - if(randomUpperLimit == MAXIMUM_UPPER_LIMIT) - break; - - randomUpperLimit <<= 1u; - randomStop = GetRandomValueWithinBounds(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. - } - - std::default_random_engine& RANDOM_NUMBER_GENERATOR_; - -private: -}; -} 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 8cddf6f..0000000 --- a/Radamsa/vmf/src/modules/common/mutator/radamsaMutator.cpp +++ /dev/null @@ -1,202 +0,0 @@ -/* ============================================================================= - * 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 - * ===========================================================================*/ -/***** - * 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) -{ - 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); - if (newEntry == nullptr) - throw RuntimeException("RadamsaMutator mutate called with numm new 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; -} diff --git a/dockerfiles/Dockerfile b/dockerfiles/Dockerfile new file mode 100644 index 0000000..6c78486 --- /dev/null +++ b/dockerfiles/Dockerfile @@ -0,0 +1,77 @@ +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 \ + doxygen \ + libcurl4-openssl-dev \ + llvm \ + llvm-dev \ + lld \ + python3-dev \ + python3-pip \ + python3-setuptools \ + build-essential \ + cmake \ + libyaml-cpp-dev + +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 +# TODO temp fix until we update for 5.0.0 +RUN set -ex \ + && cd /usr/local/src \ + && git clone https://github.com/draperlaboratory/vadermodularfuzzer.git VaderModularFuzzer\ + && cd VaderModularFuzzer \ + && mkdir -p build \ + && cd build \ + && cmake .. \ + && make -j \ + && make install \ + && set +ex + +# Copy VmfExperimental +COPY . /usr/local/src/VmfExperimental + +RUN set -ex \ + && cd /usr/local/src/VmfExperimental \ + && mkdir build \ + && cd build \ + && 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/src/ \ + && cp VmfExperimental/test/config/experimentalModules.yaml VaderModularFuzzer/build/vmf_install/test/config/experimentalModules.yaml \ + && set +ex + +# 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" ] 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/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 diff --git a/test/unittest/CMakeLists.txt b/test/unittest/CMakeLists.txt new file mode 100644 index 0000000..ccedd9a --- /dev/null +++ b/test/unittest/CMakeLists.txt @@ -0,0 +1,101 @@ +#=============================================================================== +# 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 + ${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 + ../../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 + ../../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}) + +set_target_properties(VmfTest PROPERTIES LINKER_LANGUAGE CXX) + +target_include_directories(VmfTest PUBLIC + ${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 + ${CMAKE_INSTALL_PREFIX}/lib + ${CMAKE_INSTALL_PREFIX}/plugins + ${CMAKE_INSTALL_PREFIX}/../lib +) + +target_link_libraries(VmfTest + PUBLIC + gtest + gtest_main + VMFFramework + CoreModules + Threads::Threads + Radamsa + yaml-cpp +) +gtest_discover_tests(VmfTest)