| // 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/common/input.h" | |
| #include <errno.h> | |
| #include <lib/syslog/cpp/macros.h> | |
| #include <stdlib.h> | |
| #include <sys/stat.h> | |
| #include <sys/types.h> | |
| #include <unistd.h> | |
| #include <zircon/status.h> | |
| #include <algorithm> | |
| #include <iomanip> | |
| #include <sstream> | |
| namespace fuzzing { | |
| Input::Input(SharedMemory& shmem) { | |
| if (auto status = shmem.Read(); status != ZX_OK) { | |
| FX_LOGS(FATAL) << "Failed to read shared memory: " << zx_status_get_string(status); | |
| } | |
| Allocate(shmem.size(), shmem.data(), shmem.size()); | |
| } | |
| void Input::Allocate(size_t capacity, const void* data, size_t size) { | |
| if (capacity_ != capacity) { | |
| capacity_ = capacity; | |
| if (capacity_) { | |
| data_ = std::make_unique<uint8_t[]>(capacity_); | |
| } else { | |
| data_.reset(); | |
| } | |
| } | |
| size_ = std::min(capacity, size); | |
| if (data && size_) { | |
| memcpy(data_.get(), data, size_); | |
| } | |
| } | |
| Input& Input::operator=(Input&& other) noexcept { | |
| data_ = std::move(other.data_); | |
| capacity_ = other.capacity_; | |
| size_ = other.size_; | |
| num_features_ = other.num_features_; | |
| other.data_.reset(); | |
| other.capacity_ = 0; | |
| other.size_ = 0; | |
| other.num_features_ = 0; | |
| return *this; | |
| } | |
| int Input::Compare(const Input& other) const { | |
| // Sort by size first: smaller before larger. | |
| if (size_ < other.size_) { | |
| return -1; | |
| } | |
| if (other.size_ < size_) { | |
| return 1; | |
| } | |
| // All empty inputs are the same. | |
| if (size_ == 0) { | |
| return 0; | |
| } | |
| // Sort by features next: more before fewer. | |
| if (other.num_features_ < num_features_) { | |
| return -1; | |
| } | |
| if (num_features_ < other.num_features_) { | |
| return 1; | |
| } | |
| // Sort by bytes last. | |
| return memcmp(data_.get(), other.data_.get(), size_); | |
| } | |
| std::string Input::ToHex(bool truncate) const { | |
| std::stringstream oss; | |
| oss << std::hex; | |
| auto* data = data_.get(); | |
| auto len = truncate ? std::min(size_, size_t(6)) : size_; | |
| for (size_t i = 0; i < len; ++i) { | |
| oss << std::setw(2) << std::setfill('0') << size_t(data[i]); | |
| } | |
| if (len != size_) { | |
| oss << "..."; | |
| } | |
| return oss.str(); | |
| } | |
| void Input::Swap(Input& other) { | |
| data_.swap(other.data_); | |
| std::swap(capacity_, other.capacity_); | |
| std::swap(size_, other.size_); | |
| std::swap(num_features_, other.num_features_); | |
| } | |
| Input Input::Duplicate() const { | |
| Input other; | |
| other.Allocate(size_, data_.get(), size_); | |
| other.num_features_ = num_features_; | |
| return other; | |
| } | |
| void Input::Duplicate(const Input& other) { | |
| Allocate(other.size_, other.data_.get(), other.size_); | |
| num_features_ = other.num_features_; | |
| } | |
| void Input::Reserve(size_t capacity) { | |
| if (capacity_ < capacity) { | |
| auto tmp = std::move(data_); | |
| Allocate(capacity, tmp.get(), size_); | |
| } | |
| } | |
| void Input::Write(const void* data, size_t size) { | |
| FX_DCHECK(size_ + size <= capacity_); | |
| memcpy(&data_[size_], data, size); | |
| size_ += size; | |
| } | |
| void Input::Write(uint8_t one_byte) { | |
| FX_DCHECK(size_ < capacity_); | |
| data_[size_++] = one_byte; | |
| } | |
| size_t Input::Resize(size_t size) { | |
| Reserve(size); | |
| size_ = size; | |
| return size_; | |
| } | |
| size_t Input::Truncate(size_t max_size) { | |
| size_ = std::min(size_, max_size); | |
| return size_; | |
| } | |
| size_t Input::ShrinkToFit() { | |
| if (size_ != capacity_) { | |
| auto tmp = std::move(data_); | |
| Allocate(size_, tmp.get(), size_); | |
| } | |
| return size_; | |
| } | |
| void Input::Clear() { size_ = 0; } | |
| } // namespace fuzzing |