diff --git a/.github/workflows/ci-fuzztest.yml b/.github/workflows/ci-fuzztest.yml index 80c443eddf..03c57a3dbd 100644 --- a/.github/workflows/ci-fuzztest.yml +++ b/.github/workflows/ci-fuzztest.yml @@ -35,10 +35,6 @@ jobs: codec-dav1d: "LOCAL" libxml2: "LOCAL" libyuv: ${{ matrix.libyuv }} - - name: Build fuzztest - if: steps.setup.outputs.ext-cache-hit != 'true' - working-directory: ./ext - run: bash -e fuzztest.cmd - name: Prepare libavif (cmake) run: > @@ -52,8 +48,7 @@ jobs: -DAVIF_ENABLE_EXPERIMENTAL_YCGCO_R=ON -DAVIF_ENABLE_EXPERIMENTAL_MINI=ON -DAVIF_ENABLE_EXPERIMENTAL_SAMPLE_TRANSFORM=ON - -DAVIF_ENABLE_FUZZTEST=ON - -DAVIF_LOCAL_FUZZTEST=ON + -DAVIF_FUZZTEST=LOCAL -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DAVIF_ENABLE_WERROR=ON - name: Build libavif (ninja) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ff455775d..f22b4089be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -120,13 +120,8 @@ option( "Build tests that compare encoding outputs to golden files. Needs AVIF_BUILD_APPS=ON and AVIF_BUILD_TESTS=ON, and depends on MP4box which can be built with ext/mp4box.sh" OFF ) -option(AVIF_ENABLE_FUZZTEST "Build avif fuzztest targets. Requires Google FuzzTest. Has no effect unless AVIF_BUILD_TESTS is ON." - OFF -) -option( - AVIF_LOCAL_FUZZTEST - "Build the Google FuzzTest framework by providing your own copy of the repo in ext/fuzztest (see Local Builds in README). CMake must be at least 3.25." - OFF +set_local_or_system_option( + "AVIF_FUZZTEST" OFF "Build the Google FuzzTest framework. Only OFF and LOCAL are supported. CMake must be at least 3.25." ) # Whether the libavif library uses c++ indirectly (e.g. through linking to libyuv). @@ -556,7 +551,7 @@ if(NOT AVIF_CODEC_AOM_ENABLED message(WARNING "libavif: No decoding library is enabled.") endif() -if(AVIF_LIB_USE_CXX OR AVIF_BUILD_APPS OR (AVIF_BUILD_TESTS AND (AVIF_ENABLE_FUZZTEST OR AVIF_GTEST))) +if(AVIF_LIB_USE_CXX OR AVIF_BUILD_APPS OR (AVIF_BUILD_TESTS AND (AVIF_FUZZTEST OR AVIF_GTEST))) enable_language(CXX) if(AVIF_ENABLE_NODISCARD) # [[nodiscard]] requires C++17. @@ -633,7 +628,7 @@ if(NOT SKIP_INSTALL_ALL) include(GNUInstallDirs) endif() -if(AVIF_BUILD_APPS OR (AVIF_BUILD_TESTS AND (AVIF_ENABLE_FUZZTEST OR AVIF_GTEST))) +if(AVIF_BUILD_APPS OR (AVIF_BUILD_TESTS AND (AVIF_FUZZTEST OR AVIF_GTEST))) if(AVIF_ZLIBPNG STREQUAL "OFF") message(FATAL_ERROR "libavif: AVIF_ZLIBPNG cannot be OFF when AVIF_BUILD_APPS or AVIF_BUILD_TESTS is ON") elseif(AVIF_ZLIBPNG STREQUAL "SYSTEM") diff --git a/cmake/Modules/LocalFuzztest.cmake b/cmake/Modules/LocalFuzztest.cmake new file mode 100644 index 0000000000..22b9b80645 --- /dev/null +++ b/cmake/Modules/LocalFuzztest.cmake @@ -0,0 +1,32 @@ +set(AVIF_FUZZTEST_TAG "078ea0871cc96d3a69bad406577f176a4fa14ae9") + +set(FUZZTEST_SOURCE_DIR "${AVIF_SOURCE_DIR}/ext/fuzztest") + +if(EXISTS "${FUZZTEST_SOURCE_DIR}") + message(STATUS "libavif(AVIF_FUZZTEST=LOCAL): folder found at ${FUZZTEST_SOURCE_DIR}") + set(FUZZTEST_BINARY_DIR "${FUZZTEST_SOURCE_DIR}/build.libavif") +else() + message(STATUS "libavif(AVIF_FUZZTEST=LOCAL): compiled library not found at ${LIB_FILENAME}; using FetchContent") + + message(CHECK_START "libavif(AVIF_FUZZTEST=LOCAL): configuring fuzztest") + + set(FUZZTEST_SOURCE_DIR "${FETCHCONTENT_BASE_DIR}/fuzztest-src") + set(FUZZTEST_BINARY_DIR "${FETCHCONTENT_BASE_DIR}/fuzztest-build") + FetchContent_Declare( + fuzztest + GIT_REPOSITORY "https://github.com/google/fuzztest.git" + BINARY_DIR "${FUZZTEST_BINARY_DIR}" + GIT_TAG "${AVIF_FUZZTEST_TAG}" + # Fixes for https://github.com/google/fuzztest/issues/1124 + PATCH_COMMAND + sed -i.bak -e "s/-fsanitize=address//g" cmake/FuzzTestFlagSetup.cmake && sed -i.bak -e "s/-DADDRESS_SANITIZER//g" + cmake/FuzzTestFlagSetup.cmake && + # Fixes for https://github.com/google/fuzztest/issues/1125 + sed -i.bak -e "s/if (IsEnginePlaceholderInput(data))/if (data.size() == 0)/" fuzztest/internal/compatibility_mode.cc + && sed -i.bak -e "s/set(GTEST_HAS_ABSL ON)/set(GTEST_HAS_ABSL OFF)/" cmake/BuildDependencies.cmake + ) + + message(CHECK_PASS "complete") +endif() + +avif_fetchcontent_populate_cmake(fuzztest) diff --git a/ext/fuzztest.cmd b/ext/fuzztest.cmd index b177a057b3..535374f1a3 100755 --- a/ext/fuzztest.cmd +++ b/ext/fuzztest.cmd @@ -15,8 +15,8 @@ git checkout 078ea0871cc96d3a69bad406577f176a4fa14ae9 sed -i 's/-fsanitize=address//g' ./cmake/FuzzTestFlagSetup.cmake sed -i 's/-DADDRESS_SANITIZER//g' ./cmake/FuzzTestFlagSetup.cmake : # Fixes for https://github.com/google/fuzztest/issues/1125 -sed -i 's/if (IsEnginePlaceholderInput(data)) return;/if (data.size() == 0) return;/g' ./fuzztest/internal/compatibility_mode.cc -sed -i 's/set(GTEST_HAS_ABSL ON)/set(GTEST_HAS_ABSL OFF)/g' ./cmake/BuildDependencies.cmake +sed -i 's/if (IsEnginePlaceholderInput(data))/if (data.size() == 0)/' ./fuzztest/internal/compatibility_mode.cc +sed -i 's/set(GTEST_HAS_ABSL ON)/set(GTEST_HAS_ABSL OFF)/' ./cmake/BuildDependencies.cmake : # fuzztest is built by the main CMake project through add_subdirectory as recommended at: : # https://github.com/google/fuzztest/blob/main/doc/quickstart-cmake.md diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ff50ae83b5..97d4673e35 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -43,7 +43,7 @@ foreach(AVIFYUV_MODE limited rgb) # Modes drift and premultiply take more than 2 add_test(NAME avifyuv_${AVIFYUV_MODE} COMMAND avifyuv -m ${AVIFYUV_MODE}) endforeach() -if(AVIF_ENABLE_FUZZTEST OR AVIF_GTEST OR AVIF_BUILD_APPS) +if(AVIF_FUZZTEST OR AVIF_GTEST OR AVIF_BUILD_APPS) add_library(aviftest_helpers OBJECT gtest/aviftest_helpers.cc) target_link_libraries(aviftest_helpers PUBLIC avif_apps avif) target_link_libraries(aviftest_helpers PRIVATE avif_enable_warnings) @@ -170,42 +170,39 @@ endif() ################################################################################ # Experimental FuzzTest support (Linux only) -if(AVIF_ENABLE_FUZZTEST) +if(AVIF_FUZZTEST) # Adds a fuzztest from file TEST_NAME.cc located in the gtest folder. Extra arguments # are considered as extra source files. macro(add_avif_fuzztest TEST_NAME) add_executable(${TEST_NAME} gtest/${TEST_NAME}.cc ${ARGN}) # FuzzTest bundles GoogleTest so no need to link to gtest librairies. - target_link_libraries(${TEST_NAME} PRIVATE avif_fuzztest_helpers aviftest_helpers_internal avif_enable_warnings) + # avif_enable_warnings is not added because it triggers to many warnings in fuzztest. + target_link_libraries(${TEST_NAME} PRIVATE avif_fuzztest_helpers aviftest_helpers_internal) link_fuzztest(${TEST_NAME}) add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME} --stack_limit_kb=512) set_property(TEST ${TEST_NAME} PROPERTY ENVIRONMENT "TEST_DATA_DIRS=${CMAKE_CURRENT_SOURCE_DIR}/data/") endmacro() - if(AVIF_LOCAL_FUZZTEST) - # Run ext/fuzztest.cmd first. - # Recommended top-level CMake options: - # -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DAVIF_CODEC_DAV1D=ON -DAVIF_ENABLE_WERROR=OFF - # Reproducing a failure can be done by setting the environment variable - # FUZZTEST_REPLAY=/path/to/repro_file.test - # and running one of the targets below. - # See https://github.com/google/fuzztest/blob/main/doc/quickstart-cmake.md - # Note: There are compiler warnings in the FuzzTest headers. Add the - # ext/fuzztest subdirectory with the SYSTEM directory property set to - # true so that warnings in its headers are suppressed. - if(CMAKE_VERSION VERSION_LESS 3.25.0) - message(FATAL_ERROR "CMake must be at least 3.25 to pass the SYSTEM argument to add_subdirectory(), bailing out") - endif() - # Add the fuzztest project. Note this may add some tests which may not be built because of EXCLUDE_FROM_ALL and will - # therefore fail. They can be ignored by adding them to CTestCustom.cmake - # See https://gitlab.kitware.com/cmake/cmake/-/issues/20212 - add_subdirectory(${AVIF_SOURCE_DIR}/ext/fuzztest ${AVIF_SOURCE_DIR}/ext/fuzztest/build.libavif EXCLUDE_FROM_ALL SYSTEM) - else() - message( - FATAL_ERROR - "fuzztest: Installed FuzzTest is not supported, please set AVIF_LOCAL_FUZZTEST=ON or AVIF_ENABLE_FUZZTEST=OFF" - ) + # Recommended top-level CMake options: + # -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DAVIF_CODEC_DAV1D=ON -DAVIF_ENABLE_WERROR=OFF + # Reproducing a failure can be done by setting the environment variable + # FUZZTEST_REPLAY=/path/to/repro_file.test + # and running one of the targets below. + # See https://github.com/google/fuzztest/blob/main/doc/quickstart-cmake.md + # Note: There are compiler warnings in the FuzzTest headers. Add the + # ext/fuzztest subdirectory with the SYSTEM directory property set to + # true so that warnings in its headers are suppressed. + if(CMAKE_VERSION VERSION_LESS 3.25.0) + message(FATAL_ERROR "CMake must be at least 3.25 to pass the SYSTEM argument to add_subdirectory(), bailing out") endif() + if(AVIF_FUZZTEST STREQUAL "SYSTEM") + message(FATAL_ERROR "SYSTEM is not supported for AVIF_FUZZTEST") + endif() + # Add the fuzztest project. Note this may add some tests which may not be built because of EXCLUDE_FROM_ALL and will + # therefore fail. They can be ignored by adding them to CTestCustom.cmake + # See https://gitlab.kitware.com/cmake/cmake/-/issues/20212 + include(LocalFuzztest) + fuzztest_setup_fuzzing_flags() # Create a library with avif_fuzztest_helpers.cc to compile it only once. @@ -222,7 +219,7 @@ if(AVIF_ENABLE_FUZZTEST) add_avif_fuzztest(avif_fuzztest_read_image) add_avif_fuzztest(avif_fuzztest_yuvrgb) else() - message(STATUS "FuzzTest targets are disabled because AVIF_ENABLE_FUZZTEST is OFF.") + message(STATUS "FuzzTest targets are disabled because AVIF_FUZZTEST is OFF.") endif() ################################################################################ diff --git a/tests/CTestCustom.cmake b/tests/CTestCustom.cmake index 287348132f..3412b9d070 100644 --- a/tests/CTestCustom.cmake +++ b/tests/CTestCustom.cmake @@ -1,4 +1,4 @@ set(CTEST_CUSTOM_TESTS_IGNORE - # Ignore failing tests brought by `add_subdirectory(${AVIF_SOURCE_DIR}/ext/fuzztest)` when AVIF_ENABLE_FUZZTEST is ON + # Ignore failing tests brought by `add_subdirectory(${AVIF_SOURCE_DIR}/ext/fuzztest)` when AVIF_FUZZTEST is not OFF antlr4_tests_NOT_BUILT ) diff --git a/tests/oss-fuzz/README.md b/tests/oss-fuzz/README.md index 0cce4092c6..24d020ae4e 100644 --- a/tests/oss-fuzz/README.md +++ b/tests/oss-fuzz/README.md @@ -7,7 +7,7 @@ This document provides links and knowledge about fuzzing libavif on oss-fuzz. You need to build with the following CMake flags: ```sh --DAVIF_CODEC_AOM=LOCAL -DAVIF_CODEC_AOM_DECODE=ON -DAVIF_CODEC_AOM_ENCODE=ON -DAVIF_CODEC_DAV1D=LOCAL -DAVIF_LIBYUV=LOCAL -DAVIF_LIBSHARPYUV=LOCAL -DAVIF_BUILD_TESTS=ON -DAVIF_ENABLE_GTEST=ON -DAVIF_GTEST=LOCAL -DAVIF_LOCAL_FUZZTEST=ON -DAVIF_ENABLE_FUZZTEST=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DAVIF_ENABLE_WERROR=OFF +-DAVIF_CODEC_AOM=LOCAL -DAVIF_CODEC_AOM_DECODE=ON -DAVIF_CODEC_AOM_ENCODE=ON -DAVIF_CODEC_DAV1D=LOCAL -DAVIF_LIBYUV=LOCAL -DAVIF_LIBSHARPYUV=LOCAL -DAVIF_BUILD_TESTS=ON -DAVIF_ENABLE_GTEST=ON -DAVIF_GTEST=LOCAL -DAVIF_FUZZTEST=LOCAL -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DAVIF_ENABLE_WERROR=OFF ``` You can then run your tests as normal: diff --git a/tests/oss-fuzz/build.sh b/tests/oss-fuzz/build.sh index eb9c0f56b2..ce3787755f 100755 --- a/tests/oss-fuzz/build.sh +++ b/tests/oss-fuzz/build.sh @@ -71,11 +71,11 @@ cd build EXTRA_CMAKE_FLAGS="" if [[ "$FUZZING_ENGINE" == "libfuzzer" ]]; then CXXFLAGS="${CXXFLAGS} -DFUZZTEST_COMPATIBILITY_MODE" - EXTRA_CMAKE_FLAGS="${EXTRA_CMAKE_FLAGS} -DAVIF_ENABLE_FUZZTEST=ON -DFUZZTEST_COMPATIBILITY_MODE=libfuzzer" + EXTRA_CMAKE_FLAGS="${EXTRA_CMAKE_FLAGS} -DFUZZTEST_COMPATIBILITY_MODE=libfuzzer" fi cmake .. -G Ninja -DBUILD_SHARED_LIBS=OFF -DAVIF_CODEC_AOM=LOCAL -DAVIF_CODEC_DAV1D=LOCAL \ -DAVIF_CODEC_AOM_DECODE=ON -DAVIF_CODEC_AOM_ENCODE=ON \ - -DAVIF_LOCAL_FUZZTEST=ON \ + -DAVIF_FUZZTEST=LOCAL \ -DAVIF_JPEG=LOCAL -DAVIF_LIBSHARPYUV=LOCAL \ -DAVIF_LIBYUV=LOCAL -DAVIF_ZLIBPNG=LOCAL \ -DAVIF_BUILD_TESTS=ON -DAVIF_GTEST=OFF -DAVIF_ENABLE_WERROR=ON \