浏览代码

Merge topic 'test-fuzzing'

287cf755c8 ci: Add lint job building fuzzers on Linux
c602a9824c Tests/Fuzzing: Add cmScriptFuzzer
3664b51006 Tests/Fuzzing: Add cmFileLockFuzzer
0a760a2794 Tests/Fuzzing: Add cmArchiveExtractFuzzer
2eec5a34f5 Tests/Fuzzing: Add cmELFFuzzer
26f02d8f2a Tests/Fuzzing: Add cmGlobFuzzer
78992bf2ea Tests/Fuzzing: Add cmCMakePathFuzzer
e4f4ad5959 Tests/Fuzzing: Add cmVersionFuzzer
...

Acked-by: Kitware Robot <[email protected]>
Merge-request: !11521
Brad King 1 月之前
父节点
当前提交
fad74f77ab
共有 100 个文件被更改,包括 3023 次插入7 次删除
  1. 7 0
      .gitlab-ci.yml
  2. 3 0
      .gitlab/ci/configure_fedora43_clang_fuzzing.cmake
  3. 5 0
      .gitlab/ci/env_fedora43_clang_fuzzing.sh
  4. 8 1
      .gitlab/os-linux.yml
  5. 3 0
      CMakeLists.txt
  6. 5 0
      Tests/CMakeLists.txt
  7. 99 0
      Tests/Fuzzing/CMakeLists.txt
  8. 49 6
      Tests/Fuzzing/README.rst
  9. 72 0
      Tests/Fuzzing/cmArchiveExtract.dict
  10. 121 0
      Tests/Fuzzing/cmArchiveExtractFuzzer.cxx
  11. 10 0
      Tests/Fuzzing/cmArchiveExtractFuzzer.options
  12. 61 0
      Tests/Fuzzing/cmCMakePath.dict
  13. 77 0
      Tests/Fuzzing/cmCMakePathFuzzer.cxx
  14. 85 0
      Tests/Fuzzing/cmELF.dict
  15. 147 0
      Tests/Fuzzing/cmELFFuzzer.cxx
  16. 10 0
      Tests/Fuzzing/cmELFFuzzer.options
  17. 51 0
      Tests/Fuzzing/cmExprParser.dict
  18. 48 0
      Tests/Fuzzing/cmExprParserFuzzer.cxx
  19. 43 0
      Tests/Fuzzing/cmFileLock.dict
  20. 147 0
      Tests/Fuzzing/cmFileLockFuzzer.cxx
  21. 45 0
      Tests/Fuzzing/cmGccDepfile.dict
  22. 76 0
      Tests/Fuzzing/cmGccDepfileFuzzer.cxx
  23. 84 0
      Tests/Fuzzing/cmGeneratorExpression.dict
  24. 88 0
      Tests/Fuzzing/cmGeneratorExpressionFuzzer.cxx
  25. 50 0
      Tests/Fuzzing/cmGlob.dict
  26. 69 0
      Tests/Fuzzing/cmGlobFuzzer.cxx
  27. 72 0
      Tests/Fuzzing/cmJSONParser.dict
  28. 107 0
      Tests/Fuzzing/cmJSONParserFuzzer.cxx
  29. 108 0
      Tests/Fuzzing/cmListFileLexer.dict
  30. 62 0
      Tests/Fuzzing/cmListFileLexerFuzzer.cxx
  31. 84 0
      Tests/Fuzzing/cmListFileParserFuzzer.cxx
  32. 63 0
      Tests/Fuzzing/cmPkgConfigParser.dict
  33. 59 0
      Tests/Fuzzing/cmPkgConfigParserFuzzer.cxx
  34. 193 0
      Tests/Fuzzing/cmScript.dict
  35. 147 0
      Tests/Fuzzing/cmScriptFuzzer.cxx
  36. 10 0
      Tests/Fuzzing/cmScriptFuzzer.options
  37. 71 0
      Tests/Fuzzing/cmStringAlgorithms.dict
  38. 75 0
      Tests/Fuzzing/cmStringAlgorithmsFuzzer.cxx
  39. 42 0
      Tests/Fuzzing/cmVersion.dict
  40. 56 0
      Tests/Fuzzing/cmVersionFuzzer.cxx
  41. 26 0
      Tests/Fuzzing/corpus/README.rst
  42. 二进制
      Tests/Fuzzing/corpus/archive/simple.tar
  43. 二进制
      Tests/Fuzzing/corpus/archive/simple.tar.gz
  44. 二进制
      Tests/Fuzzing/corpus/archive/simple.zip
  45. 二进制
      Tests/Fuzzing/corpus/archive/with_dir.tar
  46. 4 0
      Tests/Fuzzing/corpus/depfile/multiline.d
  47. 1 0
      Tests/Fuzzing/corpus/depfile/simple.d
  48. 1 0
      Tests/Fuzzing/corpus/depfile/spaces.d
  49. 109 0
      Tests/Fuzzing/corpus/elf/generate.py
  50. 二进制
      Tests/Fuzzing/corpus/elf/minimal32.elf
  51. 二进制
      Tests/Fuzzing/corpus/elf/minimal64.elf
  52. 1 0
      Tests/Fuzzing/corpus/expr/hex.txt
  53. 1 0
      Tests/Fuzzing/corpus/expr/not.txt
  54. 1 0
      Tests/Fuzzing/corpus/expr/parens.txt
  55. 1 0
      Tests/Fuzzing/corpus/expr/precedence.txt
  56. 1 0
      Tests/Fuzzing/corpus/expr/shift.txt
  57. 1 0
      Tests/Fuzzing/corpus/expr/simple.txt
  58. 二进制
      Tests/Fuzzing/corpus/filelock/custom_name.bin
  59. 二进制
      Tests/Fuzzing/corpus/filelock/mode0.bin
  60. 二进制
      Tests/Fuzzing/corpus/filelock/mode1.bin
  61. 二进制
      Tests/Fuzzing/corpus/filelock/mode2.bin
  62. 二进制
      Tests/Fuzzing/corpus/filelock/mode3.bin
  63. 二进制
      Tests/Fuzzing/corpus/filelock/symlink.bin
  64. 二进制
      Tests/Fuzzing/corpus/filelock/timeout.bin
  65. 1 0
      Tests/Fuzzing/corpus/genex/basic.txt
  66. 1 0
      Tests/Fuzzing/corpus/genex/complex.txt
  67. 1 0
      Tests/Fuzzing/corpus/genex/interface.txt
  68. 1 0
      Tests/Fuzzing/corpus/genex/nested.txt
  69. 1 0
      Tests/Fuzzing/corpus/genex/target.txt
  70. 1 0
      Tests/Fuzzing/corpus/json/nested.json
  71. 10 0
      Tests/Fuzzing/corpus/json/preset.json
  72. 9 0
      Tests/Fuzzing/corpus/json/types.json
  73. 3 0
      Tests/Fuzzing/corpus/listfile/basic.txt
  74. 2 0
      Tests/Fuzzing/corpus/listfile/bracket.txt
  75. 29 0
      Tests/Fuzzing/corpus/listfile/complex.txt
  76. 1 0
      Tests/Fuzzing/corpus/path/dotdot.txt
  77. 1 0
      Tests/Fuzzing/corpus/path/relative.txt
  78. 1 0
      Tests/Fuzzing/corpus/path/unix.txt
  79. 1 0
      Tests/Fuzzing/corpus/path/windows.txt
  80. 5 0
      Tests/Fuzzing/corpus/pkgconfig/deps.pc
  81. 9 0
      Tests/Fuzzing/corpus/pkgconfig/simple.pc
  82. 20 0
      Tests/Fuzzing/corpus/script/cmake_path.cmake
  83. 14 0
      Tests/Fuzzing/corpus/script/complex_string.cmake
  84. 7 0
      Tests/Fuzzing/corpus/script/configure_file.cmake
  85. 12 0
      Tests/Fuzzing/corpus/script/control_flow.cmake
  86. 10 0
      Tests/Fuzzing/corpus/script/execute_process.cmake
  87. 4 0
      Tests/Fuzzing/corpus/script/file_ops.cmake
  88. 7 0
      Tests/Fuzzing/corpus/script/function.cmake
  89. 17 0
      Tests/Fuzzing/corpus/script/list_ops.cmake
  90. 3 0
      Tests/Fuzzing/corpus/script/math_ops.cmake
  91. 6 0
      Tests/Fuzzing/corpus/script/string_ops.cmake
  92. 5 0
      Tests/Fuzzing/corpus/script/variables.cmake
  93. 1 0
      Tests/Fuzzing/corpus/string/cmake_var.txt
  94. 1 0
      Tests/Fuzzing/corpus/string/list.txt
  95. 1 0
      Tests/Fuzzing/corpus/string/quoted.txt
  96. 1 0
      Tests/Fuzzing/corpus/version/long.txt
  97. 1 0
      Tests/Fuzzing/corpus/version/semver.txt
  98. 1 0
      Tests/Fuzzing/corpus/version/simple.txt
  99. 1 0
      Tests/Fuzzing/corpus/version/tweak.txt
  100. 75 0
      Tests/Fuzzing/xml_parser.dict

+ 7 - 0
.gitlab-ci.yml

@@ -141,6 +141,13 @@ l:clang-analyzer-fedora43:
     variables:
         CMAKE_CI_JOB_NIGHTLY: "true"
 
+l:clang-fuzzing-fedora43:
+    extends:
+        - .fedora43_clang_fuzzing
+        - .cmake_build_linux
+        - .linux_x86_64_tags
+        - .run_automatically
+
 l:clazy-fedora43:
     extends:
         - .fedora43_clazy

+ 3 - 0
.gitlab/ci/configure_fedora43_clang_fuzzing.cmake

@@ -0,0 +1,3 @@
+set(CMake_BUILD_FUZZING ON CACHE BOOL "")
+
+include("${CMAKE_CURRENT_LIST_DIR}/configure_common.cmake")

+ 5 - 0
.gitlab/ci/env_fedora43_clang_fuzzing.sh

@@ -0,0 +1,5 @@
+export CC=/usr/bin/clang
+export CXX=/usr/bin/clang++
+
+export CFLAGS=-fsanitize=fuzzer-no-link,address
+export CXXFLAGS=-fsanitize=fuzzer-no-link,address

+ 8 - 1
.gitlab/os-linux.yml

@@ -141,6 +141,14 @@
         CTEST_NO_WARNINGS_ALLOWED: 1
         CMAKE_CI_NO_INSTALL: 1
 
+.fedora43_clang_fuzzing:
+    extends: .fedora43
+
+    variables:
+        CMAKE_CONFIGURATION: fedora43_clang_fuzzing
+        CTEST_NO_WARNINGS_ALLOWED: 1
+        CMAKE_CI_NO_INSTALL: 1
+
 .fedora43_clazy:
     extends: .fedora43
 
@@ -352,7 +360,6 @@
     variables:
         CMAKE_CONFIGURATION: fedora43_asan
 
-
 .fedora43_ninja_valgrind:
     extends:
         - .fedora43

+ 3 - 0
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)

+ 5 - 0
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 "")

+ 99 - 0
Tests/Fuzzing/CMakeLists.txt

