Read-only mirrors. Development, issues and pull requests are on GitHub.

summaryrefslogtreecommitdiffhomepage
path: root/fuzzing
diff options
context:
space:
mode:
authorLeitwolf2026-10-24 19:03:40 +0300
committerGitHub2026-10-24 19:03:40 +0300
commit4f1c759cffcb14bd6511e1d7c5fbace682e24f2d (patch)
tree415fe5d48a5b48650bba3747beaf245d727c4f61 /fuzzing
parent83c6fc3ac13abe83fa39f7b5f8559ccaf4412233 (diff)
parent622188f9c08e4af35941c146979883ed4882410e (diff)
downloadcatch3-4f1c759cffcb14bd6511e1d7c5fbace682e24f2d.tar.gz
Merge pull request #15 from Progmasoft/feature/catch3-runner
Replace Catch2's runner with the Catch3 runner
Diffstat (limited to 'fuzzing')
-rw-r--r--fuzzing/CMakeLists.txt12
-rw-r--r--fuzzing/Progmasoft/fuzz_RunnerJson.cpp29
-rw-r--r--fuzzing/Progmasoft/fuzz_RunnerOptions.cpp50
-rw-r--r--fuzzing/fuzz_XmlWriter.cpp22
-rw-r--r--fuzzing/fuzz_textflow.cpp54
5 files changed, 88 insertions, 79 deletions
diff --git a/fuzzing/CMakeLists.txt b/fuzzing/CMakeLists.txt
index 8370fe39..d300a19d 100644
--- a/fuzzing/CMakeLists.txt
+++ b/fuzzing/CMakeLists.txt
@@ -7,14 +7,20 @@
add_library(fuzzhelper NullOStream.h NullOStream.cpp)
target_link_libraries(fuzzhelper PUBLIC Catch2::Catch2)
-# use C++17 so we can get string_view
-target_compile_features(fuzzhelper PUBLIC cxx_std_17)
+# The runner fuzzers include its C++20 headers.
+target_compile_features(fuzzhelper PUBLIC cxx_std_20)
# This should be possible to set from the outside to be oss-fuzz compatible,
# fix later. For now, target libFuzzer only.
target_link_options(fuzzhelper PUBLIC "-fsanitize=fuzzer")
-foreach(fuzzer TestSpecParser XmlWriter textflow)
+foreach(fuzzer TestSpecParser)
add_executable(fuzz_${fuzzer} fuzz_${fuzzer}.cpp)
target_link_libraries(fuzz_${fuzzer} PRIVATE fuzzhelper)
endforeach()
+
+# Progmasoft's fuzzers live apart, under their own license header.
+foreach(fuzzer RunnerJson RunnerOptions)
+ add_executable(fuzz_${fuzzer} Progmasoft/fuzz_${fuzzer}.cpp)
+ target_link_libraries(fuzz_${fuzzer} PRIVATE fuzzhelper)
+endforeach()
diff --git a/fuzzing/Progmasoft/fuzz_RunnerJson.cpp b/fuzzing/Progmasoft/fuzz_RunnerJson.cpp
new file mode 100644
index 00000000..4cc3770c
--- /dev/null
+++ b/fuzzing/Progmasoft/fuzz_RunnerJson.cpp
@@ -0,0 +1,29 @@
+// Copyright (c) 2026 Progmasoft.
+// SPDX-License-Identifier: MPL-2.0 WITH AdditionRef-Progmasoft-Exception-1.1
+
+// The runner reads JSON from its workers, from history files and from
+// reports; none of them may crash it. A document that parses must also
+// print and parse back to the same text.
+
+#include <Progmasoft/Runner/Json.hpp>
+
+#include <cstdint>
+#include <cstdlib>
+#include <string_view>
+
+extern "C" int
+LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size)
+{
+ const std::string_view text{reinterpret_cast<const char *>(data), size};
+ auto parsed = Progmasoft::Catch3::Runner::ParseJson(text);
+ if (parsed)
+ {
+ const auto printed = parsed->ToString();
+ auto again = Progmasoft::Catch3::Runner::ParseJson(printed);
+ if (!again || again->ToString() != printed)
+ {
+ std::abort();
+ }
+ }
+ return 0;
+}
diff --git a/fuzzing/Progmasoft/fuzz_RunnerOptions.cpp b/fuzzing/Progmasoft/fuzz_RunnerOptions.cpp
new file mode 100644
index 00000000..2a10ba91
--- /dev/null
+++ b/fuzzing/Progmasoft/fuzz_RunnerOptions.cpp
@@ -0,0 +1,50 @@
+// Copyright (c) 2026 Progmasoft.
+// SPDX-License-Identifier: MPL-2.0 WITH AdditionRef-Progmasoft-Exception-1.1
+
+// The command line of a test binary: arguments separated by NUL bytes. The
+// parser must answer with options or an error, never crash, and the worker
+// arguments it derives must parse again.
+
+#include <Progmasoft/Runner/Options.hpp>
+
+#include <cstdint>
+#include <cstdlib>
+#include <string>
+#include <vector>
+
+extern "C" int
+LLVMFuzzerTestOneInput(const std::uint8_t *data, std::size_t size)
+{
+ std::vector<std::string> arguments(1);
+ for (std::size_t index = 0; index < size; ++index)
+ {
+ if (data[index] == 0)
+ {
+ arguments.emplace_back();
+ }
+ else
+ {
+ arguments.back().push_back(static_cast<char>(data[index]));
+ }
+ }
+ // Reading a file named by --input-file is not what is fuzzed here.
+ for (const auto &argument : arguments)
+ {
+ if (argument.find("input-file") != std::string::npos ||
+ (argument.size() >= 2 && argument[0] == '-' && argument[1] == 'f'))
+ {
+ return 0;
+ }
+ }
+ auto options = Progmasoft::Catch3::Runner::ParseOptions(arguments);
+ if (options)
+ {
+ const auto worker = Progmasoft::Catch3::Runner::ParseOptions(
+ Progmasoft::Catch3::Runner::WorkerArguments(*options));
+ if (!worker)
+ {
+ std::abort();
+ }
+ }
+ return 0;
+}
diff --git a/fuzzing/fuzz_XmlWriter.cpp b/fuzzing/fuzz_XmlWriter.cpp
deleted file mode 100644
index 70c4ed80..00000000
--- a/fuzzing/fuzz_XmlWriter.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-
-// Copyright Catch2 Authors
-// Distributed under the Boost Software License, Version 1.0.
-// (See accompanying file LICENSE.txt or copy at
-// https://www.boost.org/LICENSE_1_0.txt)
-
-// SPDX-License-Identifier: BSL-1.0
-//By Paul Dreik 2020
-
-#include <catch2/internal/catch_xmlwriter.hpp>
-
-#include "NullOStream.h"
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
-
- std::string buf(Data,Data+Size);
- NullOStream nul;
- Catch::XmlEncode encode(buf);
- encode.encodeTo(nul);
- return 0;
-}
-
diff --git a/fuzzing/fuzz_textflow.cpp b/fuzzing/fuzz_textflow.cpp
deleted file mode 100644
index f3119379..00000000
--- a/fuzzing/fuzz_textflow.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-
-// Copyright Catch2 Authors
-// Distributed under the Boost Software License, Version 1.0.
-// (See accompanying file LICENSE.txt or copy at
-// https://www.boost.org/LICENSE_1_0.txt)
-
-// SPDX-License-Identifier: BSL-1.0
-//By Paul Dreik 2020
-
-#include <catch2/internal/catch_textflow.hpp>
-
-#include "NullOStream.h"
-
-#include <string>
-#include <string_view>
-#include <cstdint>
-
-
-template<class Callback>
-void split(const char *Data, size_t Size, Callback callback) {
-
- using namespace std::literals;
- constexpr auto sep="\n~~~\n"sv;
-
- std::string_view remainder(Data,Size);
- for (;;) {
- auto pos=remainder.find(sep);
- if(pos==std::string_view::npos) {
- //not found. use the remainder and exit
- callback(remainder);
- return;
- } else {
- //found. invoke callback on the first part, then proceed with the rest.
- callback(remainder.substr(0,pos));
- remainder=remainder.substr(pos+sep.size());
- }
- }
-}
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
-
- Catch::TextFlow::Columns columns;
-
- // break the input on separator
- split((const char*)Data,Size,[&](std::string_view word) {
- columns+=Catch::TextFlow::Column(std::string(word));
- });
-
- NullOStream nul;
- nul << columns;
-
- return 0;
-}
-