| // 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 |