From 8535a7963c71eaa4c49f8b9f4f51e17e37d0f367 Mon Sep 17 00:00:00 2001 From: "Leslie P. Polzer" Date: Thu, 15 Jan 2026 10:28:53 +0000 Subject: [PATCH] Tests/Fuzzing: Add CMake_BUILD_FUZZING option and build infrastructure Add infrastructure for building fuzz testing targets with libFuzzer or other fuzzing engines (e.g., OSS-Fuzz's LIB_FUZZING_ENGINE). Features: - CMake_BUILD_FUZZING option in root CMakeLists.txt - Fuzzing/CMakeLists.txt with add_fuzzer() macro - Support for libFuzzer and external fuzzing engines - Documentation in Tests/Fuzzing/README.rst The infrastructure is opt-in and requires a compatible fuzzing engine. If CMake_BUILD_FUZZING is enabled but no engine is found, configuration fails with a clear error message. See Tests/Fuzzing/README.rst for build instructions. --- CMakeLists.txt | 3 + Tests/CMakeLists.txt | 5 + Tests/Fuzzing/CMakeLists.txt | 54 +++++++++ Tests/Fuzzing/README.rst | 55 ++++++++- Tests/Fuzzing/corpus/README.rst | 26 +++++ Tests/Fuzzing/corpus/archive/simple.tar | Bin 0 -> 10240 bytes Tests/Fuzzing/corpus/archive/simple.tar.gz | Bin 0 -> 144 bytes Tests/Fuzzing/corpus/archive/simple.zip | Bin 0 -> 192 bytes Tests/Fuzzing/corpus/archive/with_dir.tar | Bin 0 -> 10240 bytes Tests/Fuzzing/corpus/depfile/multiline.d | 4 + Tests/Fuzzing/corpus/depfile/simple.d | 1 + Tests/Fuzzing/corpus/depfile/spaces.d | 1 + Tests/Fuzzing/corpus/elf/generate.py | 109 ++++++++++++++++++ Tests/Fuzzing/corpus/elf/minimal32.elf | Bin 0 -> 60 bytes Tests/Fuzzing/corpus/elf/minimal64.elf | Bin 0 -> 72 bytes Tests/Fuzzing/corpus/expr/hex.txt | 1 + Tests/Fuzzing/corpus/expr/not.txt | 1 + Tests/Fuzzing/corpus/expr/parens.txt | 1 + Tests/Fuzzing/corpus/expr/precedence.txt | 1 + Tests/Fuzzing/corpus/expr/shift.txt | 1 + Tests/Fuzzing/corpus/expr/simple.txt | 1 + Tests/Fuzzing/corpus/filelock/custom_name.bin | Bin 0 -> 13 bytes Tests/Fuzzing/corpus/filelock/mode0.bin | Bin 0 -> 2 bytes Tests/Fuzzing/corpus/filelock/mode1.bin | Bin 0 -> 2 bytes Tests/Fuzzing/corpus/filelock/mode2.bin | Bin 0 -> 2 bytes Tests/Fuzzing/corpus/filelock/mode3.bin | Bin 0 -> 2 bytes Tests/Fuzzing/corpus/filelock/symlink.bin | Bin 0 -> 2 bytes Tests/Fuzzing/corpus/filelock/timeout.bin | Bin 0 -> 2 bytes Tests/Fuzzing/corpus/genex/basic.txt | 1 + Tests/Fuzzing/corpus/genex/complex.txt | 1 + Tests/Fuzzing/corpus/genex/interface.txt | 1 + Tests/Fuzzing/corpus/genex/nested.txt | 1 + Tests/Fuzzing/corpus/genex/target.txt | 1 + Tests/Fuzzing/corpus/json/nested.json | 1 + Tests/Fuzzing/corpus/json/preset.json | 10 ++ Tests/Fuzzing/corpus/json/types.json | 9 ++ Tests/Fuzzing/corpus/listfile/basic.txt | 3 + Tests/Fuzzing/corpus/listfile/bracket.txt | 2 + Tests/Fuzzing/corpus/listfile/complex.txt | 29 +++++ Tests/Fuzzing/corpus/path/dotdot.txt | 1 + Tests/Fuzzing/corpus/path/relative.txt | 1 + Tests/Fuzzing/corpus/path/unix.txt | 1 + Tests/Fuzzing/corpus/path/windows.txt | 1 + Tests/Fuzzing/corpus/pkgconfig/deps.pc | 5 + Tests/Fuzzing/corpus/pkgconfig/simple.pc | 9 ++ Tests/Fuzzing/corpus/script/cmake_path.cmake | 20 ++++ .../corpus/script/complex_string.cmake | 14 +++ .../corpus/script/configure_file.cmake | 7 ++ .../Fuzzing/corpus/script/control_flow.cmake | 12 ++ .../corpus/script/execute_process.cmake | 10 ++ Tests/Fuzzing/corpus/script/file_ops.cmake | 4 + Tests/Fuzzing/corpus/script/function.cmake | 7 ++ Tests/Fuzzing/corpus/script/list_ops.cmake | 17 +++ Tests/Fuzzing/corpus/script/math_ops.cmake | 3 + Tests/Fuzzing/corpus/script/string_ops.cmake | 6 + Tests/Fuzzing/corpus/script/variables.cmake | 5 + Tests/Fuzzing/corpus/string/cmake_var.txt | 1 + Tests/Fuzzing/corpus/string/list.txt | 1 + Tests/Fuzzing/corpus/string/quoted.txt | 1 + Tests/Fuzzing/corpus/version/long.txt | 1 + Tests/Fuzzing/corpus/version/semver.txt | 1 + Tests/Fuzzing/corpus/version/simple.txt | 1 + Tests/Fuzzing/corpus/version/tweak.txt | 1 + Tests/Fuzzing/xml_parser.dict | 75 ++++++++++++ Tests/README.rst | 6 + 65 files changed, 528 insertions(+), 6 deletions(-) create mode 100644 Tests/Fuzzing/CMakeLists.txt create mode 100644 Tests/Fuzzing/corpus/README.rst create mode 100644 Tests/Fuzzing/corpus/archive/simple.tar create mode 100644 Tests/Fuzzing/corpus/archive/simple.tar.gz create mode 100644 Tests/Fuzzing/corpus/archive/simple.zip create mode 100644 Tests/Fuzzing/corpus/archive/with_dir.tar create mode 100644 Tests/Fuzzing/corpus/depfile/multiline.d create mode 100644 Tests/Fuzzing/corpus/depfile/simple.d create mode 100644 Tests/Fuzzing/corpus/depfile/spaces.d create mode 100755 Tests/Fuzzing/corpus/elf/generate.py create mode 100755 Tests/Fuzzing/corpus/elf/minimal32.elf create mode 100755 Tests/Fuzzing/corpus/elf/minimal64.elf create mode 100644 Tests/Fuzzing/corpus/expr/hex.txt create mode 100644 Tests/Fuzzing/corpus/expr/not.txt create mode 100644 Tests/Fuzzing/corpus/expr/parens.txt create mode 100644 Tests/Fuzzing/corpus/expr/precedence.txt create mode 100644 Tests/Fuzzing/corpus/expr/shift.txt create mode 100644 Tests/Fuzzing/corpus/expr/simple.txt create mode 100644 Tests/Fuzzing/corpus/filelock/custom_name.bin create mode 100644 Tests/Fuzzing/corpus/filelock/mode0.bin create mode 100644 Tests/Fuzzing/corpus/filelock/mode1.bin create mode 100644 Tests/Fuzzing/corpus/filelock/mode2.bin create mode 100644 Tests/Fuzzing/corpus/filelock/mode3.bin create mode 100644 Tests/Fuzzing/corpus/filelock/symlink.bin create mode 100644 Tests/Fuzzing/corpus/filelock/timeout.bin create mode 100644 Tests/Fuzzing/corpus/genex/basic.txt create mode 100644 Tests/Fuzzing/corpus/genex/complex.txt create mode 100644 Tests/Fuzzing/corpus/genex/interface.txt create mode 100644 Tests/Fuzzing/corpus/genex/nested.txt create mode 100644 Tests/Fuzzing/corpus/genex/target.txt create mode 100644 Tests/Fuzzing/corpus/json/nested.json create mode 100644 Tests/Fuzzing/corpus/json/preset.json create mode 100644 Tests/Fuzzing/corpus/json/types.json create mode 100644 Tests/Fuzzing/corpus/listfile/basic.txt create mode 100644 Tests/Fuzzing/corpus/listfile/bracket.txt create mode 100644 Tests/Fuzzing/corpus/listfile/complex.txt create mode 100644 Tests/Fuzzing/corpus/path/dotdot.txt create mode 100644 Tests/Fuzzing/corpus/path/relative.txt create mode 100644 Tests/Fuzzing/corpus/path/unix.txt create mode 100644 Tests/Fuzzing/corpus/path/windows.txt create mode 100644 Tests/Fuzzing/corpus/pkgconfig/deps.pc create mode 100644 Tests/Fuzzing/corpus/pkgconfig/simple.pc create mode 100644 Tests/Fuzzing/corpus/script/cmake_path.cmake create mode 100644 Tests/Fuzzing/corpus/script/complex_string.cmake create mode 100644 Tests/Fuzzing/corpus/script/configure_file.cmake create mode 100644 Tests/Fuzzing/corpus/script/control_flow.cmake create mode 100644 Tests/Fuzzing/corpus/script/execute_process.cmake create mode 100644 Tests/Fuzzing/corpus/script/file_ops.cmake create mode 100644 Tests/Fuzzing/corpus/script/function.cmake create mode 100644 Tests/Fuzzing/corpus/script/list_ops.cmake create mode 100644 Tests/Fuzzing/corpus/script/math_ops.cmake create mode 100644 Tests/Fuzzing/corpus/script/string_ops.cmake create mode 100644 Tests/Fuzzing/corpus/script/variables.cmake create mode 100644 Tests/Fuzzing/corpus/string/cmake_var.txt create mode 100644 Tests/Fuzzing/corpus/string/list.txt create mode 100644 Tests/Fuzzing/corpus/string/quoted.txt create mode 100644 Tests/Fuzzing/corpus/version/long.txt create mode 100644 Tests/Fuzzing/corpus/version/semver.txt create mode 100644 Tests/Fuzzing/corpus/version/simple.txt create mode 100644 Tests/Fuzzing/corpus/version/tweak.txt create mode 100644 Tests/Fuzzing/xml_parser.dict diff --git a/CMakeLists.txt b/CMakeLists.txt index 87a5766fa8..820fae466b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -224,6 +224,9 @@ endif() option(CMake_BUILD_PCH "Compile CMake with precompiled headers" OFF) +option(CMake_BUILD_FUZZING "Build fuzz testing targets" OFF) +mark_as_advanced(CMake_BUILD_FUZZING) + # Check whether to build support for the debugger mode. if(NOT CMake_TEST_EXTERNAL_CMAKE) if(NOT DEFINED CMake_ENABLE_DEBUGGER) diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 61ed91ffb9..f6abcc9d7a 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -80,6 +80,11 @@ endif() configure_file(${CMake_SOURCE_DIR}/Tests/EnforceConfig.cmake.in ${CMake_BINARY_DIR}/Tests/EnforceConfig.cmake @ONLY) +# Fuzzing targets (outside BUILD_TESTING for OSS-Fuzz compatibility) +if(CMake_BUILD_FUZZING AND NOT CMake_TEST_EXTERNAL_CMAKE) + add_subdirectory(Fuzzing) +endif() + # Testing if(BUILD_TESTING) set(CMake_TEST_DEVENV "") diff --git a/Tests/Fuzzing/CMakeLists.txt b/Tests/Fuzzing/CMakeLists.txt new file mode 100644 index 0000000000..7cccbc55a8 --- /dev/null +++ b/Tests/Fuzzing/CMakeLists.txt @@ -0,0 +1,54 @@ +# Fuzzing targets for CMake +# See README.rst for documentation. + +# Determine fuzzing engine +# OSS-Fuzz sets LIB_FUZZING_ENGINE, otherwise use libFuzzer +if(DEFINED ENV{LIB_FUZZING_ENGINE}) + set(FUZZING_ENGINE $ENV{LIB_FUZZING_ENGINE}) + set(FUZZING_ENGINE_FOUND TRUE) +elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + # Check if libFuzzer is available (needs both compile and link flags) + include(CheckCXXSourceCompiles) + set(CMAKE_REQUIRED_FLAGS "-fsanitize=fuzzer") + set(CMAKE_REQUIRED_LINK_OPTIONS "-fsanitize=fuzzer") + check_cxx_source_compiles("extern \"C\" int LLVMFuzzerTestOneInput(const char *data, long size) { return 0; }" HAVE_LIBFUZZER) + unset(CMAKE_REQUIRED_FLAGS) + unset(CMAKE_REQUIRED_LINK_OPTIONS) + if(HAVE_LIBFUZZER) + set(FUZZING_ENGINE "-fsanitize=fuzzer") + set(FUZZING_ENGINE_FOUND TRUE) + endif() +endif() + +if(NOT FUZZING_ENGINE_FOUND) + message(FATAL_ERROR "No fuzzing engine found. CMake_BUILD_FUZZING requires libFuzzer or LIB_FUZZING_ENGINE.") +endif() + +# Common link libraries +set(FUZZER_LINK_LIBS + CMakeLib +) + +# Macro to add a fuzzer target +macro(add_fuzzer name source) + add_executable(${name} ${source}) + target_link_libraries(${name} PRIVATE ${FUZZER_LINK_LIBS}) + + # If using libFuzzer directly, add the flag + if(FUZZING_ENGINE STREQUAL "-fsanitize=fuzzer") + target_compile_options(${name} PRIVATE -fsanitize=fuzzer) + target_link_options(${name} PRIVATE -fsanitize=fuzzer) + else() + # OSS-Fuzz provides engine as a library + target_link_libraries(${name} PRIVATE ${FUZZING_ENGINE}) + endif() + + # Ensure we don't apply clang-tidy to fuzzers + set_property(TARGET ${name} PROPERTY C_CLANG_TIDY "") + set_property(TARGET ${name} PROPERTY CXX_CLANG_TIDY "") +endmacro() + +# Existing fuzzer from OSS-Fuzz integration +add_fuzzer(xml_parser_fuzzer xml_parser_fuzzer.cc) + +message(STATUS "Fuzzing targets enabled with engine: ${FUZZING_ENGINE}") diff --git a/Tests/Fuzzing/README.rst b/Tests/Fuzzing/README.rst index 15dc5f64fb..c61efc9514 100644 --- a/Tests/Fuzzing/README.rst +++ b/Tests/Fuzzing/README.rst @@ -1,8 +1,51 @@ -The fuzzers in this directory are run continuously through OSS-fuzz. -All fuzzers are implemented by way of the `libFuzzer engine`_. +CMake Fuzzing Suite +=================== -The link to the OSS-fuzz integration can be found here: (pending) -All email addresses in the ``project.yaml`` file on OSS-fuzz will have access -to detailed bug reports and will be notified via email if/when bugs are found. +This directory contains fuzz targets for testing CMake with coverage-guided +fuzzing. These fuzzers are integrated with `OSS-Fuzz`_ for continuous fuzzing. -.. _`libFuzzer Engine`: https://llvm.org/docs/LibFuzzer.html +All fuzzers are implemented using the `libFuzzer engine`_. + +.. _`OSS-Fuzz`: https://github.com/google/oss-fuzz +.. _`libFuzzer engine`: https://llvm.org/docs/LibFuzzer.html + +Building Locally +---------------- + +To build the fuzzers locally with Clang and libFuzzer:: + + mkdir build && cd build + cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \ + -DCMake_BUILD_FUZZING=ON \ + -DCMAKE_C_FLAGS="-fsanitize=fuzzer-no-link,address" \ + -DCMAKE_CXX_FLAGS="-fsanitize=fuzzer-no-link,address" \ + .. + make -j$(nproc) + +Seed Corpora +------------ + +Each fuzzer has a corresponding seed corpus in ``corpus//``. + +Dictionaries +------------ + +Fuzzer dictionaries are provided to improve coverage. Each fuzzer has a +corresponding ``.dict`` file with format-specific tokens. + +Security Considerations +----------------------- + +These fuzzers specifically target security-sensitive code paths: + +- **Path traversal**: Archive extraction with ``../`` sequences +- **Symlink attacks**: File handling with symlinks +- **Memory safety**: Buffer handling in parsers +- **Integer overflows**: Size calculations in binary parsers + +Bug Reports +----------- + +Security bugs found by OSS-Fuzz are reported to CMake maintainers via the +OSS-Fuzz security disclosure process. Non-security bugs are filed as public +issues after a 90-day disclosure window. diff --git a/Tests/Fuzzing/corpus/README.rst b/Tests/Fuzzing/corpus/README.rst new file mode 100644 index 0000000000..05fd348aa9 --- /dev/null +++ b/Tests/Fuzzing/corpus/README.rst @@ -0,0 +1,26 @@ +Fuzzing Seed Corpora +==================== + +This directory contains seed corpus files for the CMake fuzz targets. +Each subdirectory corresponds to a specific fuzzer. + +Regenerating Binary Corpus Files +-------------------------------- + +Some corpus files are binary and include generation scripts for reproducibility: + +- ``elf/generate.py`` - Generates minimal ELF headers for cmELFFuzzer + +To regenerate:: + + cd elf && python3 generate.py + +Adding New Corpus Files +----------------------- + +When adding new corpus files: + +1. Keep files minimal - smaller seeds lead to faster fuzzing +2. For binary formats, include a generation script +3. Cover different code paths and edge cases +4. Avoid duplicating coverage between files diff --git a/Tests/Fuzzing/corpus/archive/simple.tar b/Tests/Fuzzing/corpus/archive/simple.tar new file mode 100644 index 0000000000000000000000000000000000000000..b97311799fa9b5182a99518073cf4f877551d958 GIT binary patch literal 10240 zcmeIv!3u*g41nRB_Y{2sNyWC$Glr)@1slP={UUz}>3LCyUC!)vNG zR(srFUsgl_0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#}( F1-|yV7cBq) literal 0 HcmV?d00001 diff --git a/Tests/Fuzzing/corpus/archive/simple.tar.gz b/Tests/Fuzzing/corpus/archive/simple.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..443939e04d22e19f222c1643b6cd1929a92b63ef GIT binary patch literal 144 zcmb2|=HL)>b qYs{kg{rmad^}oA6{rYcUqb9Gue{L)r12WifoBj3bbK(pd3=9CPG(4;T literal 0 HcmV?d00001 diff --git a/Tests/Fuzzing/corpus/archive/simple.zip b/Tests/Fuzzing/corpus/archive/simple.zip new file mode 100644 index 0000000000000000000000000000000000000000..72726f7097f456abea27e407d90186d850d566a7 GIT binary patch literal 192 zcmWIWW@h1H00HLM3DLjUJA`9$x=V1<1p@| z;m|x{43Z}sgD&S%Dno3rPMyzBCu%kBotV(Dr}^mHln$dYGMyju+S<#f`r4i!SWB<` zPs63(rh979atXNW{4)3VJt(DoD}0r|^BTlxi)QLG|2+SayBV$~{{uEP4c`bLfB*sr rAbJflWMqH=W(H;k1P>;Pody6JfjWMqH=CI&kO1P>-km<9lCjscti literal 0 HcmV?d00001 diff --git a/Tests/Fuzzing/corpus/expr/hex.txt b/Tests/Fuzzing/corpus/expr/hex.txt new file mode 100644 index 0000000000..d7960fcec9 --- /dev/null +++ b/Tests/Fuzzing/corpus/expr/hex.txt @@ -0,0 +1 @@ +0xff & 0x0f diff --git a/Tests/Fuzzing/corpus/expr/not.txt b/Tests/Fuzzing/corpus/expr/not.txt new file mode 100644 index 0000000000..9ca2922220 --- /dev/null +++ b/Tests/Fuzzing/corpus/expr/not.txt @@ -0,0 +1 @@ +~0 diff --git a/Tests/Fuzzing/corpus/expr/parens.txt b/Tests/Fuzzing/corpus/expr/parens.txt new file mode 100644 index 0000000000..9f745a4618 --- /dev/null +++ b/Tests/Fuzzing/corpus/expr/parens.txt @@ -0,0 +1 @@ +(1+2)*3 diff --git a/Tests/Fuzzing/corpus/expr/precedence.txt b/Tests/Fuzzing/corpus/expr/precedence.txt new file mode 100644 index 0000000000..fcc49a64ea --- /dev/null +++ b/Tests/Fuzzing/corpus/expr/precedence.txt @@ -0,0 +1 @@ +1+2*3 diff --git a/Tests/Fuzzing/corpus/expr/shift.txt b/Tests/Fuzzing/corpus/expr/shift.txt new file mode 100644 index 0000000000..98f9c139ed --- /dev/null +++ b/Tests/Fuzzing/corpus/expr/shift.txt @@ -0,0 +1 @@ +1 << 4 diff --git a/Tests/Fuzzing/corpus/expr/simple.txt b/Tests/Fuzzing/corpus/expr/simple.txt new file mode 100644 index 0000000000..19f5084127 --- /dev/null +++ b/Tests/Fuzzing/corpus/expr/simple.txt @@ -0,0 +1 @@ +1+2 diff --git a/Tests/Fuzzing/corpus/filelock/custom_name.bin b/Tests/Fuzzing/corpus/filelock/custom_name.bin new file mode 100644 index 0000000000000000000000000000000000000000..dc408a3f78b2f86135d75b6c700d24b5abd8bf04 GIT binary patch literal 13 UcmZQzFG(#fi7zfqOUtYP034zOyZ`_I literal 0 HcmV?d00001 diff --git a/Tests/Fuzzing/corpus/filelock/mode0.bin b/Tests/Fuzzing/corpus/filelock/mode0.bin new file mode 100644 index 0000000000000000000000000000000000000000..09f370e38f498a462e1ca0faa724559b6630c04f GIT binary patch literal 2 JcmZQz0000200961 literal 0 HcmV?d00001 diff --git a/Tests/Fuzzing/corpus/filelock/mode1.bin b/Tests/Fuzzing/corpus/filelock/mode1.bin new file mode 100644 index 0000000000000000000000000000000000000000..35a038769b15c0935bb3cd038f5cc1de7579f128 GIT binary patch literal 2 JcmZQ%0000400IC2 literal 0 HcmV?d00001 diff --git a/Tests/Fuzzing/corpus/filelock/mode2.bin b/Tests/Fuzzing/corpus/filelock/mode2.bin new file mode 100644 index 0000000000000000000000000000000000000000..5407bf3ddf8b5ca61b411342fe54921a2bbb0ec2 GIT binary patch literal 2 JcmZQ#0000600RI3 literal 0 HcmV?d00001 diff --git a/Tests/Fuzzing/corpus/filelock/mode3.bin b/Tests/Fuzzing/corpus/filelock/mode3.bin new file mode 100644 index 0000000000000000000000000000000000000000..15294a501aa6e73201b85ff460b2fcf0adb11e48 GIT binary patch literal 2 JcmZQ(0000800aO4 literal 0 HcmV?d00001 diff --git a/Tests/Fuzzing/corpus/filelock/symlink.bin b/Tests/Fuzzing/corpus/filelock/symlink.bin new file mode 100644 index 0000000000000000000000000000000000000000..8835708590a9afa236e1bbad18df9d23de82ccd3 GIT binary patch literal 2 JcmZQz0ssI600RI3 literal 0 HcmV?d00001 diff --git a/Tests/Fuzzing/corpus/filelock/timeout.bin b/Tests/Fuzzing/corpus/filelock/timeout.bin new file mode 100644 index 0000000000000000000000000000000000000000..d6db588e88905ed0aaaf65a947716182301341c9 GIT binary patch literal 2 JcmZQz0RR9700jU5 literal 0 HcmV?d00001 diff --git a/Tests/Fuzzing/corpus/genex/basic.txt b/Tests/Fuzzing/corpus/genex/basic.txt new file mode 100644 index 0000000000..a999ee4c78 --- /dev/null +++ b/Tests/Fuzzing/corpus/genex/basic.txt @@ -0,0 +1 @@ +$ diff --git a/Tests/Fuzzing/corpus/genex/complex.txt b/Tests/Fuzzing/corpus/genex/complex.txt new file mode 100644 index 0000000000..6532d98919 --- /dev/null +++ b/Tests/Fuzzing/corpus/genex/complex.txt @@ -0,0 +1 @@ +$>>>,shared,static> diff --git a/Tests/Fuzzing/corpus/genex/interface.txt b/Tests/Fuzzing/corpus/genex/interface.txt new file mode 100644 index 0000000000..f0f4837425 --- /dev/null +++ b/Tests/Fuzzing/corpus/genex/interface.txt @@ -0,0 +1 @@ +$$ diff --git a/Tests/Fuzzing/corpus/genex/nested.txt b/Tests/Fuzzing/corpus/genex/nested.txt new file mode 100644 index 0000000000..f3d5f23316 --- /dev/null +++ b/Tests/Fuzzing/corpus/genex/nested.txt @@ -0,0 +1 @@ +$<$:DEBUG_MODE> diff --git a/Tests/Fuzzing/corpus/genex/target.txt b/Tests/Fuzzing/corpus/genex/target.txt new file mode 100644 index 0000000000..fbf5920bf9 --- /dev/null +++ b/Tests/Fuzzing/corpus/genex/target.txt @@ -0,0 +1 @@ +$ diff --git a/Tests/Fuzzing/corpus/json/nested.json b/Tests/Fuzzing/corpus/json/nested.json new file mode 100644 index 0000000000..69a5e0883a --- /dev/null +++ b/Tests/Fuzzing/corpus/json/nested.json @@ -0,0 +1 @@ +{"a":{"b":{"c":{"d":[1,2,3]}}}} diff --git a/Tests/Fuzzing/corpus/json/preset.json b/Tests/Fuzzing/corpus/json/preset.json new file mode 100644 index 0000000000..2850fcf205 --- /dev/null +++ b/Tests/Fuzzing/corpus/json/preset.json @@ -0,0 +1,10 @@ +{ + "version": 3, + "configurePresets": [ + { + "name": "default", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build" + } + ] +} diff --git a/Tests/Fuzzing/corpus/json/types.json b/Tests/Fuzzing/corpus/json/types.json new file mode 100644 index 0000000000..f3c078bf28 --- /dev/null +++ b/Tests/Fuzzing/corpus/json/types.json @@ -0,0 +1,9 @@ +{ + "string": "hello", + "number": 42, + "float": 3.14, + "bool": true, + "null": null, + "array": [1, "two", false], + "object": {"nested": "value"} +} diff --git a/Tests/Fuzzing/corpus/listfile/basic.txt b/Tests/Fuzzing/corpus/listfile/basic.txt new file mode 100644 index 0000000000..34f60cfe04 --- /dev/null +++ b/Tests/Fuzzing/corpus/listfile/basic.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.10) +project(Test) +add_executable(main main.cpp) diff --git a/Tests/Fuzzing/corpus/listfile/bracket.txt b/Tests/Fuzzing/corpus/listfile/bracket.txt new file mode 100644 index 0000000000..8e37caf576 --- /dev/null +++ b/Tests/Fuzzing/corpus/listfile/bracket.txt @@ -0,0 +1,2 @@ +set(x [=[nested [[brackets]] here]=]) +set(y [==[even more [=[nested]=] brackets]==]) diff --git a/Tests/Fuzzing/corpus/listfile/complex.txt b/Tests/Fuzzing/corpus/listfile/complex.txt new file mode 100644 index 0000000000..89e8e72a68 --- /dev/null +++ b/Tests/Fuzzing/corpus/listfile/complex.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.16) +project(ComplexProject VERSION 1.0.0 LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) + +option(BUILD_TESTS "Build tests" ON) + +if(BUILD_TESTS) + enable_testing() + add_subdirectory(tests) +endif() + +function(my_function arg1 arg2) + message(STATUS "Function called with ${arg1} and ${arg2}") +endfunction() + +# Bracket comment [[ +This is a bracket comment +]] + +set(LONG_STRING [[ +This is a bracket +argument with multiple +lines +]]) + +foreach(item IN ITEMS a b c) + message("Item: ${item}") +endforeach() diff --git a/Tests/Fuzzing/corpus/path/dotdot.txt b/Tests/Fuzzing/corpus/path/dotdot.txt new file mode 100644 index 0000000000..b9a8881bbb --- /dev/null +++ b/Tests/Fuzzing/corpus/path/dotdot.txt @@ -0,0 +1 @@ +/home/user/../other/./path diff --git a/Tests/Fuzzing/corpus/path/relative.txt b/Tests/Fuzzing/corpus/path/relative.txt new file mode 100644 index 0000000000..9e16302091 --- /dev/null +++ b/Tests/Fuzzing/corpus/path/relative.txt @@ -0,0 +1 @@ +../build/CMakeFiles diff --git a/Tests/Fuzzing/corpus/path/unix.txt b/Tests/Fuzzing/corpus/path/unix.txt new file mode 100644 index 0000000000..b09d685b88 --- /dev/null +++ b/Tests/Fuzzing/corpus/path/unix.txt @@ -0,0 +1 @@ +/usr/local/lib/cmake diff --git a/Tests/Fuzzing/corpus/path/windows.txt b/Tests/Fuzzing/corpus/path/windows.txt new file mode 100644 index 0000000000..544f098f14 --- /dev/null +++ b/Tests/Fuzzing/corpus/path/windows.txt @@ -0,0 +1 @@ +C:\Program Files\CMake\bin diff --git a/Tests/Fuzzing/corpus/pkgconfig/deps.pc b/Tests/Fuzzing/corpus/pkgconfig/deps.pc new file mode 100644 index 0000000000..19774577f7 --- /dev/null +++ b/Tests/Fuzzing/corpus/pkgconfig/deps.pc @@ -0,0 +1,5 @@ +Name: WithDeps +Version: 2.0 +Requires: dep1 >= 1.0, dep2 +Requires.private: internal +Libs: -lwithdeps diff --git a/Tests/Fuzzing/corpus/pkgconfig/simple.pc b/Tests/Fuzzing/corpus/pkgconfig/simple.pc new file mode 100644 index 0000000000..593db976e1 --- /dev/null +++ b/Tests/Fuzzing/corpus/pkgconfig/simple.pc @@ -0,0 +1,9 @@ +prefix=/usr +libdir=${prefix}/lib +includedir=${prefix}/include + +Name: Example +Description: An example library +Version: 1.0.0 +Libs: -L${libdir} -lexample +Cflags: -I${includedir} diff --git a/Tests/Fuzzing/corpus/script/cmake_path.cmake b/Tests/Fuzzing/corpus/script/cmake_path.cmake new file mode 100644 index 0000000000..75e9f3cc7c --- /dev/null +++ b/Tests/Fuzzing/corpus/script/cmake_path.cmake @@ -0,0 +1,20 @@ +cmake_path(SET p "/usr/local/lib/cmake/foo.cmake") +cmake_path(GET p ROOT_NAME root) +cmake_path(GET p ROOT_DIRECTORY rootdir) +cmake_path(GET p ROOT_PATH rootpath) +cmake_path(GET p FILENAME fname) +cmake_path(GET p EXTENSION ext) +cmake_path(GET p STEM stem) +cmake_path(GET p RELATIVE_PART rel) +cmake_path(GET p PARENT_PATH parent) +cmake_path(APPEND p "bar" OUTPUT_VARIABLE appended) +cmake_path(REMOVE_FILENAME p) +cmake_path(REPLACE_FILENAME p "new.txt") +cmake_path(REMOVE_EXTENSION p) +cmake_path(REPLACE_EXTENSION p ".hpp") +cmake_path(NORMAL_PATH p) +cmake_path(IS_ABSOLUTE p result) +cmake_path(IS_RELATIVE p result) +cmake_path(HAS_ROOT_NAME p result) +cmake_path(HAS_FILENAME p result) +cmake_path(COMPARE p EQUAL "/usr/local" equal_result) diff --git a/Tests/Fuzzing/corpus/script/complex_string.cmake b/Tests/Fuzzing/corpus/script/complex_string.cmake new file mode 100644 index 0000000000..0b7ee565c9 --- /dev/null +++ b/Tests/Fuzzing/corpus/script/complex_string.cmake @@ -0,0 +1,14 @@ +set(input "Hello;World;From;CMake") +string(REPLACE ";" " " spaced "${input}") +string(REGEX REPLACE "([A-Z])" "_\\1" snake "${spaced}") +string(REGEX MATCHALL "[A-Za-z]+" words "${spaced}") +string(GENEX_STRIP "$" stripped) +string(APPEND result "line1\n" "line2\n") +string(PREPEND result "header\n") +string(CONCAT full "a" "b" "c" "d") +string(JOIN ":" joined a b c d) +string(MAKE_C_IDENTIFIER "my-var.name" c_id) +string(RANDOM LENGTH 16 ALPHABET "0123456789ABCDEF" random) +string(TIMESTAMP ts "%Y-%m-%d %H:%M:%S") +string(UUID uuid NAMESPACE 6ba7b810-9dad-11d1-80b4-00c04fd430c8 NAME test TYPE SHA1) +string(JSON json_val GET "{\"key\":\"value\"}" "key") diff --git a/Tests/Fuzzing/corpus/script/configure_file.cmake b/Tests/Fuzzing/corpus/script/configure_file.cmake new file mode 100644 index 0000000000..6c2c949856 --- /dev/null +++ b/Tests/Fuzzing/corpus/script/configure_file.cmake @@ -0,0 +1,7 @@ +set(VERSION "1.0.0") +set(AUTHOR "Test Author") +file(WRITE /tmp/config.h.in "#define VERSION \"@VERSION@\"\n#define AUTHOR \"@AUTHOR@\"\n") +configure_file(/tmp/config.h.in /tmp/config.h @ONLY) +file(READ /tmp/config.h config_content) +message(STATUS "Configured: ${config_content}") +file(REMOVE /tmp/config.h.in /tmp/config.h) diff --git a/Tests/Fuzzing/corpus/script/control_flow.cmake b/Tests/Fuzzing/corpus/script/control_flow.cmake new file mode 100644 index 0000000000..8d84d639fa --- /dev/null +++ b/Tests/Fuzzing/corpus/script/control_flow.cmake @@ -0,0 +1,12 @@ +set(X 5) +if(X GREATER 3) + message("X > 3") +elseif(X EQUAL 3) + message("X == 3") +else() + message("X < 3") +endif() + +foreach(i RANGE 3) + message("i = ${i}") +endforeach() diff --git a/Tests/Fuzzing/corpus/script/execute_process.cmake b/Tests/Fuzzing/corpus/script/execute_process.cmake new file mode 100644 index 0000000000..96b0fd96ed --- /dev/null +++ b/Tests/Fuzzing/corpus/script/execute_process.cmake @@ -0,0 +1,10 @@ +execute_process( + COMMAND echo "Hello from process" + OUTPUT_VARIABLE output + ERROR_VARIABLE error + RESULT_VARIABLE result + TIMEOUT 5 + WORKING_DIRECTORY /tmp +) +message(STATUS "Output: ${output}") +message(STATUS "Result: ${result}") diff --git a/Tests/Fuzzing/corpus/script/file_ops.cmake b/Tests/Fuzzing/corpus/script/file_ops.cmake new file mode 100644 index 0000000000..1c5c619664 --- /dev/null +++ b/Tests/Fuzzing/corpus/script/file_ops.cmake @@ -0,0 +1,4 @@ +file(WRITE "/tmp/cmake_fuzz_test.txt" "test content") +file(READ "/tmp/cmake_fuzz_test.txt" content) +file(REMOVE "/tmp/cmake_fuzz_test.txt") +file(GLOB files "/tmp/*.txt") diff --git a/Tests/Fuzzing/corpus/script/function.cmake b/Tests/Fuzzing/corpus/script/function.cmake new file mode 100644 index 0000000000..b8cf7b740d --- /dev/null +++ b/Tests/Fuzzing/corpus/script/function.cmake @@ -0,0 +1,7 @@ +function(my_func arg1 arg2) + message("arg1: ${arg1}, arg2: ${arg2}") + set(RESULT "${arg1}_${arg2}" PARENT_SCOPE) +endfunction() + +my_func("hello" "world") +message("Result: ${RESULT}") diff --git a/Tests/Fuzzing/corpus/script/list_ops.cmake b/Tests/Fuzzing/corpus/script/list_ops.cmake new file mode 100644 index 0000000000..fef4874217 --- /dev/null +++ b/Tests/Fuzzing/corpus/script/list_ops.cmake @@ -0,0 +1,17 @@ +set(MYLIST a b c d e f) +list(LENGTH MYLIST len) +list(GET MYLIST 0 first) +list(GET MYLIST -1 last) +list(APPEND MYLIST g h) +list(PREPEND MYLIST z) +list(INSERT MYLIST 2 x y) +list(FIND MYLIST c idx) +list(REMOVE_AT MYLIST 0) +list(REMOVE_ITEM MYLIST e) +list(REMOVE_DUPLICATES MYLIST) +list(REVERSE MYLIST) +list(SORT MYLIST) +list(SUBLIST MYLIST 1 3 sub) +list(JOIN MYLIST "," joined) +list(TRANSFORM MYLIST TOUPPER) +list(FILTER MYLIST INCLUDE REGEX "[A-Z]") diff --git a/Tests/Fuzzing/corpus/script/math_ops.cmake b/Tests/Fuzzing/corpus/script/math_ops.cmake new file mode 100644 index 0000000000..78e785395f --- /dev/null +++ b/Tests/Fuzzing/corpus/script/math_ops.cmake @@ -0,0 +1,3 @@ +math(EXPR result "1 + 2 * 3") +math(EXPR hex "0xFF" OUTPUT_FORMAT HEXADECIMAL) +math(EXPR dec "0x10" OUTPUT_FORMAT DECIMAL) diff --git a/Tests/Fuzzing/corpus/script/string_ops.cmake b/Tests/Fuzzing/corpus/script/string_ops.cmake new file mode 100644 index 0000000000..08b9a1b323 --- /dev/null +++ b/Tests/Fuzzing/corpus/script/string_ops.cmake @@ -0,0 +1,6 @@ +set(STR "Hello World") +string(LENGTH "${STR}" len) +string(TOUPPER "${STR}" upper) +string(TOLOWER "${STR}" lower) +string(REPLACE "World" "CMake" result "${STR}") +string(REGEX MATCH "[A-Z]+" match "${STR}") diff --git a/Tests/Fuzzing/corpus/script/variables.cmake b/Tests/Fuzzing/corpus/script/variables.cmake new file mode 100644 index 0000000000..cfd374dcfe --- /dev/null +++ b/Tests/Fuzzing/corpus/script/variables.cmake @@ -0,0 +1,5 @@ +set(MY_VAR "hello") +set(MY_LIST a b c d) +message(STATUS "VAR: ${MY_VAR}") +list(LENGTH MY_LIST len) +message(STATUS "Length: ${len}") diff --git a/Tests/Fuzzing/corpus/string/cmake_var.txt b/Tests/Fuzzing/corpus/string/cmake_var.txt new file mode 100644 index 0000000000..3c3974edd3 --- /dev/null +++ b/Tests/Fuzzing/corpus/string/cmake_var.txt @@ -0,0 +1 @@ +${CMAKE_SOURCE_DIR} diff --git a/Tests/Fuzzing/corpus/string/list.txt b/Tests/Fuzzing/corpus/string/list.txt new file mode 100644 index 0000000000..2bde41b0f1 --- /dev/null +++ b/Tests/Fuzzing/corpus/string/list.txt @@ -0,0 +1 @@ +item1;item2;item3;item4 diff --git a/Tests/Fuzzing/corpus/string/quoted.txt b/Tests/Fuzzing/corpus/string/quoted.txt new file mode 100644 index 0000000000..cab0dd8140 --- /dev/null +++ b/Tests/Fuzzing/corpus/string/quoted.txt @@ -0,0 +1 @@ +"quoted string with spaces" diff --git a/Tests/Fuzzing/corpus/version/long.txt b/Tests/Fuzzing/corpus/version/long.txt new file mode 100644 index 0000000000..4e783d961c --- /dev/null +++ b/Tests/Fuzzing/corpus/version/long.txt @@ -0,0 +1 @@ +3.28.0.20231201 diff --git a/Tests/Fuzzing/corpus/version/semver.txt b/Tests/Fuzzing/corpus/version/semver.txt new file mode 100644 index 0000000000..5f3aef5fcb --- /dev/null +++ b/Tests/Fuzzing/corpus/version/semver.txt @@ -0,0 +1 @@ +1.2.3-alpha+build diff --git a/Tests/Fuzzing/corpus/version/simple.txt b/Tests/Fuzzing/corpus/version/simple.txt new file mode 100644 index 0000000000..a72fd67b60 --- /dev/null +++ b/Tests/Fuzzing/corpus/version/simple.txt @@ -0,0 +1 @@ +3.28.0 diff --git a/Tests/Fuzzing/corpus/version/tweak.txt b/Tests/Fuzzing/corpus/version/tweak.txt new file mode 100644 index 0000000000..70f7f54a2c --- /dev/null +++ b/Tests/Fuzzing/corpus/version/tweak.txt @@ -0,0 +1 @@ +3.28.0.1 diff --git a/Tests/Fuzzing/xml_parser.dict b/Tests/Fuzzing/xml_parser.dict new file mode 100644 index 0000000000..c50ef6d1fe --- /dev/null +++ b/Tests/Fuzzing/xml_parser.dict @@ -0,0 +1,75 @@ +# XML dictionary for xml_parser_fuzzer + +# Processing instruction +"" +"version=" +"encoding=" +"standalone=" + +# Document structure +"" +"/>" +"" +"" + +# Namespaces +"xmlns" +"xmlns:" + +# Common CMake XML elements +"" +"?>" diff --git a/Tests/README.rst b/Tests/README.rst index 4bbbce1951..ab1438c94c 100644 --- a/Tests/README.rst +++ b/Tests/README.rst @@ -33,4 +33,10 @@ are organized as follows. See `RunCMake/README.rst`_. +* ``Fuzzing/``: + Fuzz testing targets using libFuzzer, integrated with OSS-Fuzz. + + See `Fuzzing/README.rst`_. + .. _`RunCMake/README.rst`: RunCMake/README.rst +.. _`Fuzzing/README.rst`: Fuzzing/README.rst