Skip to content

Commit b78e7e3

Browse files
committed
Add a simple fuzz test for jsoncpp.
The idea is to then add it to the google oss-fuzz project and get jsoncpp regularly tested for bugs. https://github.com/google/oss-fuzz/ I've followed the instructions at: https://github.com/google/oss-fuzz/blob/master/docs/ideal_integration.md Tested using a simple oss-fuzz setup and with the modified jsoncpp unit tests (cmake . && make). I don't really know git, so also I've royally screwed up the commit history, and artificially flattened it into this one commit. :)
1 parent 6062f9b commit b78e7e3

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
@@ -4,6 +4,7 @@
44
// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
55

66
#include "jsontest.h"
7+
#include "fuzz.h"
78
#include <json/config.h>
89
#include <json/json.h>
910
#include <cstring>
@@ -2510,6 +2511,19 @@ JSONTEST_FIXTURE(RValueTest, moveConstruction) {
25102511
#endif
25112512
}
25122513

2514+
struct FuzzTest : JsonTest::TestCase {};
2515+
2516+
// Build and run the fuzz test without any fuzzer, so that it's guaranteed not
2517+
// go out of date, even if it's never run as an actual fuzz test.
2518+
JSONTEST_FIXTURE(FuzzTest, fuzzDoesntCrash) {
2519+
const std::string example = "{}";
2520+
JSONTEST_ASSERT_EQUAL(
2521+
0,
2522+
LLVMFuzzerTestOneInput(
2523+
reinterpret_cast<const uint8_t*>(example.c_str()),
2524+
example.size()));
2525+
}
2526+
25132527
int main(int argc, const char* argv[]) {
25142528
JsonTest::Runner runner;
25152529
JSONTEST_REGISTER_FIXTURE(runner, ValueTest, checkNormalizeFloatingPointStr);
@@ -2585,5 +2599,7 @@ int main(int argc, const char* argv[]) {
25852599

25862600
JSONTEST_REGISTER_FIXTURE(runner, RValueTest, moveConstruction);
25872601

2602+
JSONTEST_REGISTER_FIXTURE(runner, FuzzTest, fuzzDoesntCrash);
2603+
25882604
return runner.runCommandLine(argc, argv);
25892605
}

0 commit comments

Comments
 (0)