@@ -0,0 +1,99 @@
+# 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}")
+
+# CMakeLists.txt lexer fuzzer
+add_fuzzer(cmListFileLexerFuzzer cmListFileLexerFuzzer.cxx)
+
+# CMakeLists.txt parser fuzzer
+add_fuzzer(cmListFileParserFuzzer cmListFileParserFuzzer.cxx)
+
+# Generator expression fuzzer
+add_fuzzer(cmGeneratorExpressionFuzzer cmGeneratorExpressionFuzzer.cxx)
+
+# Math expression parser fuzzer
+add_fuzzer(cmExprParserFuzzer cmExprParserFuzzer.cxx)
+
+# pkg-config parser fuzzer
+add_fuzzer(cmPkgConfigParserFuzzer cmPkgConfigParserFuzzer.cxx)
+
+# JSON parser fuzzer
+add_fuzzer(cmJSONParserFuzzer cmJSONParserFuzzer.cxx)
+
+# GCC dependency file fuzzer
+add_fuzzer(cmGccDepfileFuzzer cmGccDepfileFuzzer.cxx)
+
+# String algorithms fuzzer
+add_fuzzer(cmStringAlgorithmsFuzzer cmStringAlgorithmsFuzzer.cxx)
+
+# Version parser fuzzer
+add_fuzzer(cmVersionFuzzer cmVersionFuzzer.cxx)
+
+# CMake path fuzzer
+add_fuzzer(cmCMakePathFuzzer cmCMakePathFuzzer.cxx)
+
+# File glob fuzzer
+add_fuzzer(cmGlobFuzzer cmGlobFuzzer.cxx)
+
+# ELF binary parser fuzzer
+add_fuzzer(cmELFFuzzer cmELFFuzzer.cxx)
+
+# Archive extraction fuzzer
+add_fuzzer(cmArchiveExtractFuzzer cmArchiveExtractFuzzer.cxx)
+
+# File lock fuzzer
+add_fuzzer(cmFileLockFuzzer cmFileLockFuzzer.cxx)
+
+# CMake script fuzzer
+add_fuzzer(cmScriptFuzzer cmScriptFuzzer.cxx)

+ 49 - 6
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/<fuzzer_name>/``.
+
+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.

+ 72 - 0
Tests/Fuzzing/cmArchiveExtract.dict

@@ -0,0 +1,72 @@
+# Archive Format Dictionary
+
+# Tar magic
+"ustar"
+"ustar  "
+"ustar\x0000"
+
+# Gzip magic
+"\x1f\x8b"
+"\x1f\x8b\x08"
+
+# Bzip2 magic
+"BZ"
+"BZh"
+"BZh9"
+
+# XZ magic
+"\xfd7zXZ\x00"
+
+# Zip magic
+"PK\x03\x04"
+"PK\x01\x02"
+"PK\x05\x06"
+
+# 7z magic
+"7z\xbc\xaf\x27\x1c"
+
+# Tar header fields
+"\x00\x00\x00\x00\x00\x00\x00\x00"
+"0000000"
+"0000644"
+"0000755"
+"0000777"
+"00000000000"
+"        "
+
+# Path traversal (security testing)
+"../"
+"../../"
+"../../../"
+"../../../../"
+"/../"
+"/../../"
+
+# Absolute paths
+"/etc/passwd"
+"/tmp/"
+"/home/"
+"/.."
+
+# Long paths
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+
+# Symlink indicators
+"1"
+"2"
+
+# File type indicators
+"0"
+"5"
+"L"
+"K"
+
+# Checksum placeholder
+"        "
+
+# Filenames
+"test.txt"
+"file.dat"
+"CMakeLists.txt"
+".hidden"
+"__MACOSX"

+ 121 - 0
Tests/Fuzzing/cmArchiveExtractFuzzer.cxx

