• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2020 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef SOURCE_FUZZ_ADDED_FUNCTION_REDUCER_H_
16 #define SOURCE_FUZZ_ADDED_FUNCTION_REDUCER_H_
17 
18 #include <unordered_set>
19 #include <vector>
20 
21 #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
22 #include "source/fuzz/shrinker.h"
23 #include "spirv-tools/libspirv.hpp"
24 
25 namespace spvtools {
26 namespace fuzz {
27 
28 // An auxiliary class used by Shrinker, this class takes care of using
29 // spirv-reduce to reduce the body of a function encoded in an AddFunction
30 // transformation, in case a smaller, simpler function can be added instead.
31 class AddedFunctionReducer {
32  public:
33   // Possible statuses that can result from running the shrinker.
34   enum class AddedFunctionReducerResultStatus {
35     kComplete,
36     kReductionFailed,
37   };
38 
39   struct AddedFunctionReducerResult {
40     AddedFunctionReducerResultStatus status;
41     std::vector<uint32_t> transformed_binary;
42     protobufs::TransformationSequence applied_transformations;
43     uint32_t num_reduction_attempts;
44   };
45 
46   AddedFunctionReducer(
47       spv_target_env target_env, MessageConsumer consumer,
48       const std::vector<uint32_t>& binary_in,
49       const protobufs::FactSequence& initial_facts,
50       const protobufs::TransformationSequence& transformation_sequence_in,
51       uint32_t index_of_add_function_transformation,
52       const Shrinker::InterestingnessFunction&
53           shrinker_interestingness_function,
54       bool validate_during_replay, spv_validator_options validator_options,
55       uint32_t shrinker_step_limit, uint32_t num_existing_shrink_attempts);
56 
57   // Disables copy/move constructor/assignment operations.
58   AddedFunctionReducer(const AddedFunctionReducer&) = delete;
59   AddedFunctionReducer(AddedFunctionReducer&&) = delete;
60   AddedFunctionReducer& operator=(const AddedFunctionReducer&) = delete;
61   AddedFunctionReducer& operator=(AddedFunctionReducer&&) = delete;
62 
63   ~AddedFunctionReducer();
64 
65   // Invokes spirv-reduce on the function in the AddFunction transformation
66   // identified by |index_of_add_function_transformation|.  Returns a sequence
67   // of transformations identical to |transformation_sequence_in|, except that
68   // the AddFunction transformation at |index_of_add_function_transformation|
69   // might have been simplified.  The binary associated with applying the
70   // resulting sequence of transformations to |binary_in| is also returned, as
71   // well as the number of reduction steps that spirv-reduce made.
72   //
73   // On failure, an empty transformation sequence and binary are returned,
74   // with a placeholder value of 0 for the number of reduction attempts.
75   AddedFunctionReducerResult Run();
76 
77  private:
78   // Yields, via |binary_out|, the binary obtained by applying transformations
79   // [0, |index_of_added_function_| - 1] from |transformations_in_| to
80   // |binary_in_|, and then adding the raw function encoded in
81   // |transformations_in_[index_of_added_function_]| (without adapting that
82   // function to make it livesafe).  This function has |added_function_id_| as
83   // its result id.
84   //
85   // The ids associated with all global variables in |binary_out| that had the
86   // "irrelevant pointee value" fact are also returned via
87   // |irrelevant_pointee_global_variables|.
88   //
89   // The point of this function is that spirv-reduce can subsequently be applied
90   // to function |added_function_id_| in |binary_out|.  By construction,
91   // |added_function_id_| should originally manipulate globals for which
92   // "irrelevant pointee value" facts hold.  The set
93   // |irrelevant_pointee_global_variables| can be used to force spirv-reduce
94   // to preserve this, to avoid the reduced function ending up manipulating
95   // other global variables of the SPIR-V module, potentially changing their
96   // value and thus changing the semantics of the module.
97   void ReplayPrefixAndAddFunction(
98       std::vector<uint32_t>* binary_out,
99       std::unordered_set<uint32_t>* irrelevant_pointee_global_variables) const;
100 
101   // This is the interestingness function that will be used by spirv-reduce
102   // when shrinking the added function.
103   //
104   // For |binary_under_reduction| to be deemed interesting, the following
105   // conditions must hold:
106   // - The function with id |added_function_id_| in |binary_under_reduction|
107   //   must only reference global variables in
108   //   |irrelevant_pointee_global_variables|.  This avoids the reduced function
109   //   changing the semantics of the original SPIR-V module.
110   // - It must be possible to successfully replay the transformations in
111   //   |transformation_sequence_in_|, adapted so that the function added by the
112   //   transformation at |index_of_add_function_transformation_| is replaced by
113   //   the function with id |added_function_id_| in |binary_under_reduction|,
114   //   to |binary_in| (starting with initial facts |initial_facts_|).
115   // - All the transformations in this sequence must be successfully applied
116   //   during replay.
117   // - The resulting binary must be interesting according to
118   //   |shrinker_interestingness_function_|.
119   bool InterestingnessFunctionForReducingAddedFunction(
120       const std::vector<uint32_t>& binary_under_reduction,
121       const std::unordered_set<uint32_t>& irrelevant_pointee_global_variables);
122 
123   // Starting with |binary_in_| and |initial_facts_|, the transformations in
124   // |transformation_sequence_in_| are replayed.  However, the transformation
125   // at index |index_of_add_function_transformation_| of
126   // |transformation_sequence_in_| -- which is guaranteed to be an AddFunction
127   // transformation -- is adapted so that the function to be added is replaced
128   // with the function in |binary_under_reduction| with id |added_function_id_|.
129   //
130   // The binary resulting from this replay is returned via |binary_out|, and the
131   // adapted transformation sequence via |transformation_sequence_out|.
132   void ReplayAdaptedTransformations(
133       const std::vector<uint32_t>& binary_under_reduction,
134       std::vector<uint32_t>* binary_out,
135       protobufs::TransformationSequence* transformation_sequence_out) const;
136 
137   // Returns the id of the function to be added by the AddFunction
138   // transformation at
139   // |transformation_sequence_in_[index_of_add_function_transformation_]|.
140   uint32_t GetAddedFunctionId() const;
141 
142   // Target environment.
143   const spv_target_env target_env_;
144 
145   // Message consumer.
146   MessageConsumer consumer_;
147 
148   // The initial binary to which transformations are applied -- i.e., the
149   // binary to which spirv-fuzz originally applied transformations.
150   const std::vector<uint32_t>& binary_in_;
151 
152   // Initial facts about |binary_in_|.
153   const protobufs::FactSequence& initial_facts_;
154 
155   // A set of transformations that can be successfully applied to |binary_in_|.
156   const protobufs::TransformationSequence& transformation_sequence_in_;
157 
158   // An index into |transformation_sequence_in_| referring to an AddFunction
159   // transformation.  This is the transformation to be simplified using
160   // spirv-reduce.
161   const uint32_t index_of_add_function_transformation_;
162 
163   // The interestingness function that has been provided to guide the
164   // overall shrinking process.  The AddFunction transformation being simplified
165   // by this class should still -- when applied in conjunction with the other
166   // transformations in |transformation_sequence_in_| -- lead to a binary that
167   // is deemed interesting by this function.
168   const Shrinker::InterestingnessFunction& shrinker_interestingness_function_;
169 
170   // Determines whether to check for validity during the replaying of
171   // transformations.
172   const bool validate_during_replay_;
173 
174   // Options to control validation.
175   spv_validator_options validator_options_;
176 
177   // The step limit associated with the overall shrinking process.
178   const uint32_t shrinker_step_limit_;
179 
180   // The number of shrink attempts that had been applied prior to invoking this
181   // AddedFunctionReducer instance.
182   const uint32_t num_existing_shrink_attempts_;
183 
184   // Tracks the number of attempts that spirv-reduce has invoked its
185   // interestingness function, which it does once at the start of reduction,
186   // and then once more each time it makes a reduction step.
187   uint32_t num_reducer_interestingness_function_invocations_;
188 };
189 
190 }  // namespace fuzz
191 }  // namespace spvtools
192 
193 #endif  // SOURCE_FUZZ_ADDED_FUNCTION_REDUCER_H_
194