Squashed 'third_party/flatbuffers/' changes from d6a8dbd26..338393f85
338393f85 Documentation updates for Optional Scalars (#6014) (#6270)
c27bc2d76 [C++] Add ParseJson(), Parser(Parser&&), update fuzzers (#6284)
bc518a512 Fixed FlexBufferBuilder asserting on duplicate keys
100c59054 Added a few more paths for auto labeler (#6281)
e58c18244 Add --require-explicit-ids to require explicit ids (#6277)
69a8b2a57 idl_gen_json_schema.cpp: Changed generation of array element types (#6253)
25eba6f35 fix typo (#6280)
e1f0f75ba Updated Ms build Action to fix build issue (#6279)
faeb04fbe Add type annotation to unspecified array (#6264)
537212afe [Swift] Adds a format file and reformats the swift project (#6250)
6764f25d9 Adds a fix for enum generation (#6263)
Change-Id: I716bd4d2521fb0a673e50a699cef761e042052b2
git-subtree-dir: third_party/flatbuffers
git-subtree-split: 338393f854eb5ba24761a22cd9316ff5cee4eab0
diff --git a/tests/fuzzer/CMakeLists.txt b/tests/fuzzer/CMakeLists.txt
index fbd9295..5deba0f 100644
--- a/tests/fuzzer/CMakeLists.txt
+++ b/tests/fuzzer/CMakeLists.txt
@@ -29,7 +29,7 @@
add_compile_options(
# -stdlib=libc++ # Use Clang libc++ instead of GNU.
- -std=c++14
+ -std=c++17
-Wall
-pedantic
-Werror
@@ -52,7 +52,9 @@
target_compile_options(
fuzzer_config
INTERFACE
- #-fsanitize-coverage=edge,trace-cmp
+ $<$<NOT:$<BOOL:${OSS_FUZZ}>>:
+ -fsanitize-coverage=edge,trace-cmp
+ >
$<$<BOOL:${USE_ASAN}>:
-fsanitize=fuzzer,undefined,address
>
@@ -131,6 +133,9 @@
add_executable(verifier_fuzzer flatbuffers_verifier_fuzzer.cc)
target_link_libraries(verifier_fuzzer PRIVATE flatbuffers_fuzzed)
+add_executable(monster_fuzzer flatbuffers_monster_fuzzer.cc)
+target_link_libraries(monster_fuzzer PRIVATE flatbuffers_fuzzed)
+
# Build debugger for weird cases found with fuzzer.
if(BUILD_DEBUGGER)
add_library(flatbuffers_nonfuzz STATIC ${FlatBuffers_Library_SRCS})
diff --git a/tests/fuzzer/flatbuffers_monster_fuzzer.cc b/tests/fuzzer/flatbuffers_monster_fuzzer.cc
new file mode 100644
index 0000000..9464607
--- /dev/null
+++ b/tests/fuzzer/flatbuffers_monster_fuzzer.cc
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <clocale>
+#include <string>
+
+#include "cpp17/generated_cpp17/monster_test_generated.h"
+#include "flatbuffers/idl.h"
+#include "test_init.h"
+
+namespace {
+constexpr bool use_binary_schema = true;
+// should point to flatbuffers/tests/
+constexpr const char *test_data_path = "../../";
+constexpr const char *schema_file_name = "monster_test";
+
+static constexpr uint8_t flags_strict_json = 0x80;
+static constexpr uint8_t flags_skip_unexpected_fields_in_json = 0x40;
+static constexpr uint8_t flags_allow_non_utf8 = 0x20;
+
+flatbuffers::Parser make_parser(const flatbuffers::IDLOptions opts) {
+ // once loaded from disk
+ static const std::string schemafile = [&]() {
+ std::string schemafile;
+ TEST_EQ(
+ flatbuffers::LoadFile((std::string(test_data_path) + schema_file_name +
+ (use_binary_schema ? ".bfbs" : ".fbs"))
+ .c_str(),
+ use_binary_schema, &schemafile),
+ true);
+
+ if (use_binary_schema) {
+ flatbuffers::Verifier verifier(
+ reinterpret_cast<const uint8_t *>(schemafile.c_str()),
+ schemafile.size());
+ TEST_EQ(reflection::VerifySchemaBuffer(verifier), true);
+ }
+ return schemafile;
+ }();
+
+ // parse schema first, so we can use it to parse the data after
+ flatbuffers::Parser parser;
+ if (use_binary_schema) {
+ TEST_EQ(parser.Deserialize(
+ reinterpret_cast<const uint8_t *>(schemafile.c_str()),
+ schemafile.size()),
+ true);
+ } else {
+ auto include_test_path =
+ flatbuffers::ConCatPathFileName(test_data_path, "include_test");
+ const char *include_directories[] = { test_data_path,
+ include_test_path.c_str(), nullptr };
+ TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
+ }
+ // (re)define parser options
+ parser.opts = opts;
+ return parser;
+}
+
+std::string do_test(const flatbuffers::IDLOptions &opts,
+ const std::string input_json) {
+ auto parser = make_parser(opts);
+ std::string jsongen;
+ if (parser.ParseJson(input_json.c_str())) {
+ flatbuffers::Verifier verifier(parser.builder_.GetBufferPointer(),
+ parser.builder_.GetSize());
+ TEST_EQ(MyGame::Example::VerifyMonsterBuffer(verifier), true);
+ TEST_ASSERT(
+ GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen));
+ }
+ return jsongen;
+};
+} // namespace
+
+// Utility for test run.
+OneTimeTestInit OneTimeTestInit::one_time_init_;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ // Reserve one byte for Parser flags and one byte for repetition counter.
+ if (size < 3) return 0;
+ const uint8_t flags = data[0];
+ (void)data[1]; // reserved
+ data += 2;
+ size -= 2; // bypass
+
+ const std::string original(reinterpret_cast<const char *>(data), size);
+ auto input = std::string(original.c_str()); // until '\0'
+ if (input.empty()) return 0;
+
+ flatbuffers::IDLOptions opts;
+ opts.strict_json = (flags & flags_strict_json);
+ opts.skip_unexpected_fields_in_json =
+ (flags & flags_skip_unexpected_fields_in_json);
+ opts.allow_non_utf8 = (flags & flags_allow_non_utf8);
+
+ const std::string jsongen_1 = do_test(opts, input);
+ if (!jsongen_1.empty()) {
+ const std::string jsongen_2 = do_test(opts, jsongen_1);
+ TEST_EQ(jsongen_1, jsongen_2);
+ }
+ return 0;
+}
diff --git a/tests/fuzzer/flatbuffers_parser_fuzzer.cc b/tests/fuzzer/flatbuffers_parser_fuzzer.cc
index 6646cd6..a7483a5 100644
--- a/tests/fuzzer/flatbuffers_parser_fuzzer.cc
+++ b/tests/fuzzer/flatbuffers_parser_fuzzer.cc
@@ -9,14 +9,9 @@
#include "flatbuffers/idl.h"
#include "test_init.h"
-static constexpr uint8_t flags_strict_json = 0x01;
-static constexpr uint8_t flags_skip_unexpected_fields_in_json = 0x02;
-static constexpr uint8_t flags_allow_non_utf8 = 0x04;
-// static constexpr uint8_t flags_flag_3 = 0x08;
-// static constexpr uint8_t flags_flag_4 = 0x10;
-// static constexpr uint8_t flags_flag_5 = 0x20;
-// static constexpr uint8_t flags_flag_6 = 0x40;
-// static constexpr uint8_t flags_flag_7 = 0x80;
+static constexpr uint8_t flags_strict_json = 0x80;
+static constexpr uint8_t flags_skip_unexpected_fields_in_json = 0x40;
+static constexpr uint8_t flags_allow_non_utf8 = 0x20;
// Utility for test run.
OneTimeTestInit OneTimeTestInit::one_time_init_;
diff --git a/tests/fuzzer/flatbuffers_scalar_fuzzer.cc b/tests/fuzzer/flatbuffers_scalar_fuzzer.cc
index ea8878a..3c711fc 100644
--- a/tests/fuzzer/flatbuffers_scalar_fuzzer.cc
+++ b/tests/fuzzer/flatbuffers_scalar_fuzzer.cc
@@ -1,6 +1,23 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
+
#include <algorithm>
#include <clocale>
#include <memory>
@@ -196,7 +213,7 @@
bool Parse(flatbuffers::Parser &parser, const std::string &json,
std::string *_text) {
- auto done = parser.Parse(json.c_str());
+ auto done = parser.ParseJson(json.c_str());
if (done) {
TEST_EQ(GenerateText(parser, parser.builder_.GetBufferPointer(), _text),
true);
diff --git a/tests/fuzzer/flatbuffers_verifier_fuzzer.cc b/tests/fuzzer/flatbuffers_verifier_fuzzer.cc
index d7d453c..cb32a85 100644
--- a/tests/fuzzer/flatbuffers_verifier_fuzzer.cc
+++ b/tests/fuzzer/flatbuffers_verifier_fuzzer.cc
@@ -5,7 +5,7 @@
#include <stdint.h>
#include <string>
-#include "monster_test_generated.h"
+#include "cpp17/generated_cpp17/monster_test_generated.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
flatbuffers::Verifier verifier(data, size);
diff --git a/tests/fuzzer/monster_json.dict b/tests/fuzzer/monster_json.dict
new file mode 100644
index 0000000..a06e1e0
--- /dev/null
+++ b/tests/fuzzer/monster_json.dict
@@ -0,0 +1,60 @@
+"{"
+"}"
+"["
+"]"
+"\""
+"'"
+"\\"
+"//"
+":"
+","
+" "
+"\\n"
+"\\r"
+"/*"
+"*/"
+"true"
+"false"
+"null"
+"\\u"
+"\\b"
+"\\f"
+"\\t"
+"."
+"e"
+"e+"
+"e-"
+"E"
+"E+"
+"E-"
+"0x"
+"p"
+"a"
+"b"
+"Monster"
+"pos"
+"hp"
+"name"
+"weapons"
+"damage"
+"equipped_type"
+"equipped"
+"inventory"
+"vector_of_longs"
+"vector_of_doubles"
+"test_type"
+"test"
+"test1"
+"test2"
+"test4"
+"test3"
+"test5"
+"enemy"
+"Weapon"
+"Green"
+"Red"
+"Blue"
+"testarrayofstring"
+"testarrayofbools"
+"testbool"
+"flex"
diff --git a/tests/fuzzer/parser_fbs.dict b/tests/fuzzer/parser_fbs.dict
new file mode 100644
index 0000000..44c18da
--- /dev/null
+++ b/tests/fuzzer/parser_fbs.dict
@@ -0,0 +1,101 @@
+"struct"
+"table"
+"enum"
+"union"
+"include"
+"namespace"
+"attribute"
+"null"
+"NULL"
+"byte"
+"int8"
+"ubyte"
+"uint8"
+"bool"
+"short"
+"int16"
+"ushort"
+"uint16"
+"int"
+"int32"
+"uint"
+"uint32"
+"float"
+"float32"
+"long"
+"int64"
+"ulong"
+"uint64"
+"double"
+"float64"
+"root_type"
+"file_identifier"
+"file_extension"
+"{"
+"}"
+"["
+"]"
+"\""
+"'"
+"\\"
+"//"
+":"
+","
+" "
+"\\n"
+"\\r"
+"/*"
+"*/"
+"true"
+"false"
+"null"
+"\\u"
+"\\b"
+"\\f"
+"\\t"
+"."
+"e"
+"e+"
+"e-"
+"E"
+"E+"
+"E-"
+"0x"
+"p"
+"a"
+"b"
+"Monster"
+"pos"
+"hp"
+"name"
+"weapons"
+"damage"
+"equipped_type"
+"equipped"
+"inventory"
+"vector_of_longs"
+"vector_of_doubles"
+"test_type"
+"test"
+"test1"
+"test2"
+"test4"
+"test3"
+"test5"
+"enemy"
+"Weapon"
+"Green"
+"Red"
+"Blue"
+"testarrayofstring"
+"testarrayofbools"
+"testbool"
+"testhashs32_fnv1"
+"testhashu32_fnv1"
+"testhashs64_fnv1"
+"testhashu64_fnv1"
+"testhashs32_fnv1a"
+"testhashu32_fnv1a"
+"testhashs64_fnv1a"
+"testhashu64_fnv1a"
+"flex"
diff --git a/tests/fuzzer/readme.md b/tests/fuzzer/readme.md
index c5e147b..b2c7db4 100644
--- a/tests/fuzzer/readme.md
+++ b/tests/fuzzer/readme.md
@@ -29,27 +29,43 @@
Flags may vary and depend on a version of the libFuzzer library.
For details, run a fuzzer with `-help` flag: `./parser_fuzzer -help=1`
-`./verifier_fuzzer -reduce_depth=1 -use_value_profile=1 -shrink=1 ../.corpus_verifier/`
+`./verifier_fuzzer ../.corpus_verifier/ ../.seed_verifier/`
-`./parser_fuzzer -reduce_depth=1 -use_value_profile=1 -shrink=1 ../.corpus_parser/`
+`./parser_fuzzer -only_ascii=1 -max_len=500 -dict=../parser_fbs.dict ../.corpus_parser/ ../.seed_parser/`
-`./scalar_fuzzer -reduce_depth=1 -use_value_profile=1 -shrink=1 -max_len=3000 ../.corpus_parser/ ../.seed_parser/`
+`./monster_fuzzer -only_ascii=1 -max_len=500 -dict=../monster_json.dict ../.corpus_monster/ ../.seed_monster/`
-Flag `-only_ascii=1` is useful for fast number-compatibility checking while run `scalar_fuzzer`:
-`./scalar_fuzzer -only_ascii=1 -reduce_depth=1 -use_value_profile=1 -shrink=1 -max_len=3000 -timeout=10 -rss_limit_mb=2048 -jobs=2 ../.corpus_parser/ ../.seed_parser/`
+`./scalar_fuzzer -use_value_profile=1 -max_len=500 -dict=../scalar_json.dict ../.corpus_scalar/ ../.seed_scalar/`
-Run with a specific C-locale:
+Flag `-only_ascii=1` is useful for fast number-compatibility checking while run `scalar_fuzzer`.
+
+Run with a specific C-locale:
`FLATBUFFERS_TEST_LOCALE="ru_RU.CP1251" ./scalar_fuzzer -reduce_depth=1 -use_value_profile=1 -shrink=1 -max_len=3000 -timeout=10 -rss_limit_mb=2048 ../.corpus_parser/ ../.seed_parser/`
+
## Merge (minimize) corpus
The **libFuzzer** allow to filter (minimize) corpus with help of `-merge` flag:
> -merge
If set to 1, any corpus inputs from the 2nd, 3rd etc. corpus directories that trigger new code coverage will be merged into the first corpus directory.
Defaults to 0. This flag can be used to minimize a corpus.
-Merge several seeds to one (a new collected corpus to the seed collection, for example):
-`./scalar_fuzzer -merge=1 ../.seed_parser/ ../.corpus_parser/`
+Merge several corpuses to a seed directory (a new collected corpus to the seed collection, for example):
+`./verifier_fuzzer -merge=1 ../.seed_verifier/ ../.corpus_verifier/`
+`./parser_fuzzer -merge=1 ../.seed_parser/ ../.corpus_parser/`
+`./monster_fuzzer -merge=1 ../.seed_monster/ ../.corpus_monster/`
+`./scalar_fuzzer -merge=1 ../.seed_scalar/ ../.corpus_scalar/`
## Know limitations
- LLVM 7.0 std::regex library has problem with stack overflow, maximum length of input for `scalar_fuzzer` run should be limited to 3000.
Example: `./scalar_fuzzer -max_len=3000`
+
+# Fuzzing control
+
+## Set timeout or memory limit
+
+`-timeout=10 -rss_limit_mb=2048 -jobs=4 -workers=4`.
+
+## Force stop on first UBSAN error
+
+- `export UBSAN_OPTIONS=halt_on_error=1`
+- `export ASAN_OPTIONS=halt_on_error=1`
diff --git a/tests/fuzzer/scalar_json.dict b/tests/fuzzer/scalar_json.dict
new file mode 100644
index 0000000..60689dd
--- /dev/null
+++ b/tests/fuzzer/scalar_json.dict
@@ -0,0 +1,23 @@
+"-"
+"+"
+"."
+"e"
+"e+"
+"e-"
+"E"
+"E+"
+"E-"
+"0x"
+"-0x"
+"p"
+"a"
+"b"
+"c"
+"d"
+"e"
+"f"
+"nan"
+"inf"
+"-inf"
+"infinity"
+"-infinity"