@@ -0,0 +1,121 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+/*
+ * Fuzzer for CMake's archive extraction (tar/zip)
+ *
+ * CMake extracts archives via cmSystemTools::ExtractTar. This is a critical
+ * attack surface as malicious archives could contain path traversal sequences
+ * (Zip Slip) or other exploits.
+ *
+ * Coverage targets:
+ * - Archive format detection (tar, gzip, bzip2, xz, zip)
+ * - Path handling during extraction
+ * - Symlink handling
+ * - Large file handling
+ * - Malformed archive recovery
+ *
+ * Security focus:
+ * - Path traversal (../) detection
+ * - Absolute path handling
+ * - Symlink escape attempts
+ */
+
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <string>
+#include <vector>
+
+#include "cmSystemTools.h"
+
+// Archives can be large but limit for fuzzing
+static constexpr size_t kMinInputSize = 4;          // Minimum magic bytes
+static constexpr size_t kMaxInputSize = 256 * 1024; // 256KB
+
+// Sandbox directory for extraction
+static std::string g_extractDir;
+
+extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
+{
+  (void)argc;
+  (void)argv;
+
+  // Create a unique extraction directory in /tmp
+  char tmpl[] = "/tmp/cmake_fuzz_extract_XXXXXX";
+  char* dir = mkdtemp(tmpl);
+  if (dir) {
+    g_extractDir = dir;
+  } else {
+    g_extractDir = "/tmp/cmake_fuzz_extract";
+    cmSystemTools::MakeDirectory(g_extractDir);
+  }
+
+  return 0;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
+{
+  if (size < kMinInputSize || size > kMaxInputSize) {
+    return 0;
+  }
+
+  // Write archive to temp file
+  std::string archiveFile = g_extractDir + "/test_archive";
+  {
+    FILE* fp = fopen(archiveFile.c_str(), "wb");
+    if (!fp) {
+      return 0;
+    }
+    fwrite(data, 1, size, fp);
+    fclose(fp);
+  }
+
+  // Create a fresh extraction subdirectory each time
+  std::string extractSubDir = g_extractDir + "/out";
+  cmSystemTools::RemoveADirectory(extractSubDir);
+  cmSystemTools::MakeDirectory(extractSubDir);
+
+  // Save current directory
+  std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+
+  // Change to extraction directory (cmSystemTools extracts to cwd)
+  if (cmSystemTools::ChangeDirectory(extractSubDir)) {
+    // Try extraction with different options
+    std::vector<std::string> files;
+
+    // Extract without verbose, with timestamps
+    bool result1 = cmSystemTools::ExtractTar(
+      archiveFile, files, cmSystemTools::cmTarExtractTimestamps::Yes, false);
+    (void)result1;
+
+    // Restore directory BEFORE removing (can't remove cwd)
+    cmSystemTools::ChangeDirectory(cwd);
+
+    // Clean up extracted files
+    cmSystemTools::RemoveADirectory(extractSubDir);
+    cmSystemTools::MakeDirectory(extractSubDir);
+
+    // Change back for second extraction
+    if (cmSystemTools::ChangeDirectory(extractSubDir)) {
+      // Extract with verbose, without timestamps
+      files.clear();
+      bool result2 = cmSystemTools::ExtractTar(
+        archiveFile, files, cmSystemTools::cmTarExtractTimestamps::No, true);
+      (void)result2;
+
+      // Restore directory
+      cmSystemTools::ChangeDirectory(cwd);
+    }
+  }
+
+  // Note: A more thorough security check would verify nothing escaped the
+  // sandbox, but for fuzzing we rely on sanitizers to catch path traversal
+
+  // Cleanup
+  cmSystemTools::RemoveADirectory(extractSubDir);
+  cmSystemTools::RemoveFile(archiveFile);
+
+  return 0;
+}

+ 10 - 0
Tests/Fuzzing/cmArchiveExtractFuzzer.options

@@ -0,0 +1,10 @@
+[libfuzzer]
+max_len = 262144
+timeout = 60
+rss_limit_mb = 2048
+
+[afl]
+timeout = 60
+
+[honggfuzz]
+timeout = 60

+ 61 - 0
Tests/Fuzzing/cmCMakePath.dict

@@ -0,0 +1,61 @@
+# CMake path dictionary
+
+# Separators
+"/"
+"\\"
+":"
+
+# Unix paths
+"/usr"
+"/usr/local"
+"/home"
+"/tmp"
+"/var"
+"/etc"
+"/opt"
+"/bin"
+"/lib"
+
+# Windows paths
+"C:"
+"D:"
+"C:\\"
+"Program Files"
+"Windows"
+
+# CMake directories
+"CMakeFiles"
+"cmake"
+"share"
+"lib"
+"include"
+"bin"
+"build"
+"src"
+"source"
+
+# Special paths
+"."
+".."
+"./"
+"../"
+"~"
+
+# Extensions
+".cmake"
+".txt"
+".h"
+".hpp"
+".c"
+".cpp"
+".cxx"
+".a"
+".so"
+".dll"
+".lib"
+
+# CMake files
+"CMakeLists.txt"
+"CMakeCache.txt"
+"cmake_install.cmake"
+"CTestTestfile.cmake"

+ 77 - 0
Tests/Fuzzing/cmCMakePathFuzzer.cxx

@@ -0,0 +1,77 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+/*
+ * Fuzzer for CMake's path manipulation (cmCMakePath)
+ *
+ * Tests path parsing, normalization, and manipulation operations.
+ */
+
+#include <cstddef>
+#include <cstdint>
+#include <string>
+
+#include "cmCMakePath.h"
+
+static constexpr size_t kMaxInputSize = 4096;
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
+{
+  if (size == 0 || size > kMaxInputSize) {
+    return 0;
+  }
+
+  std::string input(reinterpret_cast<char const*>(data), size);
+
+  // Test various path operations
+  cmCMakePath path(input);
+
+  // Basic queries
+  (void)path.IsEmpty();
+  (void)path.HasRootPath();
+  (void)path.HasRootName();
+  (void)path.HasRootDirectory();
+  (void)path.HasRelativePath();
+  (void)path.HasParentPath();
+  (void)path.HasFileName();
+  (void)path.HasStem();
+  (void)path.HasExtension();
+  (void)path.IsAbsolute();
+  (void)path.IsRelative();
+
+  // Component extraction
+  (void)path.GetRootName();
+  (void)path.GetRootDirectory();
+  (void)path.GetRootPath();
+  (void)path.GetRelativePath();
+  (void)path.GetParentPath();
+  (void)path.GetFileName();
+  (void)path.GetExtension();
+  (void)path.GetStem();
+  (void)path.String();
+  (void)path.GenericString();
+
+  // Manipulation
+  cmCMakePath normalized = path.Normal();
+  (void)normalized.String();
+
+  // If we have two paths in input, test operations between them
+  size_t midpoint = size / 2;
+  if (midpoint > 0) {
+    std::string input1(reinterpret_cast<char const*>(data), midpoint);
+    std::string input2(reinterpret_cast<char const*>(data + midpoint),
+                       size - midpoint);
+
+    cmCMakePath path1(input1);
+    cmCMakePath path2(input2);
+
+    // Append operations
+    cmCMakePath appended = path1 / path2;
+    (void)appended.String();
+
+    // Comparison
+    (void)(path1 == path2);
+  }
+
+  return 0;
+}

+ 85 - 0
Tests/Fuzzing/cmELF.dict

@@ -0,0 +1,85 @@
+# ELF File Format Dictionary
+
+# ELF magic number
+"\x7fELF"
+
+# ELF class (32/64 bit)
+"\x01"
+"\x02"
+
+# Data encoding (little/big endian)
+"\x01"
+"\x02"
+
+# ELF version
+"\x01"
+
+# OS/ABI
+"\x00"
+"\x03"
+"\x09"
+
+# Object file types
+"\x00\x00"
+"\x01\x00"
+"\x02\x00"
+"\x03\x00"
+"\x04\x00"
+
+# Machine types
+"\x03\x00"
+"\x3e\x00"
+"\x28\x00"
+"\xb7\x00"
+"\x08\x00"
+
+# Section types
+"\x00\x00\x00\x00"
+"\x01\x00\x00\x00"
+"\x02\x00\x00\x00"
+"\x03\x00\x00\x00"
+"\x04\x00\x00\x00"
+"\x05\x00\x00\x00"
+"\x06\x00\x00\x00"
+"\x07\x00\x00\x00"
+"\x08\x00\x00\x00"
+"\x09\x00\x00\x00"
+"\x0b\x00\x00\x00"
+
+# Dynamic tags
+"\x01\x00\x00\x00"
+"\x0e\x00\x00\x00"
+"\x0f\x00\x00\x00"
+"\x1d\x00\x00\x00"
+
+# Section names
+".text"
+".data"
+".bss"
+".rodata"
+".dynamic"
+".dynsym"
+".dynstr"
+".interp"
+".note"
+".shstrtab"
+".strtab"
+".symtab"
+".rela"
+".rel"
+".plt"
+".got"
+".init"
+".fini"
+
+# String entries
+"RPATH"
+"RUNPATH"
+"SONAME"
+"NEEDED"
+
+# Common library paths
+"/lib"
+"/usr/lib"
+"$ORIGIN"
+"$LIB"

+ 147 - 0
Tests/Fuzzing/cmELFFuzzer.cxx

@@ -0,0 +1,147 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+/*
+ * Fuzzer for CMake's ELF parser
+ *
+ * CMake parses ELF files to extract RPATH, RUNPATH, and SONAME information.
+ * Malformed ELF files from untrusted sources could trigger vulnerabilities.
+ *
+ * Coverage targets:
+ * - ELF header parsing (32-bit and 64-bit)
+ * - Section header parsing
+ * - Dynamic section parsing
+ * - String table extraction
+ * - RPATH/RUNPATH/SONAME extraction
+ *
+ * Performance notes:
+ * - Uses memfd_create on Linux for memory-backed file I/O
+ * - Falls back to temp files on other platforms
+ */
+
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <sstream>
+#include <string>
+
+#include <unistd.h>
+
+#include "cmELF.h"
+
+#ifdef __linux__
+#  include <sys/mman.h>
+#  ifndef MFD_CLOEXEC
+#    define MFD_CLOEXEC 0x0001U
+#  endif
+#endif
+
+// ELF files can be large, but we limit to avoid timeouts
+static constexpr size_t kMinInputSize = 16;         // Minimum ELF header
+static constexpr size_t kMaxInputSize = 512 * 1024; // 512KB
+
+static int g_memfd = -1;
+static std::string g_memfdPath;
+
+extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
+{
+  (void)argc;
+  (void)argv;
+
+#ifdef __linux__
+  g_memfd = memfd_create("cmake_fuzz_elf", MFD_CLOEXEC);
+  if (g_memfd >= 0) {
+    g_memfdPath = "/proc/self/fd/" + std::to_string(g_memfd);
+  }
+#endif
+  return 0;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
+{
+  // ELF files need minimum header size
+  if (size < kMinInputSize || size > kMaxInputSize) {
+    return 0;
+  }
+
+  std::string testFile;
+
+#ifdef __linux__
+  if (g_memfd >= 0) {
+    // Use memfd for better performance
+    ftruncate(g_memfd, 0);
+    lseek(g_memfd, 0, SEEK_SET);
+    if (write(g_memfd, data, size) != static_cast<ssize_t>(size)) {
+      return 0;
+    }
+    testFile = g_memfdPath;
+  } else
+#endif
+  {
+    // Fallback to temp file
+    char tmpFile[] = "/tmp/fuzz_elf_XXXXXX";
+    int fd = mkstemp(tmpFile);
+    if (fd < 0) {
+      return 0;
+    }
+    if (write(fd, data, size) != static_cast<ssize_t>(size)) {
+      close(fd);
+      unlink(tmpFile);
+      return 0;
+    }
+    close(fd);
+    testFile = tmpFile;
+  }
+
+  // Parse the ELF file
+  {
+    cmELF elf(testFile.c_str());
+
+    // Check validity
+    if (elf) {
+      // Exercise all the parsing functions
+      (void)elf.GetFileType();
+      (void)elf.GetMachine();
+      (void)elf.GetNumberOfSections();
+      (void)elf.HasDynamicSection();
+      (void)elf.IsMIPS();
+
+      // Try to get string entries
+      std::string soname;
+      elf.GetSOName(soname);
+      (void)elf.GetSOName();
+      (void)elf.GetRPath();
+      (void)elf.GetRunPath();
+
+      // Get dynamic entries
+      auto entries = elf.GetDynamicEntries();
+      if (!entries.empty()) {
+        auto encoded = elf.EncodeDynamicEntries(entries);
+        (void)encoded;
+
+        // Get positions (limit iterations to avoid timeout)
+        for (size_t i = 0; i < entries.size() && i < 100; ++i) {
+          (void)elf.GetDynamicEntryPosition(static_cast<int>(i));
+        }
+      }
+
+      // Print info to exercise that code path
+      std::ostringstream oss;
+      elf.PrintInfo(oss);
+    }
+
+    // Always check error message path
+    (void)elf.GetErrorMessage();
+  }
+
+  // Cleanup temp file (memfd doesn't need cleanup)
+#ifdef __linux__
+  if (g_memfd < 0)
+#endif
+  {
+    unlink(testFile.c_str());
+  }
+
+  return 0;
+}

+ 10 - 0
Tests/Fuzzing/cmELFFuzzer.options

@@ -0,0 +1,10 @@
+[libfuzzer]
+max_len = 524288
+timeout = 30
+rss_limit_mb = 1024
+
+[afl]
+timeout = 30
+
+[honggfuzz]
+timeout = 30

+ 51 - 0
Tests/Fuzzing/cmExprParser.dict

@@ -0,0 +1,51 @@
+# CMake Expression Parser Dictionary (math expressions)
+
+# Operators
+"+"
+"-"
+"*"
+"/"
+"%"
+"|"
+"&"
+"^"
+"~"
+"<<"
+">>"
+"("
+")"
+
+# Numbers
+"0"
+"1"
+"2"
+"10"
+"100"
+"1000"
+"-1"
+"-100"
+"0x"
+"0X"
+"0xff"
+"0xFF"
+"0x7fffffff"
+"0xffffffff"
+
+# Hex digits
+"0123456789"
+"abcdef"
+"ABCDEF"
+
+# Large numbers
+"2147483647"
+"2147483648"
+"4294967295"
+"9223372036854775807"
+
+# Edge cases
+"00"
+"0x0"
+"0x00"
+" "
+"\x09"
+"\x0a"

+ 48 - 0
Tests/Fuzzing/cmExprParserFuzzer.cxx

@@ -0,0 +1,48 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+/*
+ * Fuzzer for CMake's math expression parser
+ *
+ * The math() command uses cmExprParserHelper to evaluate mathematical
+ * expressions. This fuzzer tests the expression parser for crashes,
+ * hangs, and undefined behavior.
+ *
+ * Coverage targets:
+ * - Integer arithmetic parsing
+ * - Operator precedence handling
+ * - Parentheses nesting
+ * - Error handling for invalid expressions
+ */
+
+#include <cstddef>
+#include <cstdint>
+#include <string>
+
+#include "cmExprParserHelper.h"
+
+// Limit input size to prevent DoS via deeply nested expressions
+static constexpr size_t kMaxInputSize = 4096;
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
+{
+  if (size == 0 || size > kMaxInputSize) {
+    return 0;
+  }
+
+  // Create null-terminated string
+  std::string input(reinterpret_cast<char const*>(data), size);
+
+  cmExprParserHelper helper;
+
+  // Parse with different verbosity levels
+  int result = helper.ParseString(input.c_str(), 0);
+  (void)result;
+
+  // Always check result and error accessors
+  (void)helper.GetResult();
+  (void)helper.GetError();
+  (void)helper.GetWarning();
+
+  return 0;
+}

+ 43 - 0
Tests/Fuzzing/cmFileLock.dict

@@ -0,0 +1,43 @@
+# CMake file lock dictionary
+# Path components
+"/"
+"\\"
+"./"
+"../"
+"~/"
+
+# Common lock file names
+"lock"
+".lock"
+"lockfile"
+".lockfile"
+"cmake.lock"
+"CMakeCache.txt.lock"
+
+# Path patterns
+"/tmp/"
+"/var/lock/"
+"/run/lock/"
+
+# File extensions
+".lock"
+".lck"
+".pid"
+
+# Special paths
+"/dev/null"
+"/dev/zero"
+"NUL"
+"CON"
+"PRN"
+
+# Edge cases (space, dot, dotdot, null, newline, cr)
+" "
+"."
+".."
+"\x00"
+"\x0a"
+"\x0d"
+
+# Long path components
+"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"

+ 147 - 0
Tests/Fuzzing/cmFileLockFuzzer.cxx

@@ -0,0 +1,147 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+/*
+ * Fuzzer for CMake's file(LOCK) command
+ *
+ * The file(LOCK) command manages file locks for synchronization.
+ * This fuzzer tests various lock scenarios and argument combinations.
+ *
+ * Coverage targets:
+ * - Lock acquisition (LOCK)
+ * - Lock release (RELEASE)
+ * - Guard modes (FUNCTION, FILE, PROCESS)
+ * - Timeout handling
+ * - Error paths
+ *
+ * Security focus:
+ * - Symlink handling (CVE for data destruction)
+ * - Path traversal in lock paths
+ * - Race conditions
+ */
+
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <cstring>
+#include <string>
+
+#include <unistd.h>
+
+#include "cmFileLock.h"
+#include "cmFileLockResult.h"
+#include "cmSystemTools.h"
+
+// Limit input size
+static constexpr size_t kMaxInputSize = 4096;
+
+// Sandbox directory
+static std::string g_testDir;
+
+extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
+{
+  (void)argc;
+  (void)argv;
+
+  // Create unique test directory
+  char tmpl[] = "/tmp/cmake_fuzz_lock_XXXXXX";
+  char* dir = mkdtemp(tmpl);
+  if (dir) {
+    g_testDir = dir;
+  } else {
+    g_testDir = "/tmp/cmake_fuzz_lock";
+    cmSystemTools::MakeDirectory(g_testDir);
+  }
+
+  return 0;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
+{
+  if (size < 1 || size > kMaxInputSize) {
+    return 0;
+  }
+
+  // Use first byte for flags
+  uint8_t flags = data[0];
+
+  // Create a test file with known content
+  std::string testFile = g_testDir + "/lock_target.txt";
+  std::string lockFile = g_testDir + "/test.lock";
+  char const* testContent = "IMPORTANT DATA - MUST NOT BE TRUNCATED";
+
+  {
+    FILE* fp = fopen(testFile.c_str(), "w");
+    if (!fp)
+      return 0;
+    fputs(testContent, fp);
+    fclose(fp);
+  }
+
+  // Test different scenarios based on fuzz input
+  cmFileLock lock;
+
+  // Vary the lock file path based on remaining input
+  std::string lockPath = lockFile;
+  if (size > 1 && (flags & 0x01)) {
+    // Use part of input as filename suffix (sanitized)
+    size_t nameLen = std::min(size - 1, size_t(32));
+    std::string suffix;
+    for (size_t i = 0; i < nameLen; ++i) {
+      char c = static_cast<char>(data[1 + i]);
+      // Only allow safe filename characters
+      if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
+          (c >= '0' && c <= '9') || c == '_' || c == '-') {
+        suffix += c;
+      }
+    }
+    if (!suffix.empty()) {
+      lockPath = g_testDir + "/" + suffix + ".lock";
+    }
+  }
+
+  // Test symlink scenario (security-critical)
+  if (flags & 0x02) {
+    // Create a symlink to the test file
+    std::string symlinkPath = g_testDir + "/symlink.lock";
+    unlink(symlinkPath.c_str());
+    if (symlink(testFile.c_str(), symlinkPath.c_str()) == 0) {
+      lockPath = symlinkPath;
+    }
+  }
+
+  // Determine timeout - use 0 for fuzzing to avoid blocking
+  // (non-zero timeouts would stall the fuzzer)
+  unsigned long timeout = 0;
+
+  // Try to acquire lock
+  cmFileLockResult result = lock.Lock(lockPath, timeout);
+  (void)result.IsOk();
+
+  // Always try to release
+  (void)lock.Release();
+
+  // Security check: Verify test file wasn't truncated
+  {
+    FILE* fp = fopen(testFile.c_str(), "r");
+    if (fp) {
+      char buffer[256] = { 0 };
+      size_t bytesRead = fread(buffer, 1, sizeof(buffer) - 1, fp);
+      fclose(fp);
+
+      if (bytesRead == 0 || strcmp(buffer, testContent) != 0) {
+        // DATA DESTRUCTION DETECTED!
+        fprintf(stderr, "VULNERABILITY: File was truncated or modified!\n");
+        fprintf(stderr, "Expected: '%s'\n", testContent);
+        fprintf(stderr, "Got: '%s' (%zu bytes)\n", buffer, bytesRead);
+        abort();
+      }
+    }
+  }
+
+  // Cleanup
+  unlink(lockPath.c_str());
+  unlink((g_testDir + "/symlink.lock").c_str());
+
+  return 0;
+}

+ 45 - 0
Tests/Fuzzing/cmGccDepfile.dict

@@ -0,0 +1,45 @@
+# GCC depfile dictionary
+
+# Target separator
+":"
+
+# Dependency continuation
+"\\"
+
+# Whitespace
+" "
+"\x09"
+"\x0a"
+
+# Common file extensions
+".o"
+".obj"
+".d"
+".cpp"
+".c"
+".h"
+".hpp"
+".hxx"
+
+# Escape sequences
+"\\ "
+"\\#"
+"\\:"
+
+# Special characters
+"#"
+"$"
+
+# Common paths
+"/usr/include/"
+"/usr/local/include/"
+"../include/"
+"./src/"
+
+# Common headers
+"stdio.h"
+"stdlib.h"
+"string.h"
+"iostream"
+"vector"
+"string"

+ 76 - 0
Tests/Fuzzing/cmGccDepfileFuzzer.cxx

@@ -0,0 +1,76 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+/*
+ * Fuzzer for CMake's GCC dependency file parser
+ *
+ * GCC generates .d files with make-style dependencies.
+ * This fuzzer tests parsing of these files.
+ */
+
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <string>
+
+#include <unistd.h>
+
+#include "cmGccDepfileReader.h"
+#include "cmSystemTools.h"
+
+static constexpr size_t kMaxInputSize = 256 * 1024;
+static std::string g_testDir;
+
+extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
+{
+  (void)argc;
+  (void)argv;
+
+  char tmpl[] = "/tmp/cmake_fuzz_depfile_XXXXXX";
+  char* dir = mkdtemp(tmpl);
+  if (dir) {
+    g_testDir = dir;
+  } else {
+    g_testDir = "/tmp/cmake_fuzz_depfile";
+    cmSystemTools::MakeDirectory(g_testDir);
+  }
+
+  return 0;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
+{
+  if (size == 0 || size > kMaxInputSize) {
+    return 0;
+  }
+
+  // Write input to temp file
+  std::string depFile = g_testDir + "/test.d";
+  {
+    FILE* fp = fopen(depFile.c_str(), "wb");
+    if (!fp)
+      return 0;
+    fwrite(data, 1, size, fp);
+    fclose(fp);
+  }
+
+  // Parse the depfile
+  auto result = cmReadGccDepfile(depFile.c_str());
+
+  // Examine results if parsing succeeded
+  if (result) {
+    for (auto const& entry : *result) {
+      for (auto const& rule : entry.rules) {
+        (void)rule;
+      }
+      for (auto const& path : entry.paths) {
+        (void)path;
+      }
+    }
+  }
+
+  // Clean up
+  unlink(depFile.c_str());
+
+  return 0;
+}

+ 84 - 0
Tests/Fuzzing/cmGeneratorExpression.dict

@@ -0,0 +1,84 @@
+# CMake Generator Expression Dictionary
+
+# Basic syntax
+"$<"
+">"
+":"
+","
+
+# Boolean expressions
+"$<BOOL:"
+"$<AND:"
+"$<OR:"
+"$<NOT:"
+"$<IF:"
+"$<0:"
+"$<1:"
+
+# String operations
+"$<STREQUAL:"
+"$<EQUAL:"
+"$<IN_LIST:"
+"$<LOWER_CASE:"
+"$<UPPER_CASE:"
+"$<MAKE_C_IDENTIFIER:"
+"$<JOIN:"
+"$<REMOVE_DUPLICATES:"
+"$<FILTER:"
+"$<GENEX_EVAL:"
+
+# Version comparisons
+"$<VERSION_LESS:"
+"$<VERSION_GREATER:"
+"$<VERSION_EQUAL:"
+"$<VERSION_LESS_EQUAL:"
+"$<VERSION_GREATER_EQUAL:"
+
+# Target operations
+"$<TARGET_FILE:"
+"$<TARGET_FILE_NAME:"
+"$<TARGET_FILE_DIR:"
+"$<TARGET_FILE_BASE_NAME:"
+"$<TARGET_LINKER_FILE:"
+"$<TARGET_SONAME_FILE:"
+"$<TARGET_PDB_FILE:"
+"$<TARGET_PROPERTY:"
+"$<TARGET_OBJECTS:"
+"$<TARGET_BUNDLE_DIR:"
+"$<TARGET_BUNDLE_CONTENT_DIR:"
+"$<TARGET_EXISTS:"
+"$<TARGET_NAME_IF_EXISTS:"
+"$<TARGET_POLICY:"
+
+# Config/Platform
+"$<CONFIG:"
+"$<PLATFORM_ID:"
+"$<COMPILE_LANGUAGE:"
+"$<LINK_LANGUAGE:"
+"$<COMPILE_LANG_AND_ID:"
+"$<LINK_LANG_AND_ID:"
+"$<C_COMPILER_ID:"
+"$<CXX_COMPILER_ID:"
+"$<CUDA_COMPILER_ID:"
+
+# Interface expressions
+"$<BUILD_INTERFACE:"
+"$<INSTALL_INTERFACE:"
+"$<INSTALL_PREFIX>"
+
+# Output expressions
+"$<TARGET_NAME:"
+"$<LINK_ONLY:"
+"$<COMPILE_ONLY:"
+
+# Special
+"$<ANGLE-R>"
+"$<COMMA>"
+"$<SEMICOLON>"
+
+# Nesting patterns
+"$<$<"
+">>"
+"::"
+",,"
+"$<IF:$<"

+ 88 - 0
Tests/Fuzzing/cmGeneratorExpressionFuzzer.cxx

@@ -0,0 +1,88 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+/*
+ * Fuzzer for CMake's Generator Expression parser
+ *
+ * Generator expressions ($<...>) are evaluated at build-system generation
+ * time. This fuzzer targets the lexer and static parsing utilities that don't
+ * require full cmake context.
+ *
+ * Coverage targets:
+ * - Generator expression lexer (cmGeneratorExpressionLexer)
+ * - Static parsing/preprocessing functions
+ * - Nested expression handling
+ * - Expression validation
+ */
+
+#include <cstddef>
+#include <cstdint>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorExpressionLexer.h"
+
+// Limit input size - genex can be exponential in nested cases
+static constexpr size_t kMaxInputSize = 16 * 1024; // 16KB
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
+{
+  if (size == 0 || size > kMaxInputSize) {
+    return 0;
+  }
+
+  std::string input(reinterpret_cast<char const*>(data), size);
+
+  // Test the lexer directly
+  {
+    cmGeneratorExpressionLexer lexer;
+    auto tokens = lexer.Tokenize(input);
+    (void)tokens;
+  }
+
+  // Test static utility functions that don't need cmake context
+  {
+    // Find generator expressions
+    auto pos = cmGeneratorExpression::Find(input);
+    (void)pos;
+
+    // Check if starts with genex
+    bool starts = cmGeneratorExpression::StartsWithGeneratorExpression(input);
+    (void)starts;
+
+    // Validate as target name
+    bool valid = cmGeneratorExpression::IsValidTargetName(input);
+    (void)valid;
+
+    // Strip empty list elements
+    std::string stripped =
+      cmGeneratorExpression::StripEmptyListElements(input);
+    (void)stripped;
+
+    // Split expressions
+    std::vector<std::string> output;
+    cmGeneratorExpression::Split(input, output);
+
+    // Preprocess with different contexts
+    std::string preprocessed1 = cmGeneratorExpression::Preprocess(
+      input, cmGeneratorExpression::StripAllGeneratorExpressions);
+    (void)preprocessed1;
+
+    std::string preprocessed2 = cmGeneratorExpression::Preprocess(
+      input, cmGeneratorExpression::BuildInterface);
+    (void)preprocessed2;
+
+    std::string preprocessed3 = cmGeneratorExpression::Preprocess(
+      input, cmGeneratorExpression::InstallInterface);
+    (void)preprocessed3;
+
+    // Collect expressions
+    std::map<std::string, std::vector<std::string>> collected;
+    std::string collResult = cmGeneratorExpression::Collect(input, collected);
+    (void)collResult;
+  }
+
+  return 0;
+}

+ 50 - 0
Tests/Fuzzing/cmGlob.dict

@@ -0,0 +1,50 @@
+# CMake glob pattern dictionary
+# Basic wildcards
+"*"
+"?"
+"**"
+
+# Character classes
+"[a-z]"
+"[A-Z]"
+"[0-9]"
+"[a-zA-Z]"
+"[a-zA-Z0-9]"
+"[!a-z]"
+"[^a-z]"
+"[]"
+"[]]"
+"[[]"
+
+# Common patterns
+"*.txt"
+"*.cmake"
+"*.c"
+"*.cpp"
+"*.cxx"
+"*.h"
+"*.hpp"
+"*.hxx"
+"**/*.cmake"
+"**/CMakeLists.txt"
+
+# Path separators
+"/"
+"\\"
+"./"
+"../"
+"/"
+
+# Special characters
+"."
+".."
+"~"
+
+# Brace expansion (if supported)
+"{a,b}"
+"{*.c,*.h}"
+
+# Edge cases (space, tab, newline)
+" "
+"\x09"
+"\x0a"

+ 69 - 0
Tests/Fuzzing/cmGlobFuzzer.cxx

@@ -0,0 +1,69 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+/*
+ * Fuzzer for CMake's glob/regex matching
+ *
+ * Tests glob pattern matching and regex compilation.
+ */
+
+#include <cstddef>
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#include "cmsys/Glob.hxx"
+#include "cmsys/RegularExpression.hxx"
+
+#include "cmSystemTools.h"
+
+static constexpr size_t kMaxInputSize = 4096;
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
+{
+  if (size == 0 || size > kMaxInputSize) {
+    return 0;
+  }
+
+  std::string input(reinterpret_cast<char const*>(data), size);
+
+  // Test glob pattern matching
+  {
+    cmsys::Glob glob;
+    glob.SetRecurse(false);
+    glob.SetRelative("/tmp");
+
+    // Try to find files matching the pattern (safe - just pattern matching)
+    // Don't actually recurse filesystem, just test pattern parsing
+    (void)glob.GetFiles();
+  }
+
+  // Test regex compilation (may throw on invalid patterns)
+  {
+    cmsys::RegularExpression regex;
+    bool compiled = regex.compile(input);
+    if (compiled) {
+      // Test matching against some strings
+      (void)regex.find("test string");
+      (void)regex.find(input);
+      (void)regex.find("");
+    }
+  }
+
+  // Test string matching utilities
+  (void)cmSystemTools::StringStartsWith(input, "CMAKE_");
+  (void)cmSystemTools::StringEndsWith(input, ".cmake");
+
+  // Test simple pattern matching
+  if (size >= 4) {
+    std::string pattern(reinterpret_cast<char const*>(data), size / 2);
+    std::string text(reinterpret_cast<char const*>(data + size / 2),
+                     size - size / 2);
+    // Pattern matching is done through Glob::FindFiles, which we avoid
+    // to prevent filesystem access. Just test string operations.
+    (void)pattern.length();
+    (void)text.length();
+  }
+
+  return 0;
+}

+ 72 - 0
Tests/Fuzzing/cmJSONParser.dict

@@ -0,0 +1,72 @@
+# JSON Parser Dictionary
+
+# Structure
+"{"
+"}"
+"["
+"]"
+":"
+","
+
+# Values
+"true"
+"false"
+"null"
+
+# Strings
+"\""
+"\\"
+"\\x0a"
+"\\x0d"
+"\\x09"
+"\\u"
+"\\u0000"
+"\\uFFFF"
+
+# Numbers
+"0"
+"1"
+"-1"
+"0.0"
+"1.0"
+"-1.0"
+"1e10"
+"1E10"
+"1e-10"
+"1e+10"
+"1.5e10"
+
+# Whitespace
+" "
+"\x09"
+"\x0a"
+"\x0d"
+
+# Common CMake preset keys
+"version"
+"cmakeMinimumRequired"
+"configurePresets"
+"buildPresets"
+"testPresets"
+"packagePresets"
+"workflowPresets"
+"name"
+"hidden"
+"inherits"
+"displayName"
+"description"
+"generator"
+"binaryDir"
+"cacheVariables"
+"environment"
+"condition"
+"vendor"
+
+# Common values
+"Ninja"
+"Unix Makefiles"
+"Visual Studio"
+"Debug"
+"Release"
+"RelWithDebInfo"
+"MinSizeRel"

+ 107 - 0
Tests/Fuzzing/cmJSONParserFuzzer.cxx

@@ -0,0 +1,107 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+/*
+ * Fuzzer for CMake's JSON parsing (via jsoncpp)
+ *
+ * CMake parses JSON files for CMakePresets.json, compile_commands.json,
+ * and various other configuration files. This fuzzer tests the JSON
+ * parser for crashes and undefined behavior.
+ *
+ * Coverage targets:
+ * - JSON value parsing (strings, numbers, booleans, null)
+ * - Array and object parsing
+ * - Nested structures
+ * - Unicode handling
+ * - Error recovery
+ */
+
+#include <cstddef>
+#include <cstdint>
+#include <sstream>
+#include <string>
+
+#include <cm3p/json/reader.h>
+#include <cm3p/json/value.h>
+
+// Limit input size
+static constexpr size_t kMaxInputSize = 256 * 1024; // 256KB
+
+// Recursive helper to access all values (exercises accessor code)
+static void TraverseValue(Json::Value const& value, int depth = 0)
+{
+  // Prevent stack overflow on deeply nested structures
+  if (depth > 100) {
+    return;
+  }
+
+  switch (value.type()) {
+    case Json::nullValue:
+      (void)value.isNull();
+      break;
+    case Json::intValue:
+      (void)value.asInt64();
+      break;
+    case Json::uintValue:
+      (void)value.asUInt64();
+      break;
+    case Json::realValue:
+      (void)value.asDouble();
+      break;
+    case Json::stringValue:
+      (void)value.asString();
+      break;
+    case Json::booleanValue:
+      (void)value.asBool();
+      break;
+    case Json::arrayValue:
+      for (Json::ArrayIndex i = 0; i < value.size() && i < 1000; ++i) {
+        TraverseValue(value[i], depth + 1);
+      }
+      break;
+    case Json::objectValue:
+      for (auto const& name : value.getMemberNames()) {
+        (void)name;
+        TraverseValue(value[name], depth + 1);
+      }
+      break;
+  }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
+{
+  if (size == 0 || size > kMaxInputSize) {
+    return 0;
+  }
+
+  std::string input(reinterpret_cast<char const*>(data), size);
+
+  Json::Value root;
+  Json::CharReaderBuilder builder;
+  std::string errors;
+
+  std::istringstream stream(input);
+
+  // Try parsing with default settings
+  bool success = Json::parseFromStream(builder, stream, &root, &errors);
+
+  if (success) {
+    // Traverse the parsed structure
+    TraverseValue(root);
+  }
+
+  // Also try with strict mode
+  builder["strictRoot"] = true;
+  builder["allowComments"] = false;
+  builder["allowTrailingCommas"] = false;
+
+  stream.clear();
+  stream.str(input);
+
+  success = Json::parseFromStream(builder, stream, &root, &errors);
+  if (success) {
+    TraverseValue(root);
+  }
+
+  return 0;
+}

+ 108 - 0
Tests/Fuzzing/cmListFileLexer.dict

@@ -0,0 +1,108 @@
+# CMake ListFile Lexer Dictionary
+# Keywords and syntax for CMakeLists.txt files
+
+# Common commands
+"cmake_minimum_required"
+"project"
+"add_executable"
+"add_library"
+"target_link_libraries"
+"target_include_directories"
+"target_compile_definitions"
+"target_compile_options"
+"set"
+"unset"
+"if"
+"elseif"
+"else"
+"endif"
+"foreach"
+"endforeach"
+"while"
+"endwhile"
+"function"
+"endfunction"
+"macro"
+"endmacro"
+"return"
+"include"
+"find_package"
+"find_library"
+"find_path"
+"find_program"
+"file"
+"message"
+"option"
+"configure_file"
+"install"
+"add_custom_command"
+"add_custom_target"
+"add_subdirectory"
+"list"
+"string"
+"math"
+"get_property"
+"set_property"
+"get_target_property"
+"set_target_properties"
+"add_definitions"
+"add_dependencies"
+
+# Syntax elements
+"("
+")"
+"\""
+"[["
+"]]"
+"[=["
+"]=]"
+"[==["
+"]==]"
+"#"
+"#[["
+"#]]"
+"\x0a"
+"\x0d\x0a"
+" "
+"\x09"
+"$"
+"{"
+"}"
+"<"
+">"
+";"
+":"
+"@"
+"\\"
+
+# Variables
+"${CMAKE_SOURCE_DIR}"
+"${CMAKE_BINARY_DIR}"
+"${CMAKE_CURRENT_SOURCE_DIR}"
+"${CMAKE_CURRENT_BINARY_DIR}"
+"${PROJECT_NAME}"
+"${PROJECT_SOURCE_DIR}"
+"${PROJECT_BINARY_DIR}"
+"$ENV{}"
+"$CACHE{}"
+
+# Generator expressions
+"$<"
+">:"
+"$<TARGET_FILE:"
+"$<TARGET_PROPERTY:"
+"$<BUILD_INTERFACE:"
+"$<INSTALL_INTERFACE:"
+"$<BOOL:"
+"$<AND:"
+"$<OR:"
+"$<NOT:"
+"$<IF:"
+"$<STREQUAL:"
+"$<VERSION_LESS:"
+"$<CONFIG:"
+
+# BOMs
+"\xef\xbb\xbf"
+"\xff\xfe"
+"\xfe\xff"

+ 62 - 0
Tests/Fuzzing/cmListFileLexerFuzzer.cxx

@@ -0,0 +1,62 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+/*
+ * Fuzzer for CMake's ListFile lexer (CMakeLists.txt parser)
+ *
+ * This fuzzer targets cmListFileLexer which tokenizes CMakeLists.txt files.
+ * It's a critical attack surface as malicious CMakeLists.txt files could be
+ * encountered when building untrusted projects.
+ *
+ * Coverage targets:
+ * - Token parsing (identifiers, strings, brackets, comments)
+ * - BOM handling (UTF-8, UTF-16, UTF-32)
+ * - Bracket argument/comment parsing
+ * - Error recovery for malformed input
+ */
+
+#include <cstddef>
+#include <cstdint>
+
+#include "cmListFileLexer.h"
+
+// Limit input size to avoid timeouts on complex inputs
+static constexpr size_t kMaxInputSize = 64 * 1024; // 64KB
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
+{
+  // Skip overly large inputs
+  if (size == 0 || size > kMaxInputSize) {
+    return 0;
+  }
+
+  cmListFileLexer* lexer = cmListFileLexer_New();
+  if (!lexer) {
+    return 0;
+  }
+
+  // Parse from string (not file) for efficiency
+  if (cmListFileLexer_SetString(lexer, reinterpret_cast<char const*>(data),
+                                size)) {
+    // Consume all tokens until EOF or error
+    cmListFileLexer_Token* token;
+    while ((token = cmListFileLexer_Scan(lexer)) != nullptr) {
+      // Access token fields to ensure they're valid
+      (void)token->type;
+      (void)token->text;
+      (void)token->length;
+      (void)token->line;
+      (void)token->column;
+
+      // Get type as string for additional coverage
+      (void)cmListFileLexer_GetTypeAsString(lexer, token->type);
+    }
+
+    // Exercise position tracking
+    (void)cmListFileLexer_GetCurrentLine(lexer);
+    (void)cmListFileLexer_GetCurrentColumn(lexer);
+  }
+
+  cmListFileLexer_Delete(lexer);
+  return 0;
+}

+ 84 - 0
Tests/Fuzzing/cmListFileParserFuzzer.cxx

@@ -0,0 +1,84 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+/*
+ * Fuzzer for CMake's list file parser (CMakeLists.txt full parsing)
+ *
+ * This fuzzer tests the complete parsing of CMake files including:
+ * - Command parsing
+ * - Argument handling
+ * - Bracket arguments
+ * - Comments
+ * - Line continuations
+ */
+
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <string>
+
+#include <unistd.h>
+
+#include "cmListFileCache.h"
+#include "cmMessenger.h"
+#include "cmSystemTools.h"
+
+static constexpr size_t kMaxInputSize = 256 * 1024;
+static std::string g_testDir;
+
+extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
+{
+  (void)argc;
+  (void)argv;
+
+  char tmpl[] = "/tmp/cmake_fuzz_listfile_XXXXXX";
+  char* dir = mkdtemp(tmpl);
+  if (dir) {
+    g_testDir = dir;
+  } else {
+    g_testDir = "/tmp/cmake_fuzz_listfile";
+    cmSystemTools::MakeDirectory(g_testDir);
+  }
+
+  return 0;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
+{
+  if (size == 0 || size > kMaxInputSize) {
+    return 0;
+  }
+
+  // Write input to temp file
+  std::string testFile = g_testDir + "/CMakeLists.txt";
+  {
+    FILE* fp = fopen(testFile.c_str(), "wb");
+    if (!fp)
+      return 0;
+    fwrite(data, 1, size, fp);
+    fclose(fp);
+  }
+
+  // Create a messenger for error handling
+  cmMessenger messenger;
+
+  // Parse the file
+  cmListFile listFile;
+  cmListFileBacktrace backtrace;
+  if (listFile.ParseFile(testFile.c_str(), &messenger, backtrace)) {
+    // Successfully parsed - examine results
+    for (auto const& func : listFile.Functions) {
+      (void)func.LowerCaseName();
+      (void)func.OriginalName();
+      for (auto const& arg : func.Arguments()) {
+        (void)arg.Value;
+        (void)arg.Delim;
+      }
+    }
+  }
+
+  // Clean up
+  unlink(testFile.c_str());
+
+  return 0;
+}

+ 63 - 0
Tests/Fuzzing/cmPkgConfigParser.dict

@@ -0,0 +1,63 @@
+# pkg-config File Dictionary
+
+# Key-value separators
+"="
+":"
+
+# Variable reference
+"${"
+"}"
+
+# Common keywords
+"Name"
+"Description"
+"Version"
+"Requires"
+"Requires.private"
+"Conflicts"
+"Libs"
+"Libs.private"
+"Cflags"
+"URL"
+
+# Common variables
+"prefix"
+"exec_prefix"
+"libdir"
+"includedir"
+"datarootdir"
+"datadir"
+"sysconfdir"
+"sharedstatedir"
+"localstatedir"
+
+# Common values
+"/usr"
+"/usr/local"
+"/usr/lib"
+"/usr/include"
+"-I"
+"-L"
+"-l"
+"-D"
+"-pthread"
+
+# Whitespace
+" "
+"\x09"
+"\x0a"
+"\x0d\x0a"
+
+# Comments
+"#"
+
+# Version operators
+">="
+"<="
+">"
+"<"
+"!="
+
+# Escapes
+"\\"
+"\\$"

+ 59 - 0
Tests/Fuzzing/cmPkgConfigParserFuzzer.cxx

@@ -0,0 +1,59 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+/*
+ * Fuzzer for CMake's pkg-config file parser
+ *
+ * CMake parses .pc files (pkg-config) when using PkgConfig find module.
+ * Malformed .pc files from untrusted sources could trigger vulnerabilities.
+ *
+ * Coverage targets:
+ * - Variable definitions (key=value)
+ * - Keyword definitions (key: value)
+ * - Variable references (${var})
+ * - Multi-line handling
+ * - Comment handling
+ */
+
+#include <cstddef>
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#include "cmPkgConfigParser.h"
+
+// Limit input size
+static constexpr size_t kMaxInputSize = 64 * 1024; // 64KB
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
+{
+  if (size == 0 || size > kMaxInputSize) {
+    return 0;
+  }
+
+  // cmPkgConfigParser::Parse takes non-const buffer (may modify in place)
+  std::vector<char> buffer(data, data + size);
+
+  cmPkgConfigParser parser;
+
+  // Parse the input
+  auto result = parser.Parse(buffer.data(), buffer.size());
+  (void)result;
+
+  // Finish parsing
+  result = parser.Finish();
+  (void)result;
+
+  // Access parsed data to exercise accessors
+  auto& entries = parser.Data();
+  for (auto const& entry : entries) {
+    (void)entry.IsVariable;
+    (void)entry.Key;
+    for (auto const& elem : entry.Val) {
+      (void)elem.IsVariable;
+      (void)elem.Data;
+    }
+  }
+
+  return 0;
+}

+ 193 - 0
Tests/Fuzzing/cmScript.dict

@@ -0,0 +1,193 @@
+# CMake script dictionary - comprehensive command coverage
+
+# Basic structure
+"("
+")"
+"\x0a"
+" "
+"\x09"
+
+# Comments
+"#"
+"#[["
+"]]"
+
+# Quotes and brackets
+"\""
+"[["
+"]]"
+"[=["
+"]=]"
+
+# Variable references
+"$"
+"${"
+"}"
+"${}"
+"$ENV{"
+"$CACHE{"
+
+# Generator expressions
+"$<"
+">"
+"$<BOOL:"
+"$<AND:"
+"$<OR:"
+"$<NOT:"
+"$<IF:"
+"$<STREQUAL:"
+"$<VERSION_LESS:"
+"$<TARGET_FILE:"
+
+# Core commands
+"cmake_minimum_required"
+"project"
+"set"
+"unset"
+"message"
+"return"
+"include"
+
+# Variable commands
+"option"
+"mark_as_advanced"
+"separate_arguments"
+
+# Control flow
+"if"
+"elseif"
+"else"
+"endif"
+"foreach"
+"endforeach"
+"while"
+"endwhile"
+"break"
+"continue"
+"function"
+"endfunction"
+"macro"
+"endmacro"
+"block"
+"endblock"
+
+# String operations
+"string"
+"LENGTH"
+"SUBSTRING"
+"FIND"
+"REPLACE"
+"REGEX"
+"MATCH"
+"MATCHALL"
+"TOUPPER"
+"TOLOWER"
+"STRIP"
+"GENEX_STRIP"
+"APPEND"
+"PREPEND"
+"CONCAT"
+"JOIN"
+"COMPARE"
+"MD5"
+"SHA1"
+"SHA256"
+"MAKE_C_IDENTIFIER"
+"RANDOM"
+"TIMESTAMP"
+"UUID"
+"JSON"
+
+# List operations
+"list"
+"GET"
+"APPEND"
+"PREPEND"
+"INSERT"
+"FILTER"
+"REMOVE_ITEM"
+"REMOVE_AT"
+"REMOVE_DUPLICATES"
+"REVERSE"
+"SORT"
+"TRANSFORM"
+"SUBLIST"
+"POP_BACK"
+"POP_FRONT"
+
+# Math
+"math"
+"EXPR"
+
+# File operations
+"file"
+"READ"
+"STRINGS"
+"WRITE"
+"APPEND"
+"GLOB"
+"GLOB_RECURSE"
+"RENAME"
+"REMOVE"
+"MAKE_DIRECTORY"
+"RELATIVE_PATH"
+"TO_CMAKE_PATH"
+"TO_NATIVE_PATH"
+"DOWNLOAD"
+"UPLOAD"
+"COPY"
+"INSTALL"
+"SIZE"
+"READ_SYMLINK"
+"CREATE_LINK"
+"CHMOD"
+"TOUCH"
+"GENERATE"
+"CONFIGURE"
+"ARCHIVE_CREATE"
+"ARCHIVE_EXTRACT"
+
+# Conditionals
+"DEFINED"
+"COMMAND"
+"POLICY"
+"TARGET"
+"TEST"
+"EXISTS"
+"IS_DIRECTORY"
+"IS_SYMLINK"
+"IS_ABSOLUTE"
+"MATCHES"
+"LESS"
+"GREATER"
+"EQUAL"
+"STRLESS"
+"STRGREATER"
+"STREQUAL"
+"VERSION_LESS"
+"VERSION_GREATER"
+"VERSION_EQUAL"
+"AND"
+"OR"
+"NOT"
+"IN_LIST"
+
+# Common values
+"TRUE"
+"FALSE"
+"ON"
+"OFF"
+"YES"
+"NO"
+"STATUS"
+"WARNING"
+"FATAL_ERROR"
+"SEND_ERROR"
+"PARENT_SCOPE"
+"CACHE"
+"FORCE"
+"INTERNAL"
+"STRING"
+"BOOL"
+"PATH"
+"FILEPATH"

+ 147 - 0
Tests/Fuzzing/cmScriptFuzzer.cxx

@@ -0,0 +1,147 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+/*
+ * Fuzzer for CMake script execution
+ *
+ * This fuzzer executes CMake scripts in script mode (-P).
+ * This exercises the majority of CMake's codebase including:
+ * - All built-in commands
+ * - Variable expansion
+ * - Control flow (if, foreach, while, function, macro)
+ * - String/list/file operations
+ * - Generator expressions
+ *
+ * This is the highest-impact fuzzer for coverage.
+ *
+ * Performance notes:
+ * - Uses memfd_create on Linux for memory-backed file I/O
+ * - Falls back to temp files on other platforms
+ */
+
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <string>
+#include <vector>
+
+#include <unistd.h>
+
+#include "cmCMakePolicyCommand.h"
+#include "cmExecutionStatus.h"
+#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
+#include "cmMessenger.h"
+#include "cmState.h"
+#include "cmStateSnapshot.h"
+#include "cmSystemTools.h"
+#include "cmake.h"
+
+#ifdef __linux__
+#  include <sys/mman.h>
+#  ifndef MFD_CLOEXEC
+#    define MFD_CLOEXEC 0x0001U
+#  endif
+#endif
+
+static constexpr size_t kMaxInputSize = 256 * 1024;
+static std::string g_testDir;
+static std::string g_scriptFile;
+static bool g_useMemfd = false;
+
+extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
+{
+  (void)argc;
+  (void)argv;
+
+  // Suppress output during fuzzing (set once at init)
+  cmSystemTools::SetMessageCallback(
+    [](std::string const&, cmMessageMetadata const&) {});
+  cmSystemTools::SetStdoutCallback([](std::string const&) {});
+  cmSystemTools::SetStderrCallback([](std::string const&) {});
+
+  // Create unique test directory (even with memfd, scripts can create files)
+  char tmpl[] = "/tmp/cmake_fuzz_script_XXXXXX";
+  char* dir = mkdtemp(tmpl);
+  if (dir) {
+    g_testDir = dir;
+  } else {
+    g_testDir = "/tmp/cmake_fuzz_script";
+    cmSystemTools::MakeDirectory(g_testDir);
+  }
+
+#ifdef __linux__
+  // Try to use memfd for better performance
+  int fd = memfd_create("cmake_fuzz", MFD_CLOEXEC);
+  if (fd >= 0) {
+    g_useMemfd = true;
+    // Create path via /proc/self/fd
+    g_scriptFile = "/proc/self/fd/" + std::to_string(fd);
+    // Keep fd open - will be reused
+  } else
+#endif
+  {
+    g_scriptFile = g_testDir + "/fuzz_script.cmake";
+  }
+
+  return 0;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
+{
+  if (size == 0 || size > kMaxInputSize) {
+    return 0;
+  }
+
+#ifdef __linux__
+  if (g_useMemfd) {
+    // Extract fd from path and write directly
+    int fd = std::atoi(g_scriptFile.c_str() + 14); // "/proc/self/fd/"
+    ftruncate(fd, 0);
+    lseek(fd, 0, SEEK_SET);
+    if (write(fd, data, size) != static_cast<ssize_t>(size)) {
+      return 0;
+    }
+  } else
+#endif
+  {
+    // Write script to temp file
+    FILE* fp = fopen(g_scriptFile.c_str(), "wb");
+    if (!fp)
+      return 0;
+    fwrite(data, 1, size, fp);
+    fclose(fp);
+  }
+
+  // Save CWD in case script uses file(CHDIR)
+  std::string cwd = cmSystemTools::GetCurrentWorkingDirectory();
+
+  // Create cmake instance for script mode
+  cmake cm(cmState::Role::Script);
+  cm.SetHomeDirectory(g_testDir);
+  cm.SetHomeOutputDirectory(g_testDir);
+
+  // Run the script
+  std::vector<std::string> args;
+  args.push_back("cmake");
+  args.push_back("-P");
+  args.push_back(g_scriptFile);
+
+  (void)cm.Run(args, false);
+
+  // Restore CWD before cleanup (script may have changed it via file(CHDIR))
+  cmSystemTools::ChangeDirectory(cwd);
+
+  // Cleanup temp file (memfd doesn't need cleanup)
+  if (!g_useMemfd) {
+    unlink(g_scriptFile.c_str());
+  }
+
+  // Clean up any files the script may have created in g_testDir
+  // This prevents disk growth and non-determinism from previous iterations
+  cmSystemTools::RemoveADirectory(g_testDir);
+  cmSystemTools::MakeDirectory(g_testDir);
+
+  return 0;
+}

+ 10 - 0
Tests/Fuzzing/cmScriptFuzzer.options

@@ -0,0 +1,10 @@
+[libfuzzer]
+max_len = 262144
+timeout = 30
+rss_limit_mb = 2048
+
+[afl]
+timeout = 30
+
+[honggfuzz]
+timeout = 30

+ 71 - 0
Tests/Fuzzing/cmStringAlgorithms.dict

@@ -0,0 +1,71 @@
+# String algorithms dictionary
+
+# Whitespace
+" "
+"\x09"
+"\x0a"
+"\x0d"
+"\x0d\x0a"
+
+# CMake separators
+";"
+","
+
+# Quotes
+"\""
+"'"
+
+# Escape sequences
+"\\"
+"\\x0a"
+"\\x09"
+"\\x0d"
+"\\;"
+
+# Variable references
+"$"
+"${"
+"}"
+"${}"
+"$ENV{"
+"$CACHE{"
+
+# Generator expressions
+"$<"
+">"
+"$<AND:"
+"$<OR:"
+"$<NOT:"
+"$<IF:"
+"$<TARGET_FILE:"
+"$<TARGET_PROPERTY:"
+
+# Common CMake variables
+"CMAKE_"
+"CMAKE_SOURCE_DIR"
+"CMAKE_BINARY_DIR"
+"CMAKE_CURRENT_SOURCE_DIR"
+"CMAKE_CURRENT_BINARY_DIR"
+"PROJECT_NAME"
+"PROJECT_SOURCE_DIR"
+"PROJECT_BINARY_DIR"
+
+# List operations
+"APPEND"
+"PREPEND"
+"INSERT"
+"REMOVE"
+"FILTER"
+"TRANSFORM"
+
+# String operations
+"TOUPPER"
+"TOLOWER"
+"STRIP"
+"REPLACE"
+"REGEX"
+"MATCH"
+"SUBSTRING"
+"LENGTH"
+"FIND"
+"COMPARE"

+ 75 - 0
Tests/Fuzzing/cmStringAlgorithmsFuzzer.cxx

@@ -0,0 +1,75 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+/*
+ * Fuzzer for CMake's string algorithms
+ *
+ * Tests string manipulation, escaping, and processing functions.
+ */
+
+#include <cstddef>
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#include "cmStringAlgorithms.h"
+#include "cmSystemTools.h"
+
+static constexpr size_t kMaxInputSize = 16 * 1024;
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
+{
+  if (size == 0 || size > kMaxInputSize) {
+    return 0;
+  }
+
+  std::string input(reinterpret_cast<char const*>(data), size);
+
+  // Test string manipulation functions
+  (void)cmTrimWhitespace(input);
+  (void)cmRemoveQuotes(input);
+  (void)cmEscapeQuotes(input);
+
+  // Test case conversion
+  (void)cmSystemTools::UpperCase(input);
+  (void)cmSystemTools::LowerCase(input);
+
+  // Test tokenization
+  std::vector<std::string> tokens = cmTokenize(input, " \t\n\r");
+  (void)tokens.size();
+
+  // Test with different separators if input is large enough
+  if (size > 4) {
+    std::string sep(reinterpret_cast<char const*>(data), 2);
+    std::string str(reinterpret_cast<char const*>(data + 2), size - 2);
+    std::vector<std::string> parts = cmTokenize(str, sep);
+    (void)parts.size();
+  }
+
+  // Test join operations
+  if (!tokens.empty()) {
+    (void)cmJoin(tokens, ";");
+    (void)cmJoin(tokens, ",");
+  }
+
+  // Test string contains
+  if (size > 2) {
+    std::string haystack(reinterpret_cast<char const*>(data), size / 2);
+    std::string needle(reinterpret_cast<char const*>(data + size / 2),
+                       size - size / 2);
+    (void)cmHasPrefix(haystack, needle);
+    (void)cmHasSuffix(haystack, needle);
+  }
+
+  // Test path operations
+  (void)cmSystemTools::GetFilenameWithoutExtension(input);
+  (void)cmSystemTools::GetFilenameExtension(input);
+  (void)cmSystemTools::GetFilenameName(input);
+  (void)cmSystemTools::GetFilenameLastExtension(input);
+  (void)cmSystemTools::GetFilenamePath(input);
+
+  // Test path normalization
+  (void)cmSystemTools::CollapseFullPath(input);
+
+  return 0;
+}

+ 42 - 0
Tests/Fuzzing/cmVersion.dict

@@ -0,0 +1,42 @@
+# Version string dictionary
+
+# Separators
+"."
+"-"
+"+"
+
+# Common versions
+"0"
+"1"
+"2"
+"3"
+"10"
+"99"
+"100"
+"999"
+
+# CMake versions
+"3.28"
+"3.28.0"
+"3.27.0"
+"2.8.12"
+"3.0.0"
+
+# Semantic versioning
+"alpha"
+"beta"
+"rc"
+"rc1"
+"rc2"
+"dev"
+"SNAPSHOT"
+"build"
+"pre"
+"post"
+
+# Edge cases
+"0.0.0"
+"999.999.999"
+"1.0.0-alpha"
+"1.0.0+build"
+"1.0.0-alpha+build"

+ 56 - 0
Tests/Fuzzing/cmVersionFuzzer.cxx

@@ -0,0 +1,56 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file LICENSE.rst or https://cmake.org/licensing for details.  */
+
+/*
+ * Fuzzer for CMake's version comparison
+ *
+ * Tests version string parsing and comparison operations.
+ */
+
+#include <cstddef>
+#include <cstdint>
+#include <string>
+
+#include "cmSystemTools.h"
+#include "cmVersion.h"
+
+static constexpr size_t kMaxInputSize = 1024;
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
+{
+  if (size == 0 || size > kMaxInputSize) {
+    return 0;
+  }
+
+  std::string input(reinterpret_cast<char const*>(data), size);
+
+  // Test version comparison with current CMake version
+  (void)cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, input, "3.28.0");
+  (void)cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER, input,
+                                      "3.28.0");
+  (void)cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL, input,
+                                      "3.28.0");
+  (void)cmSystemTools::VersionCompare(cmSystemTools::OP_LESS_EQUAL, input,
+                                      "3.28.0");
+  (void)cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER_EQUAL, input,
+                                      "3.28.0");
+
+  // Compare against itself
+  (void)cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL, input, input);
+
+  // If input is large enough, compare two different versions from input
+  if (size >= 4) {
+    std::string v1(reinterpret_cast<char const*>(data), size / 2);
+    std::string v2(reinterpret_cast<char const*>(data + size / 2),
+                   size - size / 2);
+    (void)cmSystemTools::VersionCompare(cmSystemTools::OP_LESS, v1, v2);
+    (void)cmSystemTools::VersionCompare(cmSystemTools::OP_GREATER, v1, v2);
+    (void)cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL, v1, v2);
+  }
+
+  // Version compare with greater/less string format
+  (void)cmSystemTools::VersionCompareGreater(input, "1.0.0");
+  (void)cmSystemTools::VersionCompareGreaterEq(input, "1.0.0");
+
+  return 0;
+}

