diff --git a/.circleci/config.yml b/.circleci/config.yml index 97efd00f17..e2e766707e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -121,6 +121,28 @@ commands: paths: - ~/.conan + build_fuzzer: + steps: + - checkout_with_submodules: + ethereum_tests: false + - run: + name: "Ensure pip" + command: | + sudo apt-get update + sudo apt install -y python3-pip + sudo pip install conan==1.60.2 chardet + sudo apt-get update + - run: + name: "Install compiler" + command: cmake/setup/compiler_install.sh clang 15 + - run: + name: "CMake Fuzzer" + working_directory: ~/build + command: cmake ../project -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCONAN_PROFILE=linux_clang_13_release -DCMAKE_TOOLCHAIN_FILE=../project/cmake/toolchain/clang_libcxx.cmake -DSILKWORM_FUZZER=ON + - run: + name: "Build Fuzzer" + command: cmake --build ~/build -j4 --target rpcdaemon_fuzzer_test + test: parameters: ethereum_tests: @@ -316,6 +338,11 @@ jobs: path: /tmp/report.html linux-clang-fuzzer: + parameters: + run_tests: + description: Run fuzzy tests if required. + type: boolean + default: false environment: BUILD_CMAKE_ARGS: -DSILKWORM_FUZZER=ON UBSAN_OPTIONS: print_stacktrace=1 @@ -323,26 +350,11 @@ jobs: - image: cimg/python:3.12 resource_class: 2xlarge steps: - - checkout_with_submodules: - ethereum_tests: false - - run: - name: "Ensure pip" - command: | - sudo apt-get update - sudo apt install -y python3-pip - sudo pip install conan==1.60.2 chardet - sudo apt-get update - - run: - name: "Install compiler" - command: cmake/setup/compiler_install.sh clang 15 - - run: - name: "CMake Fuzzer" - working_directory: ~/build - command: cmake ../project -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCONAN_PROFILE=linux_clang_13_release -DCMAKE_TOOLCHAIN_FILE=../project/cmake/toolchain/clang_libcxx.cmake -DSILKWORM_FUZZER=ON - - run: - name: "Build Fuzzer" - command: cmake --build ~/build -j4 --target rpcdaemon_fuzzer_test - - fuzz-test + - build_fuzzer + - when: + condition: <> + steps: + - fuzz-test linux-wasm-build: environment: @@ -443,6 +455,8 @@ workflows: - linux-gcc-thread-sanitizer - linux-clang-coverage - linux-clang-address-sanitizer + - linux-clang-fuzzer: + name: linux-clang-fuzzer - linux-clang-tidy - linux-wasm-build @@ -455,4 +469,6 @@ workflows: only: - master jobs: - - linux-clang-fuzzer + - linux-clang-fuzzer: + name: linux-clang-run-fuzzer + run_tests: true diff --git a/cmd/test/fuzzer_diagnostics.cpp b/cmd/test/fuzzer_diagnostics.cpp index fe56d5bf21..716ebbea82 100644 --- a/cmd/test/fuzzer_diagnostics.cpp +++ b/cmd/test/fuzzer_diagnostics.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include "address_sanitizer_fix.hpp" @@ -32,9 +33,9 @@ void print_stack_trace() { int trace_size = backtrace(trace, 16); char** messages = backtrace_symbols(trace, trace_size); [[maybe_unused]] auto _ = gsl::finally([&messages] { free(messages); }); - std::cout << "Stack Trace:" << std::endl; + std::cout << "Stack Trace:\n"; for (int i = 0; i < trace_size; i++) { - std::cout << messages[i] << std::endl; + std::cout << messages[i] << "\n"; // extract the address from the message char* address = strchr(messages[i], '['); @@ -45,9 +46,9 @@ void print_stack_trace() { *end = '\0'; // use addr2line to get the file name and line number std::string command = "addr2line -e ./rpcdaemon_fuzzer_diagnostics " + std::string(address); - auto command_result = system(command.c_str()); + auto command_result = system(command.c_str()); // NOLINT(cert-*) if (command_result != 0) { - std::cout << "addr2line failed" << std::endl; + std::cout << "addr2line failed\n"; } } } @@ -61,17 +62,17 @@ int main(int argc, char* argv[]) { std::string input_file; app.add_option("input", input_str, "Input string") - ->description("Wrap JSON in '' to avoid shell escaping, e.g. '{\"jsonrpc\":\"2.0\",\"id\":1}'") + ->description(R"(Wrap JSON in '' to avoid shell escaping, e.g. '{"jsonrpc":"2.0","id":1}')") ->required(false); app.add_option("-f", input_file, "Path to the JSON request file") ->check(CLI::ExistingFile) ->required(false); - CLI11_PARSE(app, argc, argv); + CLI11_PARSE(app, argc, argv) if (input_str.empty() && input_file.empty()) { - std::cerr << "Either input string or input file must be provided" << std::endl; + std::cerr << "Either input string or input file must be provided\n"; return -1; } @@ -81,13 +82,13 @@ int main(int argc, char* argv[]) { } if (!nlohmann::json::accept(input_str)) { - std::cout << "Not valid json: " << input_str << std::endl; + std::cout << "Not valid json: " << input_str << "\n"; } else { auto request_json = nlohmann::json::parse(input_str); - std::cout << "Request: " << request_json.dump(4) << std::endl; + std::cout << "Request: " << request_json.dump(4) << "\n"; } - silkworm::rpc::http::Reply reply; + silkworm::rpc::Channel::Response reply; try { auto context = silkworm::rpc::test::TestDatabaseContext(); @@ -101,17 +102,17 @@ int main(int argc, char* argv[]) { std::rethrow_exception(eptr); } } catch (const std::exception& e) { - std::cout << "Caught exception: " << e.what() << std::endl; + std::cout << "Caught exception: " << e.what() << "\n"; print_stack_trace(); } } - std::cout << "Reply Status: " << static_cast(reply.status) << std::endl; + std::cout << "Reply Status: " << static_cast(reply.status) << "\n"; if (nlohmann::json::accept(reply.content)) { - std::cout << "Reply Content: " << nlohmann::json::parse(reply.content).dump(4) << std::endl; + std::cout << "Reply Content: " << nlohmann::json::parse(reply.content).dump(4) << "\n"; } else { - std::cout << "Reply Content: " << reply.content << std::endl; + std::cout << "Reply Content: " << reply.content << "\n"; } return 0; diff --git a/cmd/test/fuzzer_investigation.cpp b/cmd/test/fuzzer_investigation.cpp index 8df4939f61..46de86111e 100644 --- a/cmd/test/fuzzer_investigation.cpp +++ b/cmd/test/fuzzer_investigation.cpp @@ -17,9 +17,7 @@ #include #include -#include #include -#include #include #include #include @@ -33,15 +31,15 @@ class RequestHandler_ForTest { try { co_await is_valid_json(request_str); } catch (const std::invalid_argument& e) { - std::cerr << "Invalid argument: " << e.what() << std::endl; + std::cerr << "Invalid argument: " << e.what() << "\n"; } catch (...) { - std::cerr << "Error occurred" << std::endl; + std::cerr << "Error occurred\n"; } } boost::asio::awaitable is_valid_json(const std::string& request_str) { if (request_str.length() == 20) { - std::cout << "Target length found, terminating, request_str: " << request_str << std::endl; + std::cout << "Target length found, terminating, request_str: " << request_str << "\n"; throw std::invalid_argument("Invalid argument"); } @@ -55,14 +53,14 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { try { auto io_context = boost::asio::io_context{}; auto result = boost::asio::co_spawn( - io_context, [&request_str]() -> boost::asio::awaitable { + io_context, [](const auto& request_str) -> boost::asio::awaitable { try { RequestHandler_ForTest handler{}; co_await handler.handle_request(request_str); } catch (const std::exception& e) { std::cerr << e.what() << '\n'; } - }, + }(request_str), boost::asio::use_future); io_context.run(); @@ -72,9 +70,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { io_context.restart(); } catch (const std::exception& e) { - std::cerr << "Error: " << e.what() << std::endl; + std::cerr << "Error: " << e.what() << "\n"; } catch (...) { - std::cout << "Error" << std::endl; + std::cout << "Error\n"; } return 0; diff --git a/cmd/test/fuzzer_test.cpp b/cmd/test/fuzzer_test.cpp index 37218aaa85..6c579726c3 100644 --- a/cmd/test/fuzzer_test.cpp +++ b/cmd/test/fuzzer_test.cpp @@ -16,6 +16,9 @@ #include +#include + +#include #include #include "address_sanitizer_fix.hpp" @@ -32,10 +35,10 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { auto request_handler = RpcApiTestBase(context.db); auto request_json = nlohmann::json::parse(request_str); - silkworm::rpc::http::Reply reply; + silkworm::rpc::Channel::Response reply; request_handler.run<&RequestHandler_ForTest::handle_request>(request_str, reply); - if (reply.status == silkworm::rpc::http::StatusType::ok) { + if (reply.status == silkworm::rpc::Channel::ResponseStatus::ok) { return 0; }