Tests/Fuzzing: Add cmGeneratorExpressionFuzzer

Fuzz the CMake generator expression parser and evaluator.
Tests $<...> expression syntax and evaluation.
This commit is contained in:
Leslie P. Polzer
2026-01-15 10:30:42 +00:00
committed by Brad King
parent 90f9fa5fb5
commit 915524aaa6
3 changed files with 175 additions and 0 deletions

View File

@@ -58,3 +58,6 @@ add_fuzzer(cmListFileLexerFuzzer cmListFileLexerFuzzer.cxx)
# CMakeLists.txt parser fuzzer
add_fuzzer(cmListFileParserFuzzer cmListFileParserFuzzer.cxx)
# Generator expression fuzzer
add_fuzzer(cmGeneratorExpressionFuzzer cmGeneratorExpressionFuzzer.cxx)

View File

@@ -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:$<"

View File

@@ -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;
}