+ 26 - 0
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

二进制
Tests/Fuzzing/corpus/archive/simple.tar


二进制
Tests/Fuzzing/corpus/archive/simple.tar.gz


二进制
Tests/Fuzzing/corpus/archive/simple.zip


二进制
Tests/Fuzzing/corpus/archive/with_dir.tar


+ 4 - 0
Tests/Fuzzing/corpus/depfile/multiline.d

@@ -0,0 +1,4 @@
+target.o: \
+  source.cpp \
+  header1.h \
+  header2.h

+ 1 - 0
Tests/Fuzzing/corpus/depfile/simple.d

@@ -0,0 +1 @@
+main.o: main.cpp header.h

+ 1 - 0
Tests/Fuzzing/corpus/depfile/spaces.d

@@ -0,0 +1 @@
+"path with spaces.o": "source file.cpp" "my header.h"

+ 109 - 0
Tests/Fuzzing/corpus/elf/generate.py

@@ -0,0 +1,109 @@
+#!/usr/bin/env python3
+"""Generate minimal ELF corpus files for fuzzing.
+
+These are hand-crafted minimal ELF headers that exercise the ELF parser
+without requiring actual compiled binaries. They contain just enough
+structure to be recognized as valid ELF files.
+
+Usage: python3 generate.py
+
+Output files can be verified with: file *.elf
+"""
+
+import os
+import struct
+
+SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
+
+
+def generate_minimal_elf64():
+    """Generate a minimal 64-bit ELF executable header (72 bytes).
+
+    Structure: ELF64 header (64 bytes) with e_type=ET_EXEC, e_machine=EM_X86_64,
+    plus 8 bytes padding for fuzzer mutation headroom.
+    """
+    elf = bytearray()
+
+    # e_ident[16]: ELF identification
+    elf.extend(b'\x7fELF')  # EI_MAG: magic number
+    elf.append(2)           # EI_CLASS: ELFCLASS64
+    elf.append(1)           # EI_DATA: ELFDATA2LSB (little-endian)
+    elf.append(1)           # EI_VERSION: EV_CURRENT
+    elf.append(0)           # EI_OSABI: ELFOSABI_NONE
+    elf.extend(b'\x00' * 8) # EI_PAD: padding
+
+    # ELF header fields
+    elf.extend(struct.pack('<H', 2))      # e_type: ET_EXEC
+    elf.extend(struct.pack('<H', 0x3e))   # e_machine: EM_X86_64
+    elf.extend(struct.pack('<I', 1))      # e_version: EV_CURRENT
+    elf.extend(struct.pack('<Q', 0))      # e_entry: entry point
+    elf.extend(struct.pack('<Q', 0))      # e_phoff: program header offset
+    elf.extend(struct.pack('<Q', 0))      # e_shoff: section header offset
+    elf.extend(struct.pack('<I', 0))      # e_flags
+    elf.extend(struct.pack('<H', 0))      # e_ehsize
+    elf.extend(struct.pack('<H', 0))      # e_phentsize
+    elf.extend(struct.pack('<H', 0))      # e_phnum
+    elf.extend(struct.pack('<H', 0))      # e_shentsize
+    elf.extend(struct.pack('<H', 0))      # e_shnum
+    elf.extend(struct.pack('<H', 0))      # e_shstrndx
+
+    # Padding for fuzzer mutation headroom
+    elf.extend(b'\x00' * 8)
+
+    return bytes(elf)
+
+
+def generate_minimal_elf32():
+    """Generate a minimal 32-bit ELF PIE header (60 bytes).
+
+    Structure: ELF32 header (52 bytes) with e_type=ET_DYN, e_machine=EM_386,
+    plus 8 bytes padding for fuzzer mutation headroom.
+    """
+    elf = bytearray()
+
+    # e_ident[16]: ELF identification
+    elf.extend(b'\x7fELF')  # EI_MAG: magic number
+    elf.append(1)           # EI_CLASS: ELFCLASS32
+    elf.append(1)           # EI_DATA: ELFDATA2LSB (little-endian)
+    elf.append(1)           # EI_VERSION: EV_CURRENT
+    elf.append(0)           # EI_OSABI: ELFOSABI_NONE
+    elf.extend(b'\x00' * 8) # EI_PAD: padding
+
+    # ELF header fields
+    elf.extend(struct.pack('<H', 3))      # e_type: ET_DYN (PIE)
+    elf.extend(struct.pack('<H', 3))      # e_machine: EM_386
+    elf.extend(struct.pack('<I', 1))      # e_version: EV_CURRENT
+    elf.extend(struct.pack('<I', 0))      # e_entry: entry point
+    elf.extend(struct.pack('<I', 0))      # e_phoff: program header offset
+    elf.extend(struct.pack('<I', 0))      # e_shoff: section header offset
+    elf.extend(struct.pack('<I', 0))      # e_flags
+    elf.extend(struct.pack('<H', 0))      # e_ehsize
+    elf.extend(struct.pack('<H', 0))      # e_phentsize
+    elf.extend(struct.pack('<H', 0))      # e_phnum
+    elf.extend(struct.pack('<H', 0))      # e_shentsize
+    elf.extend(struct.pack('<H', 0))      # e_shnum
+    elf.extend(struct.pack('<H', 0))      # e_shstrndx
+
+    # Padding for fuzzer mutation headroom
+    elf.extend(b'\x00' * 8)
+
+    return bytes(elf)
+
+
+def main():
+    os.chdir(SCRIPT_DIR)
+
+    elf64 = generate_minimal_elf64()
+    elf32 = generate_minimal_elf32()
+
+    with open('minimal64.elf', 'wb') as f:
+        f.write(elf64)
+    print(f"Generated minimal64.elf ({len(elf64)} bytes)")
+
+    with open('minimal32.elf', 'wb') as f:
+        f.write(elf32)
+    print(f"Generated minimal32.elf ({len(elf32)} bytes)")
+
+
+if __name__ == '__main__':
+    main()

