| // 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. |
| |
| #ifndef SRC_SYS_FUZZING_COMMON_INPUT_H_ |
| #define SRC_SYS_FUZZING_COMMON_INPUT_H_ |
| |
| #include <fuchsia/fuzzer/cpp/fidl.h> |
| #include <limits.h> |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| #include <memory> |
| #include <string> |
| |
| #include "src/lib/fxl/macros.h" |
| #include "src/sys/fuzzing/common/shared-memory.h" |
| |
| namespace fuzzing { |
| |
| using FidlInput = ::fuchsia::fuzzer::Input; |
| |
| // Represents a single fuzzing input. A corpus is a collection of fuzzing inputs. Inputs are either |
| // provided as part of a seed corpus, or generated by mutating existing inputs. |
| class Input final { |
| public: |
| Input() = default; |
| Input(const std::initializer_list<uint8_t>& bytes) : Input(std::vector<uint8_t>(bytes)) {} |
| explicit Input(const std::vector<uint8_t>& bytes) : Input(bytes.data(), bytes.size()) {} |
| explicit Input(const std::string& bytes) : Input(bytes.c_str(), bytes.size()) {} |
| explicit Input(SharedMemory& shmem); |
| explicit Input(size_t size) : Input(std::vector<uint8_t>(size)) {} |
| Input(Input&& other) noexcept { *this = std::move(other); } |
| |
| ~Input() = default; |
| |
| Input& operator=(Input&& other) noexcept; |
| inline bool operator==(const Input& other) const { return Compare(other) == 0; } |
| inline bool operator!=(const Input& other) const { return Compare(other) != 0; } |
| inline bool operator<(const Input& other) const { return Compare(other) < 0; } |
| inline bool operator>(const Input& other) const { return Compare(other) > 0; } |
| inline bool operator<=(const Input& other) const { return Compare(other) <= 0; } |
| inline bool operator>=(const Input& other) const { return Compare(other) >= 0; } |
| |
| // This method allows easier printing by gTest. |
| friend std::ostream& operator<<(std::ostream& os, const Input& input) { |
| return os << input.ToHex(/* truncate */ false); |
| } |
| |
| const uint8_t* data() const { return data_.get(); } |
| uint8_t* data() { return data_.get(); } |
| size_t size() const { return size_; } |
| size_t capacity() const { return capacity_; } |
| size_t num_features() const { return num_features_; } |
| |
| void set_num_features(size_t num_features) { num_features_ = num_features; } |
| |
| // Returns a hex string representation. If the input is more than 6 bytes and |truncate|d, the |
| // returned string will be the first few bytes, followed by "...". |
| std::string ToHex(bool truncate = true) const; |
| |
| // Exchanges the internal state of this input with another. |
| void Swap(Input& other); |
| |
| // Creates a copy of this input. |
| Input Duplicate() const; |
| |
| // Makes this object a copy of the |other|. |
| void Duplicate(const Input& other); |
| |
| // Ensures the input has at least the given |capacity|. |
| void Reserve(size_t capacity); |
| |
| // Appends data to this input. The input must have sufficient remaining capacity for |size| bytes. |
| void Write(const void* data, size_t size); |
| void Write(uint8_t one_byte); |
| |
| // Reserves capacity and sets the size of this input to |size| bytes. This method does NOT |
| // initialize the data, but can be used in conjunction with the |data()| accessor to write into |
| // the input. Returns the new size. |
| size_t Resize(size_t size); |
| |
| // Truncates the input if larger than |max_size|. Returns the new size. |
| size_t Truncate(size_t max_size); |
| |
| // Reduces the capacity of this input to its size. Returns the new size. |
| size_t ShrinkToFit(); |
| |
| // Removes all data from this input. |
| void Clear(); |
| |
| private: |
| Input(const void* data, size_t size) { Allocate(size, data, size); } |
| |
| void Allocate(size_t capacity, const void* data = nullptr, size_t size = 0); |
| |
| void StartExport(zx::socket* sender, FidlInput* receiver) const; |
| void FinishExport(const zx::socket& sender) const; |
| |
| // Compares this input to some |other| input, and returns negative, zero, or positive depending on |
| // whether this input should be considered less than, equal to, or greater than the other input |
| // when sorting. The defined sort order is "smaller size, then more features, then byte-by-byte". |
| // |
| // Returns negative if this input is shorter than |other|, or the same length but with more |
| // features than |other|, or the same length with the same number of features but the first |
| // non-matching byte is less than the corresponding byte in |other|. |
| // |
| // Returns postive if this input is longer than |other|, or the same length but with fewer |
| // features than |other|, or the same length with the same number of features but the first |
| // non-matching byte is greater than the corresponding byte in |other|. |
| // |
| // Returns zero if this input has the same bytes as |other|. |
| int Compare(const Input& other) const; |
| |
| std::unique_ptr<uint8_t[]> data_; |
| size_t capacity_ = 0; |
| size_t size_ = 0; |
| size_t num_features_ = 0; |
| |
| FXL_DISALLOW_COPY_AND_ASSIGN(Input); |
| }; |
| |
| } // namespace fuzzing |
| |
| #endif // SRC_SYS_FUZZING_COMMON_INPUT_H_ |