From c992eafb5b50f1aab9d7863864a0a49fe278836e Mon Sep 17 00:00:00 2001 From: Vladimir Glavnyy <31897320+vglavnyy@users.noreply.github.com> Date: Fri, 19 Mar 2021 00:56:28 +0700 Subject: [PATCH] [fuzzer] Add `monster_debug` target (#6513) Add the `monster_debug` target for better troubleshooting. Improve oss-fuzz logs. --- tests/fuzzer/CMakeLists.txt | 12 +++++++++ tests/fuzzer/flatbuffers_monster_fuzzer.cc | 17 +++++++----- tests/fuzzer/fuzzer_assert.h | 9 +++++-- tests/fuzzer/monster_debug.cpp | 30 ++++++++++++++++++++++ 4 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 tests/fuzzer/monster_debug.cpp diff --git a/tests/fuzzer/CMakeLists.txt b/tests/fuzzer/CMakeLists.txt index 906fbdc16..e57343b2b 100644 --- a/tests/fuzzer/CMakeLists.txt +++ b/tests/fuzzer/CMakeLists.txt @@ -175,4 +175,16 @@ if(BUILD_DEBUGGER) scalar_debug.cpp ) target_link_libraries(scalar_debug PRIVATE flatbuffers_nonfuzz) + + add_executable(monster_debug + flatbuffers_monster_fuzzer.cc + monster_debug.cpp + ) + target_link_libraries(monster_debug PRIVATE flatbuffers_nonfuzz) + add_custom_command( + TARGET monster_debug PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_SOURCE_DIR}/../monster_test.bfbs + ${CMAKE_CURRENT_BINARY_DIR}/monster_test.bfbs) + endif(BUILD_DEBUGGER) diff --git a/tests/fuzzer/flatbuffers_monster_fuzzer.cc b/tests/fuzzer/flatbuffers_monster_fuzzer.cc index 1609c71e8..8981c2f10 100644 --- a/tests/fuzzer/flatbuffers_monster_fuzzer.cc +++ b/tests/fuzzer/flatbuffers_monster_fuzzer.cc @@ -44,9 +44,9 @@ static constexpr uint8_t flags_allow_non_utf8 = 0x20; bool TestFileExists(fs::path file_path) { if (file_path.has_filename() && fs::exists(file_path)) return true; - TEST_OUTPUT_LINE("@DEBUG: file '%s' not found", file_path.c_str()); + TEST_OUTPUT_LINE("@DEBUG: file '%s' not found", file_path.string().c_str()); for (const auto &entry : fs::directory_iterator(file_path.parent_path())) { - TEST_OUTPUT_LINE("@DEBUG: parent path entry: '%s'", entry.path().c_str()); + TEST_OUTPUT_LINE("@DEBUG: parent path entry: '%s'", entry.path().string().c_str()); } return false; } @@ -55,7 +55,7 @@ std::string LoadBinarySchema(const char *file_name) { const auto file_path = exe_path_.parent_path() / file_name; TEST_EQ(true, TestFileExists(file_path)); std::string schemafile; - TEST_EQ(true, flatbuffers::LoadFile(file_path.c_str(), true, &schemafile)); + TEST_EQ(true, flatbuffers::LoadFile(file_path.string().c_str(), true, &schemafile)); flatbuffers::Verifier verifier( reinterpret_cast(schemafile.c_str()), schemafile.size()); @@ -64,7 +64,7 @@ std::string LoadBinarySchema(const char *file_name) { } std::string do_test(const flatbuffers::IDLOptions &opts, - const std::string input_json) { + const std::string input_json, const bool check_parser) { // once loaded from disk static const std::string schemafile = LoadBinarySchema("monster_test.bfbs"); // parse schema first, so we can use it to parse the data after @@ -82,6 +82,10 @@ std::string do_test(const flatbuffers::IDLOptions &opts, TEST_EQ(true, MyGame::Example::VerifyMonsterBuffer(verifier)); TEST_ASSERT( GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen)); + } else if (check_parser) { + TEST_OUTPUT_LINE("parser failed with JSON:\n%s", input_json.c_str()); + TEST_EQ_STR("", parser.error_.c_str()); + TEST_ASSERT(false); } return jsongen; }; @@ -94,6 +98,7 @@ std::string do_test(const flatbuffers::IDLOptions &opts, // the directory where your fuzz target executable is located. // You must not modify argv[0]. extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) { + (void)argc; exe_path_ = (*argv)[0]; return 0; } @@ -117,9 +122,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { (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); + const std::string jsongen_1 = do_test(opts, input, false); if (!jsongen_1.empty()) { - const std::string jsongen_2 = do_test(opts, jsongen_1); + const std::string jsongen_2 = do_test(opts, jsongen_1, true); TEST_EQ(jsongen_1, jsongen_2); } return 0; diff --git a/tests/fuzzer/fuzzer_assert.h b/tests/fuzzer/fuzzer_assert.h index afdcf78ac..41a4164e9 100644 --- a/tests/fuzzer/fuzzer_assert.h +++ b/tests/fuzzer/fuzzer_assert.h @@ -1,9 +1,14 @@ #ifndef FUZZER_ASSERT_IMPL_H_ #define FUZZER_ASSERT_IMPL_H_ +#if defined(_MSC_VER) +extern "C" void __debugbreak(); +#define __builtin_trap __debugbreak +#else // Clang +extern "C" void __builtin_trap(void); +#endif + // Declare Debug/Release independed assert macro. #define fuzzer_assert_impl(x) (!!(x) ? static_cast(0) : __builtin_trap()) -extern "C" void __builtin_trap(void); - #endif // !FUZZER_ASSERT_IMPL_H_ diff --git a/tests/fuzzer/monster_debug.cpp b/tests/fuzzer/monster_debug.cpp new file mode 100644 index 000000000..c7a02e128 --- /dev/null +++ b/tests/fuzzer/monster_debug.cpp @@ -0,0 +1,30 @@ +#include +#include + +#include "flatbuffers/util.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); + +int main(int argc, char *argv[]) { + if (argc < 2) { + std::cerr << "Usage: monster_debug \n"; + return 0; + } + std::string crash_file_name(argv[1]); + std::string crash_file_data; + auto done = + flatbuffers::LoadFile(crash_file_name.c_str(), true, &crash_file_data); + if (!done) { + std::cerr << "Can not load file: '" << crash_file_name << "'"; + return -1; + } + if (crash_file_data.size() < 3) { + std::cerr << "Invalid file data: '" << crash_file_data << "'"; + return -2; + } + auto rc = LLVMFuzzerTestOneInput( + reinterpret_cast(crash_file_data.data()), + crash_file_data.size()); + std::cout << "LLVMFuzzerTestOneInput finished with code " << rc << "\n\n"; + return rc; +}