mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-12-27 10:20:14 +00:00
69f07da41b
Fixes #3984.
194 lines
8.6 KiB
C++
194 lines
8.6 KiB
C++
// Copyright (c) 2020 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_ADDED_FUNCTION_REDUCER_H_
|
|
#define SOURCE_FUZZ_ADDED_FUNCTION_REDUCER_H_
|
|
|
|
#include <unordered_set>
|
|
#include <vector>
|
|
|
|
#include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
|
|
#include "source/fuzz/shrinker.h"
|
|
#include "spirv-tools/libspirv.hpp"
|
|
|
|
namespace spvtools {
|
|
namespace fuzz {
|
|
|
|
// An auxiliary class used by Shrinker, this class takes care of using
|
|
// spirv-reduce to reduce the body of a function encoded in an AddFunction
|
|
// transformation, in case a smaller, simpler function can be added instead.
|
|
class AddedFunctionReducer {
|
|
public:
|
|
// Possible statuses that can result from running the shrinker.
|
|
enum class AddedFunctionReducerResultStatus {
|
|
kComplete,
|
|
kReductionFailed,
|
|
};
|
|
|
|
struct AddedFunctionReducerResult {
|
|
AddedFunctionReducerResultStatus status;
|
|
std::vector<uint32_t> transformed_binary;
|
|
protobufs::TransformationSequence applied_transformations;
|
|
uint32_t num_reduction_attempts;
|
|
};
|
|
|
|
AddedFunctionReducer(
|
|
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,
|
|
uint32_t index_of_add_function_transformation,
|
|
const Shrinker::InterestingnessFunction&
|
|
shrinker_interestingness_function,
|
|
bool validate_during_replay, spv_validator_options validator_options,
|
|
uint32_t shrinker_step_limit, uint32_t num_existing_shrink_attempts);
|
|
|
|
// Disables copy/move constructor/assignment operations.
|
|
AddedFunctionReducer(const AddedFunctionReducer&) = delete;
|
|
AddedFunctionReducer(AddedFunctionReducer&&) = delete;
|
|
AddedFunctionReducer& operator=(const AddedFunctionReducer&) = delete;
|
|
AddedFunctionReducer& operator=(AddedFunctionReducer&&) = delete;
|
|
|
|
~AddedFunctionReducer();
|
|
|
|
// Invokes spirv-reduce on the function in the AddFunction transformation
|
|
// identified by |index_of_add_function_transformation|. Returns a sequence
|
|
// of transformations identical to |transformation_sequence_in|, except that
|
|
// the AddFunction transformation at |index_of_add_function_transformation|
|
|
// might have been simplified. The binary associated with applying the
|
|
// resulting sequence of transformations to |binary_in| is also returned, as
|
|
// well as the number of reduction steps that spirv-reduce made.
|
|
//
|
|
// On failure, an empty transformation sequence and binary are returned,
|
|
// with a placeholder value of 0 for the number of reduction attempts.
|
|
AddedFunctionReducerResult Run();
|
|
|
|
private:
|
|
// Yields, via |binary_out|, the binary obtained by applying transformations
|
|
// [0, |index_of_added_function_| - 1] from |transformations_in_| to
|
|
// |binary_in_|, and then adding the raw function encoded in
|
|
// |transformations_in_[index_of_added_function_]| (without adapting that
|
|
// function to make it livesafe). This function has |added_function_id_| as
|
|
// its result id.
|
|
//
|
|
// The ids associated with all global variables in |binary_out| that had the
|
|
// "irrelevant pointee value" fact are also returned via
|
|
// |irrelevant_pointee_global_variables|.
|
|
//
|
|
// The point of this function is that spirv-reduce can subsequently be applied
|
|
// to function |added_function_id_| in |binary_out|. By construction,
|
|
// |added_function_id_| should originally manipulate globals for which
|
|
// "irrelevant pointee value" facts hold. The set
|
|
// |irrelevant_pointee_global_variables| can be used to force spirv-reduce
|
|
// to preserve this, to avoid the reduced function ending up manipulating
|
|
// other global variables of the SPIR-V module, potentially changing their
|
|
// value and thus changing the semantics of the module.
|
|
void ReplayPrefixAndAddFunction(
|
|
std::vector<uint32_t>* binary_out,
|
|
std::unordered_set<uint32_t>* irrelevant_pointee_global_variables) const;
|
|
|
|
// This is the interestingness function that will be used by spirv-reduce
|
|
// when shrinking the added function.
|
|
//
|
|
// For |binary_under_reduction| to be deemed interesting, the following
|
|
// conditions must hold:
|
|
// - The function with id |added_function_id_| in |binary_under_reduction|
|
|
// must only reference global variables in
|
|
// |irrelevant_pointee_global_variables|. This avoids the reduced function
|
|
// changing the semantics of the original SPIR-V module.
|
|
// - It must be possible to successfully replay the transformations in
|
|
// |transformation_sequence_in_|, adapted so that the function added by the
|
|
// transformation at |index_of_add_function_transformation_| is replaced by
|
|
// the function with id |added_function_id_| in |binary_under_reduction|,
|
|
// to |binary_in| (starting with initial facts |initial_facts_|).
|
|
// - All the transformations in this sequence must be successfully applied
|
|
// during replay.
|
|
// - The resulting binary must be interesting according to
|
|
// |shrinker_interestingness_function_|.
|
|
bool InterestingnessFunctionForReducingAddedFunction(
|
|
const std::vector<uint32_t>& binary_under_reduction,
|
|
const std::unordered_set<uint32_t>& irrelevant_pointee_global_variables);
|
|
|
|
// Starting with |binary_in_| and |initial_facts_|, the transformations in
|
|
// |transformation_sequence_in_| are replayed. However, the transformation
|
|
// at index |index_of_add_function_transformation_| of
|
|
// |transformation_sequence_in_| -- which is guaranteed to be an AddFunction
|
|
// transformation -- is adapted so that the function to be added is replaced
|
|
// with the function in |binary_under_reduction| with id |added_function_id_|.
|
|
//
|
|
// The binary resulting from this replay is returned via |binary_out|, and the
|
|
// adapted transformation sequence via |transformation_sequence_out|.
|
|
void ReplayAdaptedTransformations(
|
|
const std::vector<uint32_t>& binary_under_reduction,
|
|
std::vector<uint32_t>* binary_out,
|
|
protobufs::TransformationSequence* transformation_sequence_out) const;
|
|
|
|
// Returns the id of the function to be added by the AddFunction
|
|
// transformation at
|
|
// |transformation_sequence_in_[index_of_add_function_transformation_]|.
|
|
uint32_t GetAddedFunctionId() const;
|
|
|
|
// Target environment.
|
|
const spv_target_env target_env_;
|
|
|
|
// Message consumer.
|
|
MessageConsumer consumer_;
|
|
|
|
// The initial binary to which transformations are applied -- i.e., the
|
|
// binary to which spirv-fuzz originally applied transformations.
|
|
const std::vector<uint32_t>& binary_in_;
|
|
|
|
// Initial facts about |binary_in_|.
|
|
const protobufs::FactSequence& initial_facts_;
|
|
|
|
// A set of transformations that can be successfully applied to |binary_in_|.
|
|
const protobufs::TransformationSequence& transformation_sequence_in_;
|
|
|
|
// An index into |transformation_sequence_in_| referring to an AddFunction
|
|
// transformation. This is the transformation to be simplified using
|
|
// spirv-reduce.
|
|
const uint32_t index_of_add_function_transformation_;
|
|
|
|
// The interestingness function that has been provided to guide the
|
|
// overall shrinking process. The AddFunction transformation being simplified
|
|
// by this class should still -- when applied in conjunction with the other
|
|
// transformations in |transformation_sequence_in_| -- lead to a binary that
|
|
// is deemed interesting by this function.
|
|
const Shrinker::InterestingnessFunction& shrinker_interestingness_function_;
|
|
|
|
// 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_;
|
|
|
|
// The step limit associated with the overall shrinking process.
|
|
const uint32_t shrinker_step_limit_;
|
|
|
|
// The number of shrink attempts that had been applied prior to invoking this
|
|
// AddedFunctionReducer instance.
|
|
const uint32_t num_existing_shrink_attempts_;
|
|
|
|
// Tracks the number of attempts that spirv-reduce has invoked its
|
|
// interestingness function, which it does once at the start of reduction,
|
|
// and then once more each time it makes a reduction step.
|
|
uint32_t num_reducer_interestingness_function_invocations_;
|
|
};
|
|
|
|
} // namespace fuzz
|
|
} // namespace spvtools
|
|
|
|
#endif // SOURCE_FUZZ_ADDED_FUNCTION_REDUCER_H_
|