二进制
Tests/Fuzzing/corpus/elf/minimal32.elf


二进制
Tests/Fuzzing/corpus/elf/minimal64.elf


+ 1 - 0
Tests/Fuzzing/corpus/expr/hex.txt

@@ -0,0 +1 @@
+0xff & 0x0f

+ 1 - 0
Tests/Fuzzing/corpus/expr/not.txt

@@ -0,0 +1 @@
+~0

+ 1 - 0
Tests/Fuzzing/corpus/expr/parens.txt

@@ -0,0 +1 @@
+(1+2)*3

+ 1 - 0
Tests/Fuzzing/corpus/expr/precedence.txt

@@ -0,0 +1 @@
+1+2*3

+ 1 - 0
Tests/Fuzzing/corpus/expr/shift.txt

@@ -0,0 +1 @@
+1 << 4

+ 1 - 0
Tests/Fuzzing/corpus/expr/simple.txt

@@ -0,0 +1 @@
+1+2

二进制
Tests/Fuzzing/corpus/filelock/custom_name.bin


二进制
Tests/Fuzzing/corpus/filelock/mode0.bin


二进制
Tests/Fuzzing/corpus/filelock/mode1.bin


二进制
Tests/Fuzzing/corpus/filelock/mode2.bin


二进制
Tests/Fuzzing/corpus/filelock/mode3.bin


