blob: 0d78503da7308cb7a0bdeaad78ef200116b95d94 [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/corpus.h"
#include <lib/async/dispatcher.h>
#include <lib/syslog/cpp/macros.h>
#include <zircon/syscalls.h>
namespace fuzzing {
// Public methods
Corpus::Corpus() { inputs_.emplace_back(); }
Corpus& Corpus::operator=(Corpus&& other) noexcept {
options_ = other.options_;
other.options_ = nullptr;
prng_ = other.prng_;
{
std::lock_guard<std::mutex> lock(mutex_);
std::lock_guard<std::mutex> other_lock(other.mutex_);
inputs_ = std::move(other.inputs_);
other.inputs_.emplace_back();
total_size_ = other.total_size_;
other.total_size_ = 0;
}
return *this;
}
size_t Corpus::num_inputs() {
std::lock_guard<std::mutex> lock(mutex_);
return inputs_.size();
}
size_t Corpus::total_size() {
std::lock_guard<std::mutex> lock(mutex_);
return total_size_;
}
void Corpus::AddDefaults(Options* options) {
if (!options->has_seed()) {
options->set_seed(kDefaultSeed);
}
if (!options->has_max_input_size()) {
options->set_max_input_size(kDefaultMaxInputSize);
}
}
void Corpus::Configure(const std::shared_ptr<Options>& options) {
options_ = options;
prng_.seed(options_->seed());
}
zx_status_t Corpus::Add(Input input) {
std::lock_guard<std::mutex> lock(mutex_);
if (input.size() == 0) {
// Empty input is already implicitly included.
return ZX_OK;
}
FX_DCHECK(options_);
if (input.size() > options_->max_input_size()) {
return ZX_ERR_BUFFER_TOO_SMALL;
}
total_size_ += input.size();
inputs_.push_back(std::move(input));
return ZX_OK;
}
bool Corpus::At(size_t offset, Input* out) {
out->Clear();
std::lock_guard<std::mutex> lock(mutex_);
if (offset >= inputs_.size()) {
return false;
}
out->Duplicate(inputs_[offset]);
return true;
}
void Corpus::Pick(Input* out) {
std::lock_guard<std::mutex> lock(mutex_);
// Use rejection sampling to get uniform distribution.
// NOLINTNEXTLINE(google-runtime-int)
static_assert(sizeof(unsigned long long) * 8 == 64);
uint64_t size = inputs_.size();
FX_DCHECK(size > 0);
auto shift = 64 - __builtin_clzll(size);
FX_DCHECK(size < 64);
auto mod = 1ULL << shift;
size_t offset;
do {
offset = prng_() % mod;
} while (offset >= size);
out->Duplicate(inputs_[offset]);
}
} // namespace fuzzing