blob: fdba29536355830bd8efd4a4f0b0235a1f93144d [file] [log] [blame]
// Copyright 2020 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 "data-provider.h"
#include <lib/syslog/cpp/macros.h>
#include <zircon/status.h>
#include <algorithm>
#include <string_view>
namespace fuzzing {
// Public methods
DataProviderImpl::DataProviderImpl() : max_label_length_(0) {}
DataProviderImpl::~DataProviderImpl() {}
zx_status_t DataProviderImpl::Initialize(zx::vmo *out) {
std::lock_guard<std::mutex> lock(lock_);
if (inputs_.find("") != inputs_.end()) {
FX_LOGS(ERROR) << "Initialize() called more than once";
return ZX_ERR_BAD_STATE;
}
TestInput *input = &inputs_[""];
zx_status_t status;
if ((status = input->Create()) != ZX_OK || (status = input->Share(out)) != ZX_OK ||
(status = input->vmo().signal(kInIteration, kBetweenIterations)) != ZX_OK) {
FX_LOGS(ERROR) << "failed to create the shared test input memory: "
<< zx_status_get_string(status);
return status;
}
return ZX_OK;
}
void DataProviderImpl::AddConsumerLabel(std::string label) {
std::lock_guard<std::mutex> lock(lock_);
max_label_length_ = std::max(max_label_length_, label.size());
// Default construct a TestInput for the given label.
inputs_[label];
}
void DataProviderImpl::AddConsumer(std::string label, zx::vmo vmo, AddConsumerCallback callback) {
{
std::lock_guard<std::mutex> lock(lock_);
auto input = inputs_.find(label);
if (input == inputs_.end()) {
callback(ZX_ERR_INVALID_ARGS);
return;
}
input->second.Link(vmo);
input->second.vmo().signal(kInIteration, kBetweenIterations);
}
callback(ZX_OK);
}
zx_status_t DataProviderImpl::PartitionTestInput(const void *data, size_t size) {
std::lock_guard<std::mutex> lock(lock_);
if (inputs_.size() == 0) {
FX_LOGS(ERROR) << "not initialized";
return ZX_ERR_BAD_STATE;
}
for (auto &i : inputs_) {
i.second.Clear();
}
if (!data || size == 0) {
return ZX_OK;
}
const uint8_t *u8 = static_cast<const uint8_t *>(data);
TestInput *input = &inputs_[""];
size_t start = 0;
for (size_t i = 0; i + 3 < size; ++i) {
if (u8[i] != '#') {
continue;
}
size_t len = i - start;
++i;
if (u8[i] == '#') {
input->Write(&u8[start], i - start);
start = i + 1;
continue;
}
if (u8[i] != '[') {
continue;
}
++i;
size_t max = std::min(size, i + max_label_length_ + 1);
for (size_t j = i; j < max; ++j) {
if (u8[j] != ']') {
continue;
}
std::string_view label(reinterpret_cast<const char *>(&u8[i]), j - i);
i = j;
auto iter = inputs_.find(label);
if (iter != inputs_.end()) {
input->Write(&u8[start], len);
input = &iter->second;
start = i + 1;
}
break;
}
}
if (start < size) {
input->Write(&u8[start], size - start);
}
for (auto &[label, input] : inputs_) {
if (!input.is_mapped()) {
continue;
}
zx_status_t status = input.vmo().signal(kBetweenIterations, kInIteration);
if (status != ZX_OK) {
return status;
}
}
return ZX_OK;
}
zx_status_t DataProviderImpl::CompleteIteration() {
std::lock_guard<std::mutex> lock(lock_);
for (auto &[label, input] : inputs_) {
if (!input.is_mapped()) {
continue;
}
zx_status_t status = input.vmo().signal(kInIteration, kBetweenIterations);
if (status != ZX_OK) {
return status;
}
}
return ZX_OK;
}
void DataProviderImpl::Reset() {
std::lock_guard<std::mutex> lock(lock_);
inputs_.clear();
}
// Protected metohds
bool DataProviderImpl::HasLabel(const std::string &label) {
std::lock_guard<std::mutex> lock(lock_);
return inputs_.find(label) != inputs_.end();
}
bool DataProviderImpl::IsMapped(const std::string &label) {
std::lock_guard<std::mutex> lock(lock_);
auto input = inputs_.find(label);
return input != inputs_.end() && input->second.data() != nullptr;
}
} // namespace fuzzing