mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-10-04 04:03:22 +03:00
OSS-Fuzz: Add new fuzzer targets Package Info Reader
Signed-off-by: Arthur Chan <arthur.chan@adalogics.com>
This commit is contained in:
1 parent
ec85176fbe
commit
97c527aeb8
15 files changed
+476
No files matched your search
@@ -31,6 +31,12 @@
|
||||
#include "cmTargetTypes.h"
|
||||
#include "cmValue.h"
|
||||
|
||||
// When adding or changing CPS schema versions, component types, languages, or
|
||||
// branch-selecting attributes, review Tests/Fuzzing/cmPackageInfoReader.dict.
|
||||
// Add tokens including keys that help mutations reach the new paths; keep the
|
||||
// dictionary focused on useful parser inputs, not an exhaustive list of CPS
|
||||
// keywords.
|
||||
|
||||
namespace {
|
||||
|
||||
// Map of CPS language names to CMake language name. Case insensitivity is
|
||||
|
||||
@@ -104,3 +104,6 @@ add_fuzzer(cmScriptFuzzer cmScriptFuzzer.cxx)
|
||||
|
||||
# Fortran dependency scanner fuzzer
|
||||
add_fuzzer(cmFortranParserFuzzer cmFortranParserFuzzer.cxx)
|
||||
|
||||
# CPS (Common Package Specification) package-info reader fuzzer
|
||||
add_fuzzer(cmPackageInfoReaderFuzzer cmPackageInfoReaderFuzzer.cxx)
|
||||
@@ -0,0 +1,63 @@
|
||||
# Dictionary for the CPS (Common Package Specification) package-info reader.
|
||||
# Keys and values that gate the reader's branches: the accepted schema range,
|
||||
# the prefix marker, component types, and the per-configuration attributes.
|
||||
|
||||
# Top-level keys
|
||||
"\"cps_version\""
|
||||
"\"name\""
|
||||
"\"version\""
|
||||
"\"compat_version\""
|
||||
"\"version_schema\""
|
||||
"\"cps_path\""
|
||||
"\"prefix\""
|
||||
"\"components\""
|
||||
"\"requires\""
|
||||
"\"configurations\""
|
||||
"\"default_configurations\""
|
||||
"\"default_license\""
|
||||
"\"license\""
|
||||
|
||||
# Accepted schema versions (reader requires >= 0.13 and < 0.16)
|
||||
"\"0.13\""
|
||||
"\"0.14\""
|
||||
"\"0.15\""
|
||||
|
||||
# Prefix resolution
|
||||
"\"@prefix@\""
|
||||
"\"@prefix@/cps\""
|
||||
|
||||
# Version schemas
|
||||
"\"simple\""
|
||||
"\"custom\""
|
||||
"\"rpm\""
|
||||
"\"dpkg\""
|
||||
"\"pep440\""
|
||||
|
||||
# Component types
|
||||
"\"type\""
|
||||
"\"interface\""
|
||||
"\"executable\""
|
||||
"\"archive\""
|
||||
"\"dylib\""
|
||||
"\"module\""
|
||||
"\"symbolic\""
|
||||
|
||||
# Component attributes
|
||||
"\"location\""
|
||||
"\"includes\""
|
||||
"\"definitions\""
|
||||
"\"compile_flags\""
|
||||
"\"link_flags\""
|
||||
"\"link_libraries\""
|
||||
"\"compile_features\""
|
||||
"\"link_features\""
|
||||
"\"requires\""
|
||||
"\"configurations\""
|
||||
"\"file_sets\""
|
||||
"\"cxx_modules\""
|
||||
|
||||
# Languages accepted for per-language properties
|
||||
"\"c\""
|
||||
"\"cpp\""
|
||||
"\"cxx\""
|
||||
"\"fortran\""
|
||||
@@ -0,0 +1,179 @@
|
||||
/* 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 CPS (Common Package Specification) reader.
|
||||
*
|
||||
* cmPackageInfoReader.cxx is 694 lines at 0.00% coverage. It parses the .cps
|
||||
* JSON files that third-party packages install and that find_package() picks
|
||||
* up from whatever is on the search path, so the input is supplied by the
|
||||
* packages found on the machine rather than by the project being built.
|
||||
*
|
||||
* cmJSONParserFuzzer already covers jsoncpp itself. What is untested is
|
||||
* everything the reader does with the decoded value: schema-version gating,
|
||||
* prefix resolution against the file's own location, the "simple"/pep440
|
||||
* version grammar, requirement specs, and -- the bulk of the file -- turning
|
||||
* each entry under "components" into an imported target, with per-
|
||||
* configuration properties, link/compile features, definitions, file sets and
|
||||
* C++ module metadata.
|
||||
*
|
||||
* Reaching the target-import half needs a real cmMakefile, so each input gets
|
||||
* a fresh cmake/cmGlobalGenerator/cmMakefile fixture. That also keeps targets
|
||||
* created by one input from colliding with the next.
|
||||
*
|
||||
* The reader resolves its prefix by matching "cps_path" against the directory
|
||||
* the file was read from, so the input has to be a real file in a real
|
||||
* directory: the fixture writes it to <tmp>/cps/fuzz.cps, mirroring the layout
|
||||
* the upstream CPS tests use ("cps_path": "@prefix@/cps").
|
||||
*
|
||||
* Both the primary and the appendix read run on every input. An appendix is a
|
||||
* supplemental file read with an already-parsed package as its parent, which
|
||||
* skips the schema-version check and inherits the parent's prefix, components
|
||||
* and default configurations -- a different path through Read() that no
|
||||
* primary read can reach.
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <cm/memory>
|
||||
#include <cm/optional>
|
||||
|
||||
#include "cmExecutionStatus.h"
|
||||
#include "cmGlobalGenerator.h"
|
||||
#include "cmMakefile.h"
|
||||
#include "cmMessenger.h"
|
||||
#include "cmPackageInfoReader.h"
|
||||
#include "cmState.h"
|
||||
#include "cmStateDirectory.h"
|
||||
#include "cmStateSnapshot.h"
|
||||
#include "cmSystemTools.h"
|
||||
#include "cmTargetTypes.h"
|
||||
#include "cmake.h"
|
||||
|
||||
static constexpr size_t kMaxInputSize = 256 * 1024;
|
||||
|
||||
static std::string g_prefixDir;
|
||||
static std::string g_cpsFile;
|
||||
|
||||
extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
cmSystemTools::SetMessageCallback(
|
||||
[](std::string const&, cmMessageMetadata const&) {});
|
||||
cmSystemTools::SetStdoutCallback([](std::string const&) {});
|
||||
cmSystemTools::SetStderrCallback([](std::string const&) {});
|
||||
|
||||
char tmpl[] = "/tmp/cmake_fuzz_cps_XXXXXX";
|
||||
char* dir = mkdtemp(tmpl);
|
||||
if (dir) {
|
||||
g_prefixDir = dir;
|
||||
} else {
|
||||
g_prefixDir = "/tmp/cmake_fuzz_cps";
|
||||
}
|
||||
|
||||
cmSystemTools::MakeDirectory(g_prefixDir + "/cps");
|
||||
g_cpsFile = g_prefixDir + "/cps/fuzz.cps";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct Fixture
|
||||
{
|
||||
cmake CMake{ cmState::Role::Project };
|
||||
std::unique_ptr<cmGlobalGenerator> GG;
|
||||
std::unique_ptr<cmMakefile> MF;
|
||||
|
||||
Fixture()
|
||||
{
|
||||
this->CMake.SetHomeDirectory(g_prefixDir);
|
||||
this->CMake.SetHomeOutputDirectory(g_prefixDir);
|
||||
this->GG = cm::make_unique<cmGlobalGenerator>(&this->CMake);
|
||||
cmStateSnapshot snapshot = this->CMake.GetCurrentSnapshot();
|
||||
snapshot.GetDirectory().SetCurrentBinary(g_prefixDir);
|
||||
snapshot.GetDirectory().SetCurrentSource(g_prefixDir);
|
||||
this->MF = cm::make_unique<cmMakefile>(this->GG.get(), snapshot);
|
||||
}
|
||||
};
|
||||
|
||||
void Consume(cmPackageInfoReader const& reader)
|
||||
{
|
||||
(void)reader.GetName();
|
||||
|
||||
cm::optional<std::string> const version = reader.GetVersion();
|
||||
cm::optional<std::string> const compatVersion = reader.GetCompatVersion();
|
||||
(void)reader.ParseVersion(version);
|
||||
(void)reader.ParseVersion(compatVersion);
|
||||
|
||||
for (cmPackageRequirement const& req : reader.GetRequirements()) {
|
||||
(void)req.Name;
|
||||
(void)req.Version;
|
||||
(void)req.Components;
|
||||
(void)req.Hints;
|
||||
}
|
||||
(void)reader.GetComponentNames();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
|
||||
{
|
||||
if (size == 0 || size > kMaxInputSize) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
{
|
||||
FILE* fp = fopen(g_cpsFile.c_str(), "wb");
|
||||
if (!fp) {
|
||||
return 0;
|
||||
}
|
||||
bool const written = fwrite(data, 1, size, fp) == size;
|
||||
fclose(fp);
|
||||
if (!written) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Fixture fx;
|
||||
std::unique_ptr<cmPackageInfoReader> reader =
|
||||
cmPackageInfoReader::Read(fx.MF.get(), g_cpsFile);
|
||||
if (reader) {
|
||||
Consume(*reader);
|
||||
|
||||
cmExecutionStatus status(*fx.MF);
|
||||
if (reader->ImportTargets(fx.MF.get(), status,
|
||||
cm::ImportedTargetScope::Local)) {
|
||||
reader->ImportTargetConfigurations(fx.MF.get(), status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Fixture fx;
|
||||
std::unique_ptr<cmPackageInfoReader> parent =
|
||||
cmPackageInfoReader::Read(fx.MF.get(), g_cpsFile);
|
||||
if (parent) {
|
||||
std::unique_ptr<cmPackageInfoReader> appendix =
|
||||
cmPackageInfoReader::Read(fx.MF.get(), g_cpsFile, parent.get());
|
||||
if (appendix) {
|
||||
Consume(*appendix);
|
||||
|
||||
cmExecutionStatus status(*fx.MF);
|
||||
if (appendix->ImportTargets(fx.MF.get(), status,
|
||||
cm::ImportedTargetScope::Global)) {
|
||||
appendix->ImportTargetConfigurations(fx.MF.get(), status);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"cps_version": "0.13",
|
||||
"name": "DefaultConfigurationsTest",
|
||||
"cps_path": "@prefix@/cps",
|
||||
"configurations": [ "Default" ],
|
||||
"components": {
|
||||
"Target1": {
|
||||
"type": "interface",
|
||||
"configurations": {
|
||||
"Test": {
|
||||
"includes": [ "@prefix@/include" ]
|
||||
}
|
||||
}
|
||||
},
|
||||
"Target2": {
|
||||
"type": "interface",
|
||||
"configurations": {
|
||||
"Test": {
|
||||
"includes": [ "@prefix@/include" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"cps_version": "0.14.0",
|
||||
"name": "RequiresTest",
|
||||
"cps_path": "@prefix@/cps",
|
||||
"components": {
|
||||
"Indirect": {
|
||||
"type": "interface",
|
||||
"requires": [ ":Direct" ]
|
||||
},
|
||||
"Direct": {
|
||||
"type": "interface",
|
||||
"definitions": {
|
||||
"*": {
|
||||
"ANSWER": 42
|
||||
}
|
||||
}
|
||||
},
|
||||
"CompileOnly": {
|
||||
"type": "interface",
|
||||
"compile_requires": [ ":BrokenLibrary" ]
|
||||
},
|
||||
"BrokenLibrary": {
|
||||
"type": "archive",
|
||||
"location": "@prefix@/lib/does-not-exist.a",
|
||||
"definitions": {
|
||||
"*": {
|
||||
"ANSWER": 42
|
||||
}
|
||||
}
|
||||
},
|
||||
"Private1": {
|
||||
"type": "dylib"
|
||||
},
|
||||
"Private2": {
|
||||
"type": "dylib"
|
||||
},
|
||||
"Other": {
|
||||
"type": "dylib",
|
||||
"link_libraries": [ "every-config" ],
|
||||
"dyld_requires": [ ":Private1" ],
|
||||
"configurations": {
|
||||
"test": {
|
||||
"link_libraries": [ "test-config" ],
|
||||
"dyld_requires": [ ":Private2" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"cps_version": "0.13",
|
||||
"name": "TransitiveTest",
|
||||
"cps_path": "@prefix@/cps",
|
||||
"requires": {
|
||||
"TransitiveDep": {
|
||||
"components": [ "Target2" ]
|
||||
}
|
||||
},
|
||||
"components": {}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"cps_version": "0.13",
|
||||
"name": "Bad1",
|
||||
"cps_path": "@prefix@/cps",
|
||||
"requires": "Broken",
|
||||
"components": {
|
||||
"Target": {
|
||||
"type": "interface"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"cps_version": "0.13",
|
||||
"name": "BadVersion2",
|
||||
"version": "1.1a.0",
|
||||
"version_schema": "simple",
|
||||
"cps_path": "@prefix@/cps",
|
||||
"components": {}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"cps_version": "0.13",
|
||||
"name": "CustomVersion",
|
||||
"version": "VII",
|
||||
"version_schema": "roman",
|
||||
"cps_path": "@prefix@/cps",
|
||||
"components": {}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"cps_version": "0.13",
|
||||
"name": "defs",
|
||||
"cps_path": "@prefix@/cps",
|
||||
"components": {
|
||||
"defs": {
|
||||
"type": "interface",
|
||||
"definitions": {
|
||||
"c": {
|
||||
"ONLY_IN_C": null,
|
||||
"OVERRIDE1": "1",
|
||||
"OVERRIDE2": "1"
|
||||
},
|
||||
"cxx": {
|
||||
"ONLY_IN_CXX": null,
|
||||
"OVERRIDE1": "2"
|
||||
},
|
||||
"*": {
|
||||
"NOVALUE": null,
|
||||
"EMPTYVALUE": "",
|
||||
"OVERRIDE1": "0",
|
||||
"OVERRIDE2": "0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"cps_version": "0.15.0",
|
||||
"name": "FileSets-Named",
|
||||
"cps_path": "@prefix@/cps",
|
||||
"components": {
|
||||
"Target": {
|
||||
"file_sets":
|
||||
[
|
||||
{
|
||||
"extensions":
|
||||
{
|
||||
"cmake":
|
||||
{
|
||||
"name@v1": "foo"
|
||||
}
|
||||
},
|
||||
"type": "includes",
|
||||
"root": "@prefix@/include/a",
|
||||
"files": [ "foo1.h", "foo2.h" ]
|
||||
},
|
||||
{
|
||||
"extensions":
|
||||
{
|
||||
"cmake":
|
||||
{
|
||||
"name@v1": "foo"
|
||||
}
|
||||
},
|
||||
"type": "includes",
|
||||
"root": "@prefix@/include/b",
|
||||
"files": [ "foo3.h" ]
|
||||
},
|
||||
{
|
||||
"extensions":
|
||||
{
|
||||
"cmake":
|
||||
{
|
||||
"name@v1": "bar"
|
||||
}
|
||||
},
|
||||
"type": "includes",
|
||||
"root": "@prefix@/include",
|
||||
"files": [ "bar.h" ]
|
||||
}
|
||||
],
|
||||
"type": "interface"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"cps_version": "0.13",
|
||||
"name": "Foo",
|
||||
"cps_path": "@prefix@/cps",
|
||||
"default_configurations": ["default"],
|
||||
"components": {
|
||||
"PrefixTest": {
|
||||
"type": "interface"
|
||||
},
|
||||
"Empty": {
|
||||
"type": "interface"
|
||||
},
|
||||
"ExecutableTest": {
|
||||
"type": "executable"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"cps_version": "0.13",
|
||||
"name": "Foo",
|
||||
"configuration": "default",
|
||||
"components": {
|
||||
"PrefixTest": {
|
||||
"includes": ["@prefix@/include"]
|
||||
},
|
||||
"ExecutableTest": {
|
||||
"location": "@prefix@/foo"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"cps_version": "0.13",
|
||||
"name": "Sample",
|
||||
"version": "2.10.11",
|
||||
"compat_version": "2.0.0",
|
||||
"cps_path": "@prefix@/cps",
|
||||
"components": {}
|
||||
}
|
||||
Reference in new issue
Block a user