1*890232f2SAndroid Build Coastguard Worker /*
2*890232f2SAndroid Build Coastguard Worker * Copyright 2014 Google Inc. All rights reserved.
3*890232f2SAndroid Build Coastguard Worker *
4*890232f2SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*890232f2SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*890232f2SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*890232f2SAndroid Build Coastguard Worker *
8*890232f2SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*890232f2SAndroid Build Coastguard Worker *
10*890232f2SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*890232f2SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*890232f2SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*890232f2SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*890232f2SAndroid Build Coastguard Worker * limitations under the License.
15*890232f2SAndroid Build Coastguard Worker */
16*890232f2SAndroid Build Coastguard Worker
17*890232f2SAndroid Build Coastguard Worker #include <stddef.h>
18*890232f2SAndroid Build Coastguard Worker #include <stdint.h>
19*890232f2SAndroid Build Coastguard Worker
20*890232f2SAndroid Build Coastguard Worker #include <clocale>
21*890232f2SAndroid Build Coastguard Worker #include <filesystem>
22*890232f2SAndroid Build Coastguard Worker #include <string>
23*890232f2SAndroid Build Coastguard Worker
24*890232f2SAndroid Build Coastguard Worker #include "cpp17/generated_cpp17/monster_test_generated.h"
25*890232f2SAndroid Build Coastguard Worker #include "flatbuffers/idl.h"
26*890232f2SAndroid Build Coastguard Worker #include "test_assert.h"
27*890232f2SAndroid Build Coastguard Worker #include "test_init.h"
28*890232f2SAndroid Build Coastguard Worker
29*890232f2SAndroid Build Coastguard Worker namespace fs = std::filesystem;
30*890232f2SAndroid Build Coastguard Worker
31*890232f2SAndroid Build Coastguard Worker // Utility for test run.
32*890232f2SAndroid Build Coastguard Worker OneTimeTestInit OneTimeTestInit::one_time_init_;
33*890232f2SAndroid Build Coastguard Worker // The current executable path (see LLVMFuzzerInitialize).
34*890232f2SAndroid Build Coastguard Worker static fs::path exe_path_;
35*890232f2SAndroid Build Coastguard Worker
36*890232f2SAndroid Build Coastguard Worker static flatbuffers::Parser parser_;
37*890232f2SAndroid Build Coastguard Worker
38*890232f2SAndroid Build Coastguard Worker namespace {
39*890232f2SAndroid Build Coastguard Worker
40*890232f2SAndroid Build Coastguard Worker static constexpr size_t kMinInputLength = 1;
41*890232f2SAndroid Build Coastguard Worker static constexpr size_t kMaxInputLength = 16384;
42*890232f2SAndroid Build Coastguard Worker
43*890232f2SAndroid Build Coastguard Worker static constexpr uint8_t flags_strict_json = 0x80;
44*890232f2SAndroid Build Coastguard Worker static constexpr uint8_t flags_skip_unexpected_fields_in_json = 0x40;
45*890232f2SAndroid Build Coastguard Worker static constexpr uint8_t flags_allow_non_utf8 = 0x20;
46*890232f2SAndroid Build Coastguard Worker
TestFileExists(fs::path file_path)47*890232f2SAndroid Build Coastguard Worker bool TestFileExists(fs::path file_path) {
48*890232f2SAndroid Build Coastguard Worker if (file_path.has_filename() && fs::exists(file_path)) return true;
49*890232f2SAndroid Build Coastguard Worker
50*890232f2SAndroid Build Coastguard Worker TEST_OUTPUT_LINE("@DEBUG: file '%s' not found", file_path.string().c_str());
51*890232f2SAndroid Build Coastguard Worker for (const auto &entry : fs::directory_iterator(file_path.parent_path())) {
52*890232f2SAndroid Build Coastguard Worker TEST_OUTPUT_LINE("@DEBUG: parent path entry: '%s'",
53*890232f2SAndroid Build Coastguard Worker entry.path().string().c_str());
54*890232f2SAndroid Build Coastguard Worker }
55*890232f2SAndroid Build Coastguard Worker return false;
56*890232f2SAndroid Build Coastguard Worker }
57*890232f2SAndroid Build Coastguard Worker
LoadBinarySchema(const char * file_name)58*890232f2SAndroid Build Coastguard Worker std::string LoadBinarySchema(const char *file_name) {
59*890232f2SAndroid Build Coastguard Worker const auto file_path = exe_path_.parent_path() / file_name;
60*890232f2SAndroid Build Coastguard Worker TEST_EQ(true, TestFileExists(file_path));
61*890232f2SAndroid Build Coastguard Worker std::string schemafile;
62*890232f2SAndroid Build Coastguard Worker TEST_EQ(true,
63*890232f2SAndroid Build Coastguard Worker flatbuffers::LoadFile(file_path.string().c_str(), true, &schemafile));
64*890232f2SAndroid Build Coastguard Worker
65*890232f2SAndroid Build Coastguard Worker flatbuffers::Verifier verifier(
66*890232f2SAndroid Build Coastguard Worker reinterpret_cast<const uint8_t *>(schemafile.c_str()), schemafile.size());
67*890232f2SAndroid Build Coastguard Worker TEST_EQ(true, reflection::VerifySchemaBuffer(verifier));
68*890232f2SAndroid Build Coastguard Worker return schemafile;
69*890232f2SAndroid Build Coastguard Worker }
70*890232f2SAndroid Build Coastguard Worker
do_test(const flatbuffers::IDLOptions & opts,const std::string input_json,const bool check_parser)71*890232f2SAndroid Build Coastguard Worker std::string do_test(const flatbuffers::IDLOptions &opts,
72*890232f2SAndroid Build Coastguard Worker const std::string input_json, const bool check_parser) {
73*890232f2SAndroid Build Coastguard Worker // (re)define parser options
74*890232f2SAndroid Build Coastguard Worker parser_.opts = opts;
75*890232f2SAndroid Build Coastguard Worker
76*890232f2SAndroid Build Coastguard Worker std::string jsongen;
77*890232f2SAndroid Build Coastguard Worker if (parser_.ParseJson(input_json.c_str())) {
78*890232f2SAndroid Build Coastguard Worker flatbuffers::Verifier verifier(parser_.builder_.GetBufferPointer(),
79*890232f2SAndroid Build Coastguard Worker parser_.builder_.GetSize());
80*890232f2SAndroid Build Coastguard Worker TEST_EQ(true, MyGame::Example::VerifyMonsterBuffer(verifier));
81*890232f2SAndroid Build Coastguard Worker TEST_ASSERT(
82*890232f2SAndroid Build Coastguard Worker GenerateText(parser_, parser_.builder_.GetBufferPointer(), &jsongen));
83*890232f2SAndroid Build Coastguard Worker } else if (check_parser) {
84*890232f2SAndroid Build Coastguard Worker TEST_OUTPUT_LINE("parser failed with JSON:\n%s", input_json.c_str());
85*890232f2SAndroid Build Coastguard Worker TEST_EQ_STR("", parser_.error_.c_str());
86*890232f2SAndroid Build Coastguard Worker TEST_ASSERT(false);
87*890232f2SAndroid Build Coastguard Worker }
88*890232f2SAndroid Build Coastguard Worker return jsongen;
89*890232f2SAndroid Build Coastguard Worker };
90*890232f2SAndroid Build Coastguard Worker } // namespace
91*890232f2SAndroid Build Coastguard Worker
92*890232f2SAndroid Build Coastguard Worker // https://google.github.io/oss-fuzz/further-reading/fuzzer-environment/
93*890232f2SAndroid Build Coastguard Worker // Current working directory
94*890232f2SAndroid Build Coastguard Worker // You should not make any assumptions about the current working directory of
95*890232f2SAndroid Build Coastguard Worker // your fuzz target. If you need to load data files, please use argv[0] to get
96*890232f2SAndroid Build Coastguard Worker // the directory where your fuzz target executable is located.
97*890232f2SAndroid Build Coastguard Worker // You must not modify argv[0].
LLVMFuzzerInitialize(int * argc,char *** argv)98*890232f2SAndroid Build Coastguard Worker extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) {
99*890232f2SAndroid Build Coastguard Worker (void)argc;
100*890232f2SAndroid Build Coastguard Worker exe_path_ = (*argv)[0];
101*890232f2SAndroid Build Coastguard Worker
102*890232f2SAndroid Build Coastguard Worker static const std::string schemafile = LoadBinarySchema("monster_test.bfbs");
103*890232f2SAndroid Build Coastguard Worker // parse schema first, so we can use it to parse the data after
104*890232f2SAndroid Build Coastguard Worker parser_.Deserialize(reinterpret_cast<const uint8_t *>(schemafile.c_str()),
105*890232f2SAndroid Build Coastguard Worker schemafile.size());
106*890232f2SAndroid Build Coastguard Worker return 0;
107*890232f2SAndroid Build Coastguard Worker }
108*890232f2SAndroid Build Coastguard Worker
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)109*890232f2SAndroid Build Coastguard Worker extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
110*890232f2SAndroid Build Coastguard Worker // Reserve one byte for Parser flags and one byte for repetition counter.
111*890232f2SAndroid Build Coastguard Worker if (size < 3) return 0;
112*890232f2SAndroid Build Coastguard Worker const uint8_t flags = data[0];
113*890232f2SAndroid Build Coastguard Worker (void)data[1]; // reserved
114*890232f2SAndroid Build Coastguard Worker data += 2;
115*890232f2SAndroid Build Coastguard Worker size -= 2; // bypass
116*890232f2SAndroid Build Coastguard Worker
117*890232f2SAndroid Build Coastguard Worker const std::string original(reinterpret_cast<const char *>(data), size);
118*890232f2SAndroid Build Coastguard Worker auto input = std::string(original.c_str()); // until '\0'
119*890232f2SAndroid Build Coastguard Worker if (input.size() < kMinInputLength || input.size() > kMaxInputLength)
120*890232f2SAndroid Build Coastguard Worker return 0;
121*890232f2SAndroid Build Coastguard Worker
122*890232f2SAndroid Build Coastguard Worker flatbuffers::IDLOptions opts;
123*890232f2SAndroid Build Coastguard Worker opts.strict_json = (flags & flags_strict_json);
124*890232f2SAndroid Build Coastguard Worker opts.skip_unexpected_fields_in_json =
125*890232f2SAndroid Build Coastguard Worker (flags & flags_skip_unexpected_fields_in_json);
126*890232f2SAndroid Build Coastguard Worker opts.allow_non_utf8 = (flags & flags_allow_non_utf8);
127*890232f2SAndroid Build Coastguard Worker
128*890232f2SAndroid Build Coastguard Worker do {
129*890232f2SAndroid Build Coastguard Worker const std::string jsongen_1 = do_test(opts, input, false);
130*890232f2SAndroid Build Coastguard Worker if (!jsongen_1.empty()) {
131*890232f2SAndroid Build Coastguard Worker const std::string jsongen_2 = do_test(opts, jsongen_1, true);
132*890232f2SAndroid Build Coastguard Worker if (jsongen_1 != jsongen_2 && !opts.output_default_scalars_in_json) {
133*890232f2SAndroid Build Coastguard Worker // This gets tricky when the jsongen_1 includes a default-value, as the
134*890232f2SAndroid Build Coastguard Worker // generated jsongen_2 doesn't emit default-values. So enable default
135*890232f2SAndroid Build Coastguard Worker // scalars and re-run it.
136*890232f2SAndroid Build Coastguard Worker opts.output_default_scalars_in_json = true;
137*890232f2SAndroid Build Coastguard Worker continue;
138*890232f2SAndroid Build Coastguard Worker }
139*890232f2SAndroid Build Coastguard Worker TEST_EQ(jsongen_1, jsongen_2);
140*890232f2SAndroid Build Coastguard Worker }
141*890232f2SAndroid Build Coastguard Worker } while (0);
142*890232f2SAndroid Build Coastguard Worker
143*890232f2SAndroid Build Coastguard Worker return 0;
144*890232f2SAndroid Build Coastguard Worker }
145