OSS-Fuzz: Add new fuzzer targets Fortran Parser

Signed-off-by: Arthur Chan <arthur.chan@adalogics.com>
This commit is contained in:
Arthur Chan
2026-09-04 21:30:00 +01:00
parent 9e593fd2c0
commit 3b58f95f8c
9 changed files with 147 additions and 0 deletions
+3
View File
@@ -100,3 +100,6 @@ add_fuzzer(cmFileLockFuzzer cmFileLockFuzzer.cxx)
# CMake script fuzzer
add_fuzzer(cmScriptFuzzer cmScriptFuzzer.cxx)
# Fortran dependency scanner fuzzer
add_fuzzer(cmFortranParserFuzzer cmFortranParserFuzzer.cxx)
+36
View File
@@ -0,0 +1,36 @@
# Fortran dependency scanner dictionary
# Module dependency statements
"module "
"submodule "
"end module"
"use "
"use, intrinsic ::"
"only:"
"include "
"#include "
# Submodule parent syntax
"submodule ("
")"
":"
# Preprocessor directives the scanner tracks
"#define"
"#undef"
"#ifdef"
"#ifndef"
"#if defined"
"#elif"
"#else"
"#endif"
# Fixed-form and continuation punctuation
"&"
"!"
"c "
"*"
"'"
"\""
";"
"::"
+79
View File
@@ -0,0 +1,79 @@
/* 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 Fortran dependency scanner
*
* CMake runs a flex lexer and a bison parser over Fortran sources to discover
* module dependencies: MODULE, SUBMODULE, USE and INCLUDE statements, plus the
* preprocessor directives that guard them. This fuzzer drives that scanner.
*/
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <set>
#include <string>
#include <vector>
#include <unistd.h>
#include "cmFortranParser.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_fortran_XXXXXX";
char* dir = mkdtemp(tmpl);
if (dir) {
g_testDir = dir;
} else {
g_testDir = "/tmp/cmake_fuzz_fortran";
cmSystemTools::MakeDirectory(g_testDir);
}
return 0;
}
extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
{
if (size == 0 || size > kMaxInputSize) {
return 0;
}
std::string const source = g_testDir + "/test.f90";
{
FILE* fp = fopen(source.c_str(), "wb");
if (!fp) {
return 0;
}
fwrite(data, 1, size, fp);
fclose(fp);
}
cmFortranCompiler compiler;
compiler.Id = "GNU";
compiler.SModSep = "@";
compiler.SModExt = ".smod";
cmFortranSourceInfo info;
info.Source = source;
std::vector<std::string> const includes;
std::set<std::string> const defines;
cmFortranParser parser(compiler, includes, defines, info);
if (cmFortranParser_FilePush(&parser, source.c_str())) {
cmFortran_yyparse(parser.Scanner);
}
unlink(source.c_str());
return 0;
}
@@ -0,0 +1,4 @@
module a
use b
&
use c
+3
View File
@@ -0,0 +1,3 @@
MODULE FIXED
USE OTHER
END
+4
View File
@@ -0,0 +1,4 @@
module geometry
implicit none
integer, parameter :: dp = kind(1.0d0)
end module geometry
+7
View File
@@ -0,0 +1,7 @@
#define HAVE_MPI 1
#ifdef HAVE_MPI
use mpi
#else
use serial_stub
#endif
include 'missing.inc'
@@ -0,0 +1,6 @@
submodule (parent:child) impl
implicit none
contains
subroutine s()
end subroutine s
end submodule impl
+5
View File
@@ -0,0 +1,5 @@
program main
use geometry, only: dp
use, intrinsic :: iso_fortran_env
implicit none
end program main