From 3f88a33518d28dad225c9c91d5e959121b711bc9 Mon Sep 17 00:00:00 2001 From: Mikhail Khachayants Date: Tue, 8 Oct 2024 09:59:56 +0300 Subject: [PATCH] direct parsing fuzzing test --- .github/workflows/run_fuzzer.yml | 1 + fuzzing/.gitignore | 1 + fuzzing/CMakeLists.txt | 4 + fuzzing/Jamfile | 4 +- fuzzing/fuzz.sh | 2 +- fuzzing/fuzz_direct_parse.cpp | 84 +++++++++++++++++++ fuzzing/old_crashes/direct_parse/array.json | 1 + fuzzing/old_crashes/direct_parse/tuple.json | 1 + .../old_crashes/direct_parse/valid_cxx14.json | 21 +++++ .../old_crashes/direct_parse/valid_cxx17.json | 26 ++++++ 10 files changed, 142 insertions(+), 3 deletions(-) create mode 100644 fuzzing/fuzz_direct_parse.cpp create mode 100644 fuzzing/old_crashes/direct_parse/array.json create mode 100644 fuzzing/old_crashes/direct_parse/tuple.json create mode 100644 fuzzing/old_crashes/direct_parse/valid_cxx14.json create mode 100644 fuzzing/old_crashes/direct_parse/valid_cxx17.json diff --git a/.github/workflows/run_fuzzer.yml b/.github/workflows/run_fuzzer.yml index 05c092a34..37b17b950 100644 --- a/.github/workflows/run_fuzzer.yml +++ b/.github/workflows/run_fuzzer.yml @@ -60,6 +60,7 @@ jobs: buildtype: 'boost' path: 'head' toolset: clang-18 + cxxstd: 17 targets: libs/json/fuzzing//run - name: Pack the corpus working-directory: boost-root/libs/json/fuzzing/ diff --git a/fuzzing/.gitignore b/fuzzing/.gitignore index 61b2d0a71..ac1668eea 100644 --- a/fuzzing/.gitignore +++ b/fuzzing/.gitignore @@ -6,6 +6,7 @@ corpus.tar fuzzer_basic_parser fuzzer_parse fuzzer_parser +fuzzer_direct_parse out*/ fuzz-*.log diff --git a/fuzzing/CMakeLists.txt b/fuzzing/CMakeLists.txt index 056fad484..4c06da7a5 100644 --- a/fuzzing/CMakeLists.txt +++ b/fuzzing/CMakeLists.txt @@ -11,6 +11,7 @@ source_group("" FILES fuzz_basic_parser.cpp fuzz_parse.cpp fuzz_parser.cpp + fuzz_direct_parse.cpp ) # The fuzzers are built as libraries, to make @@ -33,3 +34,6 @@ add_library(fuzzerlib_parser fuzz_parser.cpp) set_property(TARGET fuzzerlib_parser PROPERTY FOLDER "fuzzing") target_link_libraries(fuzzerlib_parser PRIVATE Boost::json) +add_library(fuzzerlib_direct_parse fuzz_direct_parse.cpp) +set_property(TARGET fuzzerlib_direct_parse PROPERTY FOLDER "fuzzing") +target_link_libraries(fuzzerlib_direct_parse PRIVATE Boost::json) diff --git a/fuzzing/Jamfile b/fuzzing/Jamfile index 99ef3f139..0eef94aca 100644 --- a/fuzzing/Jamfile +++ b/fuzzing/Jamfile @@ -59,8 +59,8 @@ explicit old-corpus ; local initial-corpus = [ glob-tree-ex ../test : *.json ] ; -local variants = basic_parser parse parser ; -for local variant in basic_parser parse parser +local variants = basic_parser parse parser direct_parse ; +for local variant in basic_parser parse parser direct_parse { local $(variant)-runs ; local fuzzer = fuzzer_$(variant) ; diff --git a/fuzzing/fuzz.sh b/fuzzing/fuzz.sh index de50ef411..78767e255 100755 --- a/fuzzing/fuzz.sh +++ b/fuzzing/fuzz.sh @@ -44,7 +44,7 @@ JOBS= # set a timelimit (you may want to adjust this if you run locally) MAXTIME="-max_total_time=30" -variants="basic_parser parse parser" +variants="basic_parser parse parser direct_parse" for variant in $variants; do diff --git a/fuzzing/fuzz_direct_parse.cpp b/fuzzing/fuzz_direct_parse.cpp new file mode 100644 index 000000000..8c9ab7e33 --- /dev/null +++ b/fuzzing/fuzz_direct_parse.cpp @@ -0,0 +1,84 @@ +// Copyright (c) 2024 Mikhail Khachayants (mkhachaiants@gmail.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/boostorg/json +// + +#include +#include +#include +#include + +#ifndef BOOST_NO_CXX17_HDR_OPTIONAL +# include +# define IF_CXX17_HDR_OPTIONAL(...) __VA_ARGS__ +#else +# define IF_CXX17_HDR_OPTIONAL(...) +#endif // BOOST_NO_CXX17_HDR_OPTIONAL + +using namespace boost::json; + +struct Object +{ + bool b; + float f; + double d; + std::int64_t i64; + std::uint64_t u64; + std::string s; + std::vector v1; + std::vector v2; + std::vector v3; + std::array a1; + std::array a2; + std::array a3; + std::map m1; + std::map m2; + std::map m3; + std::tuple t1; + std::tuple, std::array, std::nullptr_t> t2; + std::tuple, std::vector> t3; + boost::variant2::variant v; + +#ifndef BOOST_NO_CXX17_HDR_OPTIONAL + std::optional ob; + std::optional oi; + std::optional ou; + std::optional od; + std::optional os; +#endif // BOOST_NO_CXX17_HDR_OPTIONAL +}; + +BOOST_DESCRIBE_STRUCT(Object, (), + (b, i64, u64, f, d, s, v1, v2, v3, a1, a2, a3, m1, m2, m3, t1, t2, t3, v, + IF_CXX17_HDR_OPTIONAL(ob, oi, ou, od, os))) + + +bool +fuzz_direct_parse(string_view sv) +{ + Object object; + boost::system::error_code ec; + parse_into(object, sv, ec); + return !ec; +} + +extern "C" +int +LLVMFuzzerTestOneInput( + const uint8_t* data, size_t size) +{ + try + { + string_view sv{reinterpret_cast< + const char*>(data), size}; + fuzz_direct_parse(sv); + } + catch(...) + { + } + return 0; +} + diff --git a/fuzzing/old_crashes/direct_parse/array.json b/fuzzing/old_crashes/direct_parse/array.json new file mode 100644 index 000000000..b18794c90 --- /dev/null +++ b/fuzzing/old_crashes/direct_parse/array.json @@ -0,0 +1 @@ +{"a2":[977,775500052916,9216,77552916,9216]} diff --git a/fuzzing/old_crashes/direct_parse/tuple.json b/fuzzing/old_crashes/direct_parse/tuple.json new file mode 100644 index 000000000..7d1f914c0 --- /dev/null +++ b/fuzzing/old_crashes/direct_parse/tuple.json @@ -0,0 +1 @@ +{"t1":[]} diff --git a/fuzzing/old_crashes/direct_parse/valid_cxx14.json b/fuzzing/old_crashes/direct_parse/valid_cxx14.json new file mode 100644 index 000000000..30598a7c2 --- /dev/null +++ b/fuzzing/old_crashes/direct_parse/valid_cxx14.json @@ -0,0 +1,21 @@ +{ + "b": true, + "i64": -123, + "u64": 123, + "f": 123.45, + "d": 0.9832747263462, + "s": "text", + "v1": [true, false], + "v2": [-12, 89], + "v3": [1000, 0], + "a1": [true, false, true], + "a2": [-1, 2, 3], + "a3": [1, 2, 3], + "m1": {"k": 42}, + "m2": {"k": "v"}, + "m3": {"k": 0.42}, + "t1": [true, 1, 2, 1.23, "s"], + "t2": [["a", "b", "c"], [1.0, 0.1, 2.2], null], + "t3": [[], []], + "v": "text" +} diff --git a/fuzzing/old_crashes/direct_parse/valid_cxx17.json b/fuzzing/old_crashes/direct_parse/valid_cxx17.json new file mode 100644 index 000000000..341894772 --- /dev/null +++ b/fuzzing/old_crashes/direct_parse/valid_cxx17.json @@ -0,0 +1,26 @@ +{ + "b": true, + "i64": -123, + "u64": 123, + "f": 123.45, + "d": 0.9832747263462, + "s": "text", + "v1": [true, false], + "v2": [-12, 89], + "v3": [1000, 0], + "a1": [true, false, true], + "a2": [-1, 2, 3], + "a3": [1, 2, 3], + "m1": {"k": 42}, + "m2": {"k": "v"}, + "m3": {"k": 0.42}, + "t1": [true, 1, 2, 1.23, "s"], + "t2": [["a", "b", "c"], [1.0, 0.1, 2.2], null], + "t3": [[], []], + "ob": null, + "oi": 123, + "ou": 456, + "od": 1.1, + "os": null, + "v": "text" +}