From 07a67f6d481d7096a3fd9fee78f22171e6ab8989 Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Wed, 8 Jan 2025 10:14:08 -0500 Subject: [PATCH 1/3] Add an initial cjson fuzz test Signed-off-by: Geoff Hutchison --- tests/io/CMakeLists.txt | 15 +++++++++++++++ tests/io/fuzztest.cpp | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 tests/io/fuzztest.cpp diff --git a/tests/io/CMakeLists.txt b/tests/io/CMakeLists.txt index 056776be13..f53da8aecf 100644 --- a/tests/io/CMakeLists.txt +++ b/tests/io/CMakeLists.txt @@ -51,3 +51,18 @@ foreach(TestName ${tests}) add_test(NAME "Io-${TestName}" COMMAND AvogadroIOTests "--gtest_filter=${TestName}Test.*") endforeach() + +option(ENABLE_FUZZ "Enable fuzz testing." OFF) + +if(ENABLE_FUZZ) + add_definitions(-DFUZZTEST_FUZZING_MODE=on) + # fuzztest uses abseil-cpp + set(CMAKE_CXX_STANDARD 17) + set(CMAKE_CXX_VISIBILITY_PRESET default) + add_subdirectory(fuzztest) + + fuzztest_setup_fuzzing_flags() + add_executable(AvogadroFuzzTests fuzztest.cpp) + target_link_libraries(AvogadroFuzzTests PRIVATE Avogadro::IO) + link_fuzztest(AvogadroFuzzTests) +endif() diff --git a/tests/io/fuzztest.cpp b/tests/io/fuzztest.cpp new file mode 100644 index 0000000000..c0cef99361 --- /dev/null +++ b/tests/io/fuzztest.cpp @@ -0,0 +1,32 @@ +/****************************************************************************** + This source file is part of the Avogadro project. + This source code is released under the 3-Clause BSD License, (see "LICENSE"). +******************************************************************************/ + +#include "fuzztest/fuzztest.h" +#include "iotests.h" + +#include + +#include +#include +#include + +#include + +using Avogadro::Core::Molecule; +using Avogadro::Io::CjsonFormat; + +static const std::string cjsonDir = std::string(AVOGADRO_DATA) + "/data/cjson/"; + +void readCjson(const std::string& data) +{ + CjsonFormat cjson; + Molecule molecule; + bool success = cjson.readString(data, molecule); + EXPECT_TRUE(success); + EXPECT_EQ(cjson.error(), ""); +} + +FUZZ_TEST(AvogadroFuzzTests, readCjson) + .WithSeeds(fuzztest::ReadFilesFromDirectory(cjsonDir)); From 820d90c98cf91c1ee2027055d5eb5f18eca8ba40 Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Mon, 20 Jan 2025 15:07:09 -0500 Subject: [PATCH 2/3] Switch back to libFuzzer style Signed-off-by: Geoff Hutchison --- tests/io/CMakeLists.txt | 16 ++++++---------- tests/io/fuzztest.cpp | 23 ++++++----------------- 2 files changed, 12 insertions(+), 27 deletions(-) diff --git a/tests/io/CMakeLists.txt b/tests/io/CMakeLists.txt index f53da8aecf..26ec31528c 100644 --- a/tests/io/CMakeLists.txt +++ b/tests/io/CMakeLists.txt @@ -54,15 +54,11 @@ endforeach() option(ENABLE_FUZZ "Enable fuzz testing." OFF) -if(ENABLE_FUZZ) - add_definitions(-DFUZZTEST_FUZZING_MODE=on) - # fuzztest uses abseil-cpp - set(CMAKE_CXX_STANDARD 17) - set(CMAKE_CXX_VISIBILITY_PRESET default) - add_subdirectory(fuzztest) +if(ENABLE_FUZZ OR DEFINED ENV{LIB_FUZZING_ENGINE}) + add_executable(fuzz_cjson fuzztest.cpp) + target_compile_options(fuzz_cjson PRIVATE -g -fsanitize=fuzzer) + target_link_libraries(fuzz_cjson PRIVATE Avogadro::IO $ENV{LIB_FUZZING_ENGINE}) - fuzztest_setup_fuzzing_flags() - add_executable(AvogadroFuzzTests fuzztest.cpp) - target_link_libraries(AvogadroFuzzTests PRIVATE Avogadro::IO) - link_fuzztest(AvogadroFuzzTests) + # todo use a modular input format + # target_compile_definitions(fuzz_cjson PRIVATE -DFUZZ_INPUT_FORMAT="cjson") endif() diff --git a/tests/io/fuzztest.cpp b/tests/io/fuzztest.cpp index c0cef99361..ce1267315a 100644 --- a/tests/io/fuzztest.cpp +++ b/tests/io/fuzztest.cpp @@ -3,30 +3,19 @@ This source code is released under the 3-Clause BSD License, (see "LICENSE"). ******************************************************************************/ -#include "fuzztest/fuzztest.h" -#include "iotests.h" - -#include - -#include #include -#include - #include using Avogadro::Core::Molecule; using Avogadro::Io::CjsonFormat; -static const std::string cjsonDir = std::string(AVOGADRO_DATA) + "/data/cjson/"; - -void readCjson(const std::string& data) +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { + std::string input(reinterpret_cast(Data), Size); + CjsonFormat cjson; Molecule molecule; - bool success = cjson.readString(data, molecule); - EXPECT_TRUE(success); - EXPECT_EQ(cjson.error(), ""); -} + bool success = cjson.readString(input, molecule); -FUZZ_TEST(AvogadroFuzzTests, readCjson) - .WithSeeds(fuzztest::ReadFilesFromDirectory(cjsonDir)); + return 0; +} From 55060be9d1c78b8651b8d109b9a51476809cb39a Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Mon, 20 Jan 2025 15:30:43 -0500 Subject: [PATCH 3/3] Modular fuzz testing for major formats cjson, cml, xyz, sdf, pdb Signed-off-by: Geoff Hutchison --- tests/io/CMakeLists.txt | 27 ++++++++++++++++++++------- tests/io/fuzztest.cpp | 10 ++++++---- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/tests/io/CMakeLists.txt b/tests/io/CMakeLists.txt index 26ec31528c..b097cc34c6 100644 --- a/tests/io/CMakeLists.txt +++ b/tests/io/CMakeLists.txt @@ -52,13 +52,26 @@ foreach(TestName ${tests}) COMMAND AvogadroIOTests "--gtest_filter=${TestName}Test.*") endforeach() -option(ENABLE_FUZZ "Enable fuzz testing." OFF) +if (DEFINED ENV{LIB_FUZZING_ENGINE}) + option(ENABLE_FUZZ "Enable fuzz testing." ON) +else() + option(ENABLE_FUZZ "Enable fuzz testing." OFF) +endif() if(ENABLE_FUZZ OR DEFINED ENV{LIB_FUZZING_ENGINE}) - add_executable(fuzz_cjson fuzztest.cpp) - target_compile_options(fuzz_cjson PRIVATE -g -fsanitize=fuzzer) - target_link_libraries(fuzz_cjson PRIVATE Avogadro::IO $ENV{LIB_FUZZING_ENGINE}) - - # todo use a modular input format - # target_compile_definitions(fuzz_cjson PRIVATE -DFUZZ_INPUT_FORMAT="cjson") + # todo - make this into a loop for multiple formats + set(fuzz + cjson + cml + sdf + pdb + xyz + ) + foreach(fuzzName ${fuzz}) + add_executable(fuzz_${fuzzName} fuzztest.cpp) + target_compile_definitions(fuzz_${fuzzName} PRIVATE -DFUZZ_INPUT_FORMAT="${fuzzName}") + target_compile_options(fuzz_${fuzzName} PRIVATE -g -fsanitize=fuzzer) + target_link_options(fuzz_${fuzzName} PRIVATE -fsanitize=fuzzer) + target_link_libraries(fuzz_${fuzzName} PRIVATE Avogadro::IO $ENV{LIB_FUZZING_ENGINE}) + endforeach() endif() diff --git a/tests/io/fuzztest.cpp b/tests/io/fuzztest.cpp index ce1267315a..beee886d76 100644 --- a/tests/io/fuzztest.cpp +++ b/tests/io/fuzztest.cpp @@ -4,18 +4,20 @@ ******************************************************************************/ #include -#include +#include +#include using Avogadro::Core::Molecule; -using Avogadro::Io::CjsonFormat; +using Avogadro::Io::FileFormatManager; +// FUZZ_INPUT_FORMAT is defined in the build system +// e.g., "cjson", "sdf", "xyz", etc. extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { std::string input(reinterpret_cast(Data), Size); - CjsonFormat cjson; Molecule molecule; - bool success = cjson.readString(input, molecule); + FileFormatManager::instance().readString(molecule, input, FUZZ_INPUT_FORMAT); return 0; }