blob: fb18c48723623aec41232c7653eb885402ceead1 [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/sys/fuzzing/framework/engine/adapter-client.h"
#include <lib/syslog/cpp/macros.h>
#include <zircon/status.h>
namespace fuzzing {
TargetAdapterClient::TargetAdapterClient(ExecutorPtr executor)
: executor_(executor), eventpair_(executor) {}
void TargetAdapterClient::AddDefaults(Options* options) {
if (!options->has_max_input_size()) {
options->set_max_input_size(kDefaultMaxInputSize);
}
}
void TargetAdapterClient::Configure(const OptionsPtr& options) {
FX_CHECK(options);
if (auto status = test_input_.Reserve(options->max_input_size()); status != ZX_OK) {
FX_LOGS(WARNING) << "Failed to reserve test input: " << zx_status_get_string(status);
}
}
Promise<> TargetAdapterClient::Connect() {
return fpromise::make_promise([this, handling = Future<>(),
connect = Future<>()](Context& context) mutable -> Result<> {
if (!connect) {
if (eventpair_.IsConnected()) {
return fpromise::ok();
}
handler_(ptr_.NewRequest(executor_->dispatcher()));
ptr_.set_error_handler([](zx_status_t status) {});
zx::vmo test_input;
if (auto status = test_input_.Share(&test_input); status != ZX_OK) {
FX_LOGS(WARNING) << "Failed to share test input: " << zx_status_get_string(status);
return fpromise::error();
}
Bridge<> bridge;
ptr_->Connect(eventpair_.Create(), std::move(test_input), bridge.completer.bind());
connect = bridge.consumer.promise_or(fpromise::error());
}
if (!connect(context)) {
return fpromise::pending();
}
return connect.result();
})
.wrap_with(scope_);
}
Promise<std::vector<std::string>> TargetAdapterClient::GetParameters() {
return Connect()
.and_then([this] {
Bridge<std::vector<std::string>> bridge;
ptr_->GetParameters(bridge.completer.bind());
return bridge.consumer.promise_or(fpromise::error());
})
.wrap_with(scope_);
}
std::vector<std::string> TargetAdapterClient::GetSeedCorpusDirectories(
const std::vector<std::string>& parameters) {
std::vector<std::string> seed_corpus_dirs;
bool ignored = false;
std::copy_if(parameters.begin(), parameters.end(), std::back_inserter(seed_corpus_dirs),
[&ignored](const std::string& parameter) {
ignored |= parameter == "--";
return !ignored && !parameter.empty() && parameter[0] != '-';
});
return seed_corpus_dirs;
}
Promise<> TargetAdapterClient::TestOneInput(const Input& test_input) {
if (auto status = test_input_.Write(test_input.data(), test_input.size()); status != ZX_OK) {
FX_LOGS(ERROR) << "Failed to write test input: " << zx_status_get_string(status);
return fpromise::make_error_promise();
}
return Connect()
.inspect([](const Result<>& result) {})
.or_else([] { return fpromise::error(ZX_ERR_CANCELED); })
.and_then([this]() -> ZxResult<> { return AsZxResult(eventpair_.SignalSelf(kFinish, 0)); })
.and_then([this]() -> ZxResult<> { return AsZxResult(eventpair_.SignalPeer(0, kStart)); })
.and_then(eventpair_.WaitFor(kFinish))
.and_then([](const zx_signals_t& observed) -> ZxResult<> { return fpromise::ok(); })
.or_else([](const zx_status_t& status) -> Result<> {
if (status != ZX_ERR_PEER_CLOSED) {
FX_LOGS(ERROR) << "Target adapter returned error: " << zx_status_get_string(status);
return fpromise::error();
}
return fpromise::ok();
})
.wrap_with(scope_);
}
void TargetAdapterClient::Disconnect() {
eventpair_.Reset();
ptr_.Unbind();
}
} // namespace fuzzing