xref: /aosp_15_r20/external/flatbuffers/tests/fuzzer/flatbuffers_monster_fuzzer.cc (revision 890232f25432b36107d06881e0a25aaa6b473652)
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