二进制
Tests/Fuzzing/corpus/filelock/symlink.bin


二进制
Tests/Fuzzing/corpus/filelock/timeout.bin


+ 1 - 0
Tests/Fuzzing/corpus/genex/basic.txt

@@ -0,0 +1 @@
+$<TARGET_FILE:mylib>

+ 1 - 0
Tests/Fuzzing/corpus/genex/complex.txt

@@ -0,0 +1 @@
+$<IF:$<AND:$<BOOL:${BUILD_SHARED},$<NOT:$<PLATFORM_ID:Windows>>>>,shared,static>

+ 1 - 0
Tests/Fuzzing/corpus/genex/interface.txt

@@ -0,0 +1 @@
+$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>$<INSTALL_INTERFACE:include>

+ 1 - 0
Tests/Fuzzing/corpus/genex/nested.txt

@@ -0,0 +1 @@
+$<$<CONFIG:Debug>:DEBUG_MODE>

+ 1 - 0
Tests/Fuzzing/corpus/genex/target.txt

@@ -0,0 +1 @@
+$<TARGET_PROPERTY:mylib,INTERFACE_INCLUDE_DIRECTORIES>

+ 1 - 0
Tests/Fuzzing/corpus/json/nested.json

@@ -0,0 +1 @@
+{"a":{"b":{"c":{"d":[1,2,3]}}}}

