SPIRV-Tools/source/fuzz/shrinker.h
Alastair Donaldson 125b642419
spirv-fuzz: Refactor fuzzer, replayer and shrinker (#3818)
In preparation for some upcoming work on the shrinker, this PR changes
the interfaces of Fuzzer, Replayer and Shrinker so that all data
relevant to each class is provided on construction, meaning that the
"Run" method can become a zero-argument method that returns a status,
transformed binary and sequence of applied transformations via a
struct.

This makes greater use of fields, so that -- especially in Fuzzer --
there is a lot less parameter passing.
2020-09-22 10:07:58 +01:00

128 lines
4.6 KiB
C++

// Copyright (c) 2019 Google LLC
//
// 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 SOURCE_FUZZ_SHRINKER_H_
#define SOURCE_FUZZ_SHRINKER_H_
#include <memory>
#include <vector>
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
#include "spirv-tools/libspirv.hpp"
namespace spvtools {
namespace fuzz {
// Shrinks a sequence of transformations that lead to an interesting SPIR-V
// binary to yield a smaller sequence of transformations that still produce an
// interesting binary.
class Shrinker {
public:
// Possible statuses that can result from running the shrinker.
enum class ShrinkerResultStatus {
kComplete,
kFailedToCreateSpirvToolsInterface,
kInitialBinaryInvalid,
kInitialBinaryNotInteresting,
kReplayFailed,
kStepLimitReached,
};
struct ShrinkerResult {
ShrinkerResultStatus status;
std::vector<uint32_t> transformed_binary;
protobufs::TransformationSequence applied_transformations;
};
// The type for a function that will take a binary, |binary|, and return true
// if and only if the binary is deemed interesting. (The function also takes
// an integer argument, |counter|, that will be incremented each time the
// function is called; this is for debugging purposes).
//
// The notion of "interesting" depends on what properties of the binary or
// tools that process the binary we are trying to maintain during shrinking.
using InterestingnessFunction = std::function<bool(
const std::vector<uint32_t>& binary, uint32_t counter)>;
Shrinker(spv_target_env target_env, MessageConsumer consumer,
const std::vector<uint32_t>& binary_in,
const protobufs::FactSequence& initial_facts,
const protobufs::TransformationSequence& transformation_sequence_in,
const InterestingnessFunction& interestingness_function,
uint32_t step_limit, bool validate_during_replay,
spv_validator_options validator_options);
// Disables copy/move constructor/assignment operations.
Shrinker(const Shrinker&) = delete;
Shrinker(Shrinker&&) = delete;
Shrinker& operator=(const Shrinker&) = delete;
Shrinker& operator=(Shrinker&&) = delete;
~Shrinker();
// Requires that when |transformation_sequence_in_| is applied to |binary_in_|
// with initial facts |initial_facts_|, the resulting binary is interesting
// according to |interestingness_function_|.
//
// If shrinking succeeded -- possibly terminating early due to reaching the
// shrinker's step limit -- an associated result status is returned together
// with a subsequence of |transformation_sequence_in_| that, when applied
// to |binary_in_| with initial facts |initial_facts_|, produces a binary
// that is also interesting according to |interestingness_function_|; this
// binary is also returned.
//
// If shrinking failed for some reason, an appropriate result status is
// returned together with an empty binary and empty transformation sequence.
ShrinkerResult Run();
private:
// Returns the id bound for the given SPIR-V binary, which is assumed to be
// valid.
uint32_t GetIdBound(const std::vector<uint32_t>& binary) const;
// Target environment.
const spv_target_env target_env_;
// Message consumer that will be invoked once for each message communicated
// from the library.
MessageConsumer consumer_;
// The binary to which transformations are to be applied.
const std::vector<uint32_t>& binary_in_;
// Initial facts known to hold in advance of applying any transformations.
const protobufs::FactSequence& initial_facts_;
// The series of transformations to be shrunk.
const protobufs::TransformationSequence& transformation_sequence_in_;
// Function that decides whether a given binary is interesting.
const InterestingnessFunction& interestingness_function_;
// Step limit to decide when to terminate shrinking early.
const uint32_t step_limit_;
// Determines whether to check for validity during the replaying of
// transformations.
const bool validate_during_replay_;
// Options to control validation.
spv_validator_options validator_options_;
};
} // namespace fuzz
} // namespace spvtools
#endif // SOURCE_FUZZ_SHRINKER_H_