| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- // 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_
|