+ 10 - 0
Tests/Fuzzing/corpus/json/preset.json

@@ -0,0 +1,10 @@
+{
+  "version": 3,
+  "configurePresets": [
+    {
+      "name": "default",
+      "generator": "Ninja",
+      "binaryDir": "${sourceDir}/build"
+    }
+  ]
+}

+ 9 - 0
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"}
+}

+ 3 - 0
Tests/Fuzzing/corpus/listfile/basic.txt

@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.10)
+project(Test)
+add_executable(main main.cpp)

+ 2 - 0
Tests/Fuzzing/corpus/listfile/bracket.txt

@@ -0,0 +1,2 @@
+set(x [=[nested [[brackets]] here]=])
+set(y [==[even more [=[nested]=] brackets]==])

+ 29 - 0
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()

+ 1 - 0
Tests/Fuzzing/corpus/path/dotdot.txt

@@ -0,0 +1 @@
+/home/user/../other/./path

+ 1 - 0
Tests/Fuzzing/corpus/path/relative.txt

@@ -0,0 +1 @@
+../build/CMakeFiles

+ 1 - 0
Tests/Fuzzing/corpus/path/unix.txt

@@ -0,0 +1 @@
+/usr/local/lib/cmake

+ 1 - 0
Tests/Fuzzing/corpus/path/windows.txt

