From 4199177aa0c4bff5a604686a95e318cd463bf1a7 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Wed, 28 May 2025 21:09:56 +0200 Subject: [PATCH] Optimize fuzzer --- src/common/utils/string.cpp | 52 +++++++++++++++++++++++++++++ src/common/utils/string.hpp | 7 ++++ src/common/utils/timer.hpp | 8 +++-- src/fuzzing-engine/fuzzer.cpp | 63 +++++++++++++++++++++++++++++++++-- 4 files changed, 126 insertions(+), 4 deletions(-) create mode 100644 src/common/utils/string.cpp diff --git a/src/common/utils/string.cpp b/src/common/utils/string.cpp new file mode 100644 index 00000000..d1451f11 --- /dev/null +++ b/src/common/utils/string.cpp @@ -0,0 +1,52 @@ +#include "string.hpp" + +#include +#include + +namespace utils::string +{ + // NOLINTNEXTLINE(cert-dcl50-cpp) + const char* va(const char* format, ...) + { + constexpr auto buffer_count = 4; + thread_local std::array, buffer_count> buffers{}; + thread_local size_t current_index{0}; + + const auto index = current_index++; + current_index %= buffers.size(); + + auto& buffer = buffers.at(index); + + if (buffer.size() < 10) + { + buffer.resize(10); + } + + while (true) + { + va_list ap{}; + va_start(ap, format); + +#ifdef _WIN32 + const int res = vsnprintf_s(buffer.data(), buffer.size(), _TRUNCATE, format, ap); +#else + const int res = vsnprintf(buffer.data(), buffer.size(), format, ap); +#endif + + va_end(ap); + + if (res > 0 && static_cast(res) < buffer.size()) + { + break; + } + if (res == 0) + { + return nullptr; + } + + buffer.resize(std::max(buffer.size() * 2, static_cast(1))); + } + + return buffer.data(); + } +} diff --git a/src/common/utils/string.hpp b/src/common/utils/string.hpp index 5d88643a..de59dfdd 100644 --- a/src/common/utils/string.hpp +++ b/src/common/utils/string.hpp @@ -1,6 +1,7 @@ #pragma once #include #include +#include #include #include #include @@ -8,6 +9,12 @@ namespace utils::string { +#ifdef __clang__ + __attribute__((__format__(__printf__, 1, 2))) +#endif + const char* + va(const char* format, ...); + template requires(std::is_trivially_copyable_v) // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) diff --git a/src/common/utils/timer.hpp b/src/common/utils/timer.hpp index 22120bce..cea6902e 100644 --- a/src/common/utils/timer.hpp +++ b/src/common/utils/timer.hpp @@ -14,10 +14,14 @@ namespace utils } bool has_elapsed(typename Clock::duration duration) const + { + return this->elapsed() > duration; + } + + typename Clock::duration elapsed() const { const auto now = Clock::now(); - const auto diff = now - this->point_; - return diff > duration; + return now - this->point_; } private: diff --git a/src/fuzzing-engine/fuzzer.cpp b/src/fuzzing-engine/fuzzer.cpp index c5aa4d59..22b8e0a3 100644 --- a/src/fuzzing-engine/fuzzer.cpp +++ b/src/fuzzing-engine/fuzzer.cpp @@ -3,6 +3,10 @@ #include "input_generator.hpp" +#include +#include +#include + namespace fuzzer { namespace @@ -45,6 +49,57 @@ namespace fuzzer std::atomic_bool stop_{false}; }; + std::string format_binary_data(const std::span input) + { + std::string data; + std::string bytes; + std::string text; + + const auto wrap_line = [&] { + if (bytes.empty()) + { + return; + } + + while (bytes.size() < 16 * 3) + { + bytes.push_back(' '); + } + + data += bytes; + data += "| "; + data += text; + data += "\n"; + + bytes.clear(); + text.clear(); + }; + + for (size_t i = 0; i < input.size(); ++i) + { + if (i % 16 == 0) + { + wrap_line(); + } + + const auto in = input[i]; + bytes += utils::string::va("%02X ", static_cast(in)); + text.push_back(isprint(in) ? static_cast(in) : '.'); + } + + wrap_line(); + + return data; + } + + void print_crash(const std::span input) + { + std::string text = utils::string::va("\nFound crash for input (length %zu):\n", input.size()); + text += format_binary_data(input); + + printf("%.*s\n", static_cast(text.size()), text.c_str()); + } + void perform_fuzzing_iteration(fuzzing_context& context, executer& executer) { ++context.executions; @@ -56,8 +111,7 @@ namespace fuzzer if (result == execution_result::error) { - printf("Found error!\n"); - context.stop(); + print_crash(input); } return score; @@ -111,6 +165,7 @@ namespace fuzzer void run(fuzzing_handler& handler, const size_t concurrency) { + const utils::timer<> t{}; input_generator generator{}; fuzzing_context context{generator, handler}; worker_pool pool{context, concurrency}; @@ -125,5 +180,9 @@ namespace fuzzer printf("Executions/s: %" PRIu64 " - Score: %" PRIx64 " - Avg: %.3f\n", executions, highest_scorer.score, avg_score); } + + const auto duration = t.elapsed(); + const int64_t seconds = std::chrono::duration_cast(duration).count(); + printf("Fuzzing stopped after %" PRIi64 "s\n", seconds); } }