From 0b9ae71b17c6fe550215019e763e23d4364b830f Mon Sep 17 00:00:00 2001 From: Nathaniel Brough Date: Sat, 9 Dec 2023 17:13:30 -0800 Subject: [PATCH] fuzz: Add fuzz harnesses for string/crc api's --- CMakeLists.txt | 18 ++++++ fuzz/CMakeLists.txt | 16 +++++ fuzz/etl_profile.h | 138 +++++++++++++++++++++++++++++++++++++++++ fuzz/hash_fuzzer.cpp | 42 +++++++++++++ fuzz/string_fuzzer.cpp | 59 ++++++++++++++++++ 5 files changed, 273 insertions(+) create mode 100644 fuzz/CMakeLists.txt create mode 100644 fuzz/etl_profile.h create mode 100644 fuzz/hash_fuzzer.cpp create mode 100644 fuzz/string_fuzzer.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f81b8bbe..2285e5afd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,7 @@ endif() project(etl VERSION ${ETL_VERSION} LANGUAGES CXX) option(BUILD_TESTS "Build unit tests" OFF) +option(BUILD_FUZZ_TESTS "Build fuzz tests" OFF) option(NO_STL "No STL" OFF) # There is a bug on old gcc versions for some targets that causes all system headers # to be implicitly wrapped with 'extern "C"' @@ -80,3 +81,20 @@ if (BUILD_TESTS) enable_testing() add_subdirectory(test) endif() + +if (BUILD_FUZZ_TESTS AND CMAKE_CXX_COMPILER_ID MATCHES "Clang") + # Determine the flags for fuzzing. Use OSS-Fuzz's configuration if available, otherwise fall back to defaults. + if(DEFINED ENV{LIB_FUZZING_ENGINE}) + set(FUZZING_ENGINE $ENV{LIB_FUZZING_ENGINE}) + set(FUZZING_COMPILE_FLAGS "") + set(FUZZING_LINK_FLAGS "${FUZZING_ENGINE}") + else() + # Instrument all source code for fuzzing. + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=fuzzer-no-link,address") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=fuzzer-no-link,address") + set(FUZZING_COMPILE_FLAGS "") + # Link against libfuzzer and adderss sanitizer. + set(FUZZING_LINK_FLAGS "-fsanitize=fuzzer,address") + endif() + add_subdirectory(fuzz) +endif() diff --git a/fuzz/CMakeLists.txt b/fuzz/CMakeLists.txt new file mode 100644 index 000000000..25fda2cde --- /dev/null +++ b/fuzz/CMakeLists.txt @@ -0,0 +1,16 @@ +set(FUZZ_TARGETS + hash_fuzzer + string_fuzzer +) + +foreach(TARGET ${FUZZ_TARGETS}) + add_executable("${TARGET}" "${TARGET}.cpp") + # Apply the determined flags + set_target_properties(${TARGET} PROPERTIES + COMPILE_FLAGS "${FUZZING_COMPILE_FLAGS}" + LINK_FLAGS "${FUZZING_LINK_FLAGS}" + ) + # Link QuantLib and any other necessary libraries + target_link_libraries(${TARGET} PRIVATE etl::etl) + target_sources(${TARGET} PRIVATE etl_profile.h) +endforeach() diff --git a/fuzz/etl_profile.h b/fuzz/etl_profile.h new file mode 100644 index 000000000..079e24ad8 --- /dev/null +++ b/fuzz/etl_profile.h @@ -0,0 +1,138 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 John Wellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_PROFILE_H_INCLUDED +#define ETL_PROFILE_H_INCLUDED + +#define ETL_THROW_EXCEPTIONS +#define ETL_VERBOSE_ERRORS +#define ETL_CHECK_PUSH_POP +#define ETL_ISTRING_REPAIR_ENABLE +#define ETL_IVECTOR_REPAIR_ENABLE +#define ETL_IDEQUE_REPAIR_ENABLE +#define ETL_ICIRCULAR_BUFFER_REPAIR_ENABLE +#define ETL_IN_UNIT_TEST +//#define ETL_DEBUG_COUNT +#define ETL_ARRAY_VIEW_IS_MUTABLE + +#define ETL_MESSAGE_TIMER_USE_ATOMIC_LOCK +#define ETL_CALLBACK_TIMER_USE_ATOMIC_LOCK + +#define ETL_POLYMORPHIC_RANDOM + +#define ETL_POLYMORPHIC_BITSET +#define ETL_POLYMORPHIC_DEQUE +#define ETL_POLYMORPHIC_FLAT_MAP +#define ETL_POLYMORPHIC_FLAT_MULTIMAP +#define ETL_POLYMORPHIC_FLAT_SET +#define ETL_POLYMORPHIC_FLAT_MULTISET +#define ETL_POLYMORPHIC_FORWARD_LIST +#define ETL_POLYMORPHIC_LIST +#define ETL_POLYMORPHIC_MAP +#define ETL_POLYMORPHIC_MULTIMAP +#define ETL_POLYMORPHIC_SET +#define ETL_POLYMORPHIC_MULTISET +#define ETL_POLYMORPHIC_QUEUE +#define ETL_POLYMORPHIC_STACK +#define ETL_POLYMORPHIC_REFERENCE_FLAT_MAP +#define ETL_POLYMORPHIC_REFERENCE_FLAT_MULTIMAP +#define ETL_POLYMORPHIC_REFERENCE_FLAT_SET +#define ETL_POLYMORPHIC_REFERENCE_FLAT_MULTISET +#define ETL_POLYMORPHIC_UNORDERED_MAP +#define ETL_POLYMORPHIC_UNORDERED_MULTIMAP +#define ETL_POLYMORPHIC_UNORDERED_SET +#define ETL_POLYMORPHIC_UNORDERED_MULTISET +#define ETL_POLYMORPHIC_STRINGS +#define ETL_POLYMORPHIC_POOL +#define ETL_POLYMORPHIC_VECTOR +#define ETL_POLYMORPHIC_INDIRECT_VECTOR + +#if defined(ETL_FORCE_TEST_CPP03_IMPLEMENTATION) + #define ETL_FUNCTION_FORCE_CPP03_IMPLEMENTATION + #define ETL_PRIORITY_QUEUE_FORCE_CPP03_IMPLEMENTATION + #define ETL_QUEUE_ATOMIC_FORCE_CPP03_IMPLEMENTATION + #define ETL_VARIANT_FORCE_CPP03_IMPLEMENTATION + #define ETL_VECTOR_FORCE_CPP03_IMPLEMENTATION + #define ETL_QUEUE_FORCE_CPP03_IMPLEMENTATION + #define ETL_QUEUE_MPMC_MUTEX_FORCE_CPP03_IMPLEMENTATION + #define ETL_QUEUE_ISR_FORCE_CPP03_IMPLEMENTATION + #define ETL_QUEUE_LOCKED_FORCE_CPP03_IMPLEMENTATION + #define ETL_OPTIONAL_FORCE_CPP03_IMPLEMENTATION + #define ETL_LARGEST_TYPE_FORCE_CPP03_IMPLEMENTATION + #define ETL_TYPE_SELECT_FORCE_CPP03_IMPLEMENTATION + #define ETL_UNINITIALIZED_BUFFER_FORCE_CPP03_IMPLEMENTATION + #define ETL_CRC_FORCE_CPP03_IMPLEMENTATION + #define ETL_MEM_CAST_FORCE_CPP03_IMPLEMENTATION + #define ETL_OBSERVER_FORCE_CPP03_IMPLEMENTATION + #define ETL_MESSAGE_PACKET_FORCE_CPP03_IMPLEMENTATION + #define ETL_OBSERVER_FORCE_CPP03_IMPLEMENTATION + #define ETL_MESSAGE_ROUTER_FORCE_CPP03_IMPLEMENTATION + #define ETL_FSM_FORCE_CPP03_IMPLEMENTATION + #define ETL_DELEGATE_FORCE_CPP03_IMPLEMENTATION + #define ETL_SINGLETON_FORCE_CPP03_IMPLEMENTATION + #define ETL_BYTE_FORCE_CPP03_IMPLEMENTATION + #define ETL_LIST_FORCE_CPP03_IMPLEMENTATION + #define ETL_FORWARD_LIST_FORCE_CPP03_IMPLEMENTATION + #define ETL_FLAT_SET_FORCE_CPP03_IMPLEMENTATION + #define ETL_FLAT_MULTISET_FORCE_CPP03_IMPLEMENTATION +#endif + +#if defined(ETL_FORCE_TEST_CPP11) + #define ETL_OVERLOAD_FORCE_CPP11 + #define ETL_VARIANT_FORCE_CPP11 +#endif + +#include "../include/etl/profiles/determine_compiler_language_support.h" +#include "../include/etl/profiles/determine_compiler_version.h" +#include "../include/etl/profiles/determine_development_os.h" + +//#if ETL_CPP17_NOT_SUPPORTED +// #error THE UNIT TESTS REQUIRE C++17 SUPPORT +//#endif + +#if defined(ETL_COMPILER_GCC) + #if (ETL_COMPILER_VERSION < 8) + #define ETL_TEMPLATE_DEDUCTION_GUIDE_TESTS_DISABLED + #endif +#endif + +#if defined(ETL_DEVELOPMENT_OS_WINDOWS) + #define ETL_TARGET_OS_WINDOWS +#elif defined(ETL_DEVELOPMENT_OS_LINUX) + #define ETL_TARGET_OS_LINUX +#else + #define ETL_TARGET_OS_GENERIC +#endif + +#if !((ETL_CPP20_SUPPORTED && !defined(ETL_NO_STL)) || defined(__BYTE_ORDER__)) + #define ETL_ENDIAN_NATIVE 0 +#endif + +#endif diff --git a/fuzz/hash_fuzzer.cpp b/fuzz/hash_fuzzer.cpp new file mode 100644 index 000000000..5a495075e --- /dev/null +++ b/fuzz/hash_fuzzer.cpp @@ -0,0 +1,42 @@ +#include "etl/checksum.h" +#include "etl/crc.h" +#include +#include +#include +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + FuzzedDataProvider fdp(data, size); + const size_t kMaxBufferSize = 1024; + // ---- Checksums ---- + std::vector buffer = fdp.ConsumeBytes( + fdp.ConsumeIntegralInRange(0, kMaxBufferSize)); + uint8_t sum = etl::checksum(buffer.begin(), buffer.end()); + + etl::checksum checksum_calculator; + + for (size_t i = 0UL; i < buffer.size(); ++i) { + checksum_calculator.add(buffer[i]); + } + + uint8_t loop_sum = checksum_calculator; + assert(sum == loop_sum); + + // ---- CRC ---- + // Get new data for new algorithm. + buffer = fdp.ConsumeBytes( + fdp.ConsumeIntegralInRange(0, kMaxBufferSize)); + + uint8_t crc = etl::crc8_ccitt(buffer.begin(), buffer.end()); + etl::crc8_ccitt crc_calculator; + + for (size_t i = 0UL; i < buffer.size(); ++i) { + crc_calculator.add(buffer[i]); + } + + uint8_t loop_crc = crc_calculator; + assert(crc == loop_crc); + + return 0; +} diff --git a/fuzz/string_fuzzer.cpp b/fuzz/string_fuzzer.cpp new file mode 100644 index 000000000..d7183b9a3 --- /dev/null +++ b/fuzz/string_fuzzer.cpp @@ -0,0 +1,59 @@ +#include "etl/string.h" +#include "etl/to_arithmetic.h" +#include +#include +#include +#include +#include + +template void fuzzed_convert_integral(FuzzedDataProvider *fdp) { + assert(fdp != nullptr); + std::string s = fdp->ConsumeRandomLengthString(); + etl::string_view etl_string(s.c_str(), s.size()); + + etl::radix::value_type radix = fdp->PickValueInArray({ + etl::radix::binary, + etl::radix::octal, + etl::radix::decimal, + etl::radix::hex + }); + + auto result = etl::to_arithmetic(etl_string, radix); + if (result.has_value()) { + volatile T value = result.value(); + (void)value; + } +} + +template void fuzzed_convert_float(FuzzedDataProvider *fdp) { + assert(fdp != nullptr); + std::string s = fdp->ConsumeRandomLengthString(); + etl::string_view etl_string(s.c_str(), s.size()); + + auto result = etl::to_arithmetic(etl_string); + if (result.has_value()) { + volatile T value = result.value(); + (void)value; + } +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + FuzzedDataProvider fdp(data, size); + // Unsigned. + fuzzed_convert_integral(&fdp); + fuzzed_convert_integral(&fdp); + fuzzed_convert_integral(&fdp); + fuzzed_convert_integral(&fdp); + + // Signed. + fuzzed_convert_integral(&fdp); + fuzzed_convert_integral(&fdp); + fuzzed_convert_integral(&fdp); + fuzzed_convert_integral(&fdp); + + // Floating. + fuzzed_convert_float(&fdp); + fuzzed_convert_float(&fdp); + fuzzed_convert_float(&fdp); + return 0; +}