@@ -0,0 +1 @@
+C:\Program Files\CMake\bin

+ 5 - 0
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

+ 9 - 0
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}

+ 20 - 0
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)

+ 14 - 0
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 "$<TARGET_FILE:foo>" 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")

+ 7 - 0
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)

+ 12 - 0
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()

+ 10 - 0
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}")

+ 4 - 0
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")

+ 7 - 0
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}")

+ 17 - 0
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]")

+ 3 - 0
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)

+ 6 - 0
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}")

+ 5 - 0
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}")

+ 1 - 0
Tests/Fuzzing/corpus/string/cmake_var.txt

@@ -0,0 +1 @@
+${CMAKE_SOURCE_DIR}

+ 1 - 0
Tests/Fuzzing/corpus/string/list.txt

@@ -0,0 +1 @@
+item1;item2;item3;item4

+ 1 - 0
Tests/Fuzzing/corpus/string/quoted.txt

@@ -0,0 +1 @@
+"quoted string with spaces"

+ 1 - 0
Tests/Fuzzing/corpus/version/long.txt

@@ -0,0 +1 @@
+3.28.0.20231201

+ 1 - 0
Tests/Fuzzing/corpus/version/semver.txt

@@ -0,0 +1 @@
+1.2.3-alpha+build

+ 1 - 0
Tests/Fuzzing/corpus/version/simple.txt

@@ -0,0 +1 @@
+3.28.0

+ 1 - 0
Tests/Fuzzing/corpus/version/tweak.txt

@@ -0,0 +1 @@
+3.28.0.1

+ 75 - 0
Tests/Fuzzing/xml_parser.dict

@@ -0,0 +1,75 @@
+# XML dictionary for xml_parser_fuzzer
+
+# Processing instruction
+"<?xml"
+"?>"
+"version="
+"encoding="
+"standalone="
+
+# Document structure
+"<!DOCTYPE"
+"<!ELEMENT"
+"<!ATTLIST"
+"<!ENTITY"
+"<!NOTATION"
+"SYSTEM"
+"PUBLIC"
+
+# Tags
+"<"
+">"
+"/>"
+"</"
+
+# Attributes
+"="
+"\x22"
+"\x27"
+
+# CDATA and comments
+"<![CDATA["
+"]]>"
+"<!--"
+"-->"
+
+# Namespaces
+"xmlns"
+"xmlns:"
+
+# Common CMake XML elements
+"<cmake"
+"<project"
+"<target"
+"<file"
+"<dependency"
+"<source"
+"<include"
+"<define"
+"<flag"
+"<option"
+"<property"
+"<configuration"
+"<install"
+"<test"
+"<cache"
+
+# Entity references
+"&lt;"
+"&gt;"
+"&amp;"
+"&quot;"
+"&apos;"
+"&#"
+"&#x"
+
+# Whitespace
+"\x09"
+"\x0a"
+"\x0d"
+"\x20"
+
+# Special patterns
+"]]]]><![CDATA["
+"-->"
+"?>"

部分文件因为文件数量过多而无法显示