Skip to content

Commit

Permalink
CI: fix fuzzer build and add it to integration workflow (#1756)
Browse files Browse the repository at this point in the history
* ci: fix RpcDaemon fuzzer after PR 1744

* make fmt

* ci: add fuzzer build to integration workflow

* ci: fix syntax

* ci: give fuzzer jobs different names

---------

Co-authored-by: GitHub <[email protected]>
  • Loading branch information
canepat and web-flow authored Jan 14, 2024
1 parent fd6a882 commit 6801437
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 46 deletions.
58 changes: 37 additions & 21 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -316,33 +338,23 @@ 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
docker:
- 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: <<parameters.run_tests>>
steps:
- fuzz-test

linux-wasm-build:
environment:
Expand Down Expand Up @@ -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

Expand All @@ -455,4 +469,6 @@ workflows:
only:
- master
jobs:
- linux-clang-fuzzer
- linux-clang-fuzzer:
name: linux-clang-run-fuzzer
run_tests: true
29 changes: 15 additions & 14 deletions cmd/test/fuzzer_diagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <CLI/CLI.hpp>
#include <gsl/util>

#include <silkworm/rpc/http/channel.hpp>
#include <silkworm/rpc/test/api_test_database.hpp>

#include "address_sanitizer_fix.hpp"
Expand All @@ -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], '[');
Expand All @@ -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";
}
}
}
Expand All @@ -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;
}

Expand All @@ -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();
Expand All @@ -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<int>(reply.status) << std::endl;
std::cout << "Reply Status: " << static_cast<int>(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;
Expand Down
16 changes: 7 additions & 9 deletions cmd/test/fuzzer_investigation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@
#include <iostream>
#include <string>

#include <boost/asio/async_result.hpp>
#include <boost/asio/awaitable.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/asio/co_spawn.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio/io_context.hpp>
Expand All @@ -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<bool> 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");
}

Expand All @@ -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<void> {
io_context, [](const auto& request_str) -> boost::asio::awaitable<void> {
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();
Expand All @@ -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;
Expand Down
7 changes: 5 additions & 2 deletions cmd/test/fuzzer_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@

#include <string>

#include <nlohmann/json.hpp>

#include <silkworm/rpc/http/channel.hpp>
#include <silkworm/rpc/test/api_test_database.hpp>

#include "address_sanitizer_fix.hpp"
Expand All @@ -32,10 +35,10 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {

auto request_handler = RpcApiTestBase<RequestHandler_ForTest>(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;
}

Expand Down

0 comments on commit 6801437

Please sign in to comment.