// Copyright 2021 The Tint Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef FUZZERS_TINT_SPIRV_TOOLS_FUZZER_MUTATOR_H_ #define FUZZERS_TINT_SPIRV_TOOLS_FUZZER_MUTATOR_H_ #include <cassert> #include <cstdint> #include <string> #include <vector> namespace tint { namespace fuzzers { namespace spvtools_fuzzer { /// This is an interface that is used to define custom mutators based on the /// SPIR-V tools. class Mutator { public: /// The status of the mutation. enum class Status { /// Binary is valid, the limit is not reached - can mutate further. kComplete, /// The binary is valid, the limit of mutations has been reached - /// can't mutate further. kLimitReached, /// The binary is valid, the limit is not reached but the mutator has spent /// too much time without mutating anything - better to restart to make sure /// we can make any progress. kStuck, /// The binary is invalid - this is likely a bug in the mutator - must /// abort. kInvalid }; /// Represents the result of the mutation. The following states are possible: /// - if `IsChanged() == false`, then `GetStatus()` can be either /// `kLimitReached` or `kStuck`. /// - otherwise, any value of `Status` is possible. class Result { public: /// Constructor. /// @param status - the status of the mutation. /// @param is_changed - whether the module was changed during mutation. Result(Status status, bool is_changed); /// @return the status of the mutation. Status GetStatus() const { return status_; } /// @return whether the module was changed during mutation. bool IsChanged() const { return is_changed_; } private: Status status_; bool is_changed_; }; /// Virtual destructor. virtual ~Mutator(); /// Causes the mutator to apply a mutation. This method can be called /// multiple times as long as the previous call didn't return /// `Status::kInvalid`. /// /// @return the status of the mutation (e.g. success, error etc) and whether /// the binary was changed during mutation. virtual Result Mutate() = 0; /// Returns the mutated binary. The returned binary is guaranteed to be valid /// iff the previous call to the `Mutate` method returned didn't return /// `Status::kInvalid`. /// /// @return the mutated SPIR-V binary. It might be identical to the original /// binary if `Result::IsChanged` returns `false`. virtual std::vector<uint32_t> GetBinary() const = 0; /// Returns errors, produced by the mutator. /// /// @param path - the directory to which the errors are printed to. No files /// are created if the `path` is nullptr. /// @param count - the number of the error. Files for this error will be /// prefixed with `count`. virtual void LogErrors(const std::string* path, uint32_t count) const = 0; /// @return errors encountered during the mutation. The returned string is /// if there were no errors during mutation. virtual std::string GetErrors() const = 0; }; } // namespace spvtools_fuzzer } // namespace fuzzers } // namespace tint #endif // FUZZERS_TINT_SPIRV_TOOLS_FUZZER_MUTATOR_H_