diff --git a/AUTHORS b/AUTHORS index 5747e61c1..93169a829 100644 --- a/AUTHORS +++ b/AUTHORS @@ -37,6 +37,7 @@ datadiode David Seifert David West dawesc +Devin Jeanpierre Dmitry Marakasov dominicpezzuto Don Milham diff --git a/meson.build b/meson.build index 106e17f6a..8c6c32555 100644 --- a/meson.build +++ b/meson.build @@ -88,7 +88,8 @@ jsoncpp_test = executable( 'jsoncpp_test', [ 'src/test_lib_json/jsontest.cpp', 'src/test_lib_json/jsontest.h', - 'src/test_lib_json/main.cpp'], + 'src/test_lib_json/main.cpp', + 'src/test_lib_json/fuzz.cpp'], include_directories : jsoncpp_include_directories, link_with : jsoncpp_lib, install : false, diff --git a/src/test_lib_json/CMakeLists.txt b/src/test_lib_json/CMakeLists.txt index 8a3970fc0..ab0041413 100644 --- a/src/test_lib_json/CMakeLists.txt +++ b/src/test_lib_json/CMakeLists.txt @@ -3,6 +3,8 @@ add_executable( jsoncpp_test jsontest.cpp jsontest.h + fuzz.cpp + fuzz.h main.cpp ) diff --git a/src/test_lib_json/fuzz.cpp b/src/test_lib_json/fuzz.cpp new file mode 100644 index 000000000..f79f19ffe --- /dev/null +++ b/src/test_lib_json/fuzz.cpp @@ -0,0 +1,49 @@ +// Copyright 2007-2019 The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#include "fuzz.h" + +#include +#include +#include +#include +#include +#include + +namespace Json { +class Exception; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + Json::CharReaderBuilder builder; + + if (size < sizeof(uint32_t)) { + return 0; + } + + uint32_t hash_settings = *(const uint32_t*)data; + data += sizeof(uint32_t); + + builder.settings_["failIfExtra"] = hash_settings & (1 << 0); + builder.settings_["allowComments_"] = hash_settings & (1 << 1); + builder.settings_["strictRoot_"] = hash_settings & (1 << 2); + builder.settings_["allowDroppedNullPlaceholders_"] = hash_settings & (1 << 3); + builder.settings_["allowNumericKeys_"] = hash_settings & (1 << 4); + builder.settings_["allowSingleQuotes_"] = hash_settings & (1 << 5); + builder.settings_["failIfExtra_"] = hash_settings & (1 << 6); + builder.settings_["rejectDupKeys_"] = hash_settings & (1 << 7); + builder.settings_["allowSpecialFloats_"] = hash_settings & (1 << 8); + + std::unique_ptr reader(builder.newCharReader()); + + Json::Value root; + const char* data_str = reinterpret_cast(data); + try { + reader->parse(data_str, data_str + size, &root, nullptr); + } catch (Json::Exception const&) { + } + // Whether it succeeded or not doesn't matter. + return 0; +} diff --git a/src/test_lib_json/fuzz.h b/src/test_lib_json/fuzz.h new file mode 100644 index 000000000..0816d2757 --- /dev/null +++ b/src/test_lib_json/fuzz.h @@ -0,0 +1,14 @@ +// Copyright 2007-2010 The JsonCpp Authors +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef FUZZ_H_INCLUDED +#define FUZZ_H_INCLUDED + +#include +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size); + +#endif // ifndef FUZZ_H_INCLUDED diff --git a/src/test_lib_json/main.cpp b/src/test_lib_json/main.cpp index 280f7eac6..3dd816e7d 100644 --- a/src/test_lib_json/main.cpp +++ b/src/test_lib_json/main.cpp @@ -10,6 +10,7 @@ #pragma warning(disable : 4996) #endif +#include "fuzz.h" #include "jsontest.h" #include #include @@ -2528,6 +2529,18 @@ JSONTEST_FIXTURE(RValueTest, moveConstruction) { JSONTEST_ASSERT_EQUAL(Json::stringValue, moved["key"].type()); } +struct FuzzTest : JsonTest::TestCase {}; + +// Build and run the fuzz test without any fuzzer, so that it's guaranteed not +// go out of date, even if it's never run as an actual fuzz test. +JSONTEST_FIXTURE(FuzzTest, fuzzDoesntCrash) { + const std::string example = "{}"; + JSONTEST_ASSERT_EQUAL( + 0, + LLVMFuzzerTestOneInput(reinterpret_cast(example.c_str()), + example.size())); +} + int main(int argc, const char* argv[]) { JsonTest::Runner runner; JSONTEST_REGISTER_FIXTURE(runner, ValueTest, checkNormalizeFloatingPointStr); @@ -2607,6 +2620,8 @@ int main(int argc, const char* argv[]) { JSONTEST_REGISTER_FIXTURE(runner, RValueTest, moveConstruction); + JSONTEST_REGISTER_FIXTURE(runner, FuzzTest, fuzzDoesntCrash); + return runner.runCommandLine(argc, argv); }