Skip to content

Commit 8ba25e0

Browse files
authored
Merge pull request #610 from ssbr/master
Add a simple fuzz test for jsoncpp. Only in cmake.
2 parents 586e7a8 + edd093c commit 8ba25e0

File tree

5 files changed

+90
-0
lines changed

5 files changed

+90
-0
lines changed

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ datadiode <jochen.neubeck@vodafone.de>
3737
David Seifert <soap@gentoo.org>
3838
David West <david-west@idexx.com>
3939
dawesc <chris.dawes@eftlab.co.uk>
40+
Devin Jeanpierre <jeanpierreda@google.com>
4041
Dmitry Marakasov <amdmi3@amdmi3.ru>
4142
dominicpezzuto <dom@dompezzuto.com>
4243
Don Milham <dmilham@gmail.com>

src/test_lib_json/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
ADD_EXECUTABLE( jsoncpp_test
44
jsontest.cpp
55
jsontest.h
6+
fuzz.cpp
7+
fuzz.h
68
main.cpp
79
)
810

src/test_lib_json/fuzz.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright 2007-2010 The JsonCpp Authors
2+
// Distributed under MIT license, or public domain if desired and
3+
// recognized in your jurisdiction.
4+
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
5+
6+
#include "fuzz.h"
7+
8+
#include <json/config.h>
9+
#include <json/json.h>
10+
#include <memory>
11+
#include <string>
12+
#include <stdint.h>
13+
14+
namespace {
15+
// https://en.wikipedia.org/wiki/Jenkins_hash_function#one-at-a-time
16+
uint32_t JenkinsOneAtATimeHash(const uint8_t* data, size_t size) {
17+
uint32_t hash = 0;
18+
for (size_t i = 0; i < size; i++) {
19+
hash += data[i];
20+
hash += hash << 10;
21+
hash ^= hash >> 6;
22+
}
23+
hash += hash << 3;
24+
hash ^= hash >> 11;
25+
hash += hash << 15;
26+
return hash;
27+
}
28+
} // namespace
29+
30+
namespace Json {
31+
class Exception;
32+
}
33+
34+
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
35+
Json::CharReaderBuilder builder;
36+
37+
uint32_t hash_settings = JenkinsOneAtATimeHash(data, size);
38+
builder.settings_["failIfExtra"] = hash_settings & (1 << 0);
39+
builder.settings_["allowComments_"] = hash_settings & (1 << 1);
40+
builder.settings_["strictRoot_"] = hash_settings & (1 << 2);
41+
builder.settings_["allowDroppedNullPlaceholders_"] = hash_settings & (1 << 3);
42+
builder.settings_["allowNumericKeys_"] = hash_settings & (1 << 4);
43+
builder.settings_["allowSingleQuotes_"] = hash_settings & (1 << 5);
44+
builder.settings_["failIfExtra_"] = hash_settings & (1 << 6);
45+
builder.settings_["rejectDupKeys_"] = hash_settings & (1 << 7);
46+
builder.settings_["allowSpecialFloats_"] = hash_settings & (1 << 8);
47+
48+
std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
49+
50+
Json::Value root;
51+
const char* data_str = reinterpret_cast<const char*>(data);
52+
try {
53+
reader->parse(data_str, data_str + size, &root, nullptr);
54+
} catch (Json::Exception const&) {}
55+
// Whether it succeeded or not doesn't matter.
56+
return 0;
57+
}

src/test_lib_json/fuzz.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2007-2010 The JsonCpp Authors
2+
// Distributed under MIT license, or public domain if desired and
3+
// recognized in your jurisdiction.
4+
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
5+
6+
#ifndef FUZZ_H_INCLUDED
7+
#define FUZZ_H_INCLUDED
8+
9+
#include <stddef.h>
10+
#include <stdint.h>
11+
12+
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
13+
14+
#endif // ifndef FUZZ_H_INCLUDED

src/test_lib_json/main.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
88

99
#include "jsontest.h"
10+
#include "fuzz.h"
1011
#include <json/config.h>
1112
#include <json/json.h>
1213
#include <cstring>
@@ -2513,6 +2514,19 @@ JSONTEST_FIXTURE(RValueTest, moveConstruction) {
25132514
#endif
25142515
}
25152516

2517+
struct FuzzTest : JsonTest::TestCase {};
2518+
2519+
// Build and run the fuzz test without any fuzzer, so that it's guaranteed not
2520+
// go out of date, even if it's never run as an actual fuzz test.
2521+
JSONTEST_FIXTURE(FuzzTest, fuzzDoesntCrash) {
2522+
const std::string example = "{}";
2523+
JSONTEST_ASSERT_EQUAL(
2524+
0,
2525+
LLVMFuzzerTestOneInput(
2526+
reinterpret_cast<const uint8_t*>(example.c_str()),
2527+
example.size()));
2528+
}
2529+
25162530
int main(int argc, const char* argv[]) {
25172531
JsonTest::Runner runner;
25182532
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, checkNormalizeFloatingPointStr);
@@ -2588,6 +2602,8 @@ int main(int argc, const char* argv[]) {
25882602

25892603
JSONTEST_REGISTER_FIXTURE(runner, RValueTest, moveConstruction);
25902604

2605+
JSONTEST_REGISTER_FIXTURE(runner, FuzzTest, fuzzDoesntCrash);
2606+
25912607
return runner.runCommandLine(argc, argv);
25922608
}
25932609

0 commit comments

Comments
 (0)