diff --git a/Tests/Fuzzing/CMakeLists.txt b/Tests/Fuzzing/CMakeLists.txt index 7cccbc55a8..40a625b7ed 100644 --- a/Tests/Fuzzing/CMakeLists.txt +++ b/Tests/Fuzzing/CMakeLists.txt @@ -52,3 +52,6 @@ endmacro() 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) diff --git a/Tests/Fuzzing/cmListFileLexer.dict b/Tests/Fuzzing/cmListFileLexer.dict new file mode 100644 index 0000000000..ad3393bae6 --- /dev/null +++ b/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 +"$<" +">:" +"$ +#include + +#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(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; +}