• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2019 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_FUZZER_H_
16 #define SOURCE_FUZZ_FUZZER_H_
17 
18 #include <memory>
19 #include <utility>
20 #include <vector>
21 
22 #include "source/fuzz/fuzzer_context.h"
23 #include "source/fuzz/fuzzer_pass.h"
24 #include "source/fuzz/fuzzer_util.h"
25 #include "source/fuzz/pass_management/repeated_pass_instances.h"
26 #include "source/fuzz/pass_management/repeated_pass_manager.h"
27 #include "source/fuzz/pass_management/repeated_pass_recommender.h"
28 #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
29 #include "source/fuzz/random_generator.h"
30 #include "source/opt/ir_context.h"
31 #include "spirv-tools/libspirv.hpp"
32 
33 namespace spvtools {
34 namespace fuzz {
35 
36 // Transforms a SPIR-V module into a semantically equivalent SPIR-V module by
37 // running a number of randomized fuzzer passes.
38 class Fuzzer {
39  public:
40   // Possible statuses that can result from running the fuzzer.
41   enum class Status {
42     kComplete,
43     kModuleTooBig,
44     kTransformationLimitReached,
45     kFuzzerStuck,
46     kFuzzerPassLedToInvalidModule,
47   };
48 
49   struct Result {
50     // Status of the fuzzing session.
51     Status status;
52 
53     // Equals to true if new transformations were applied during the previous
54     // fuzzing session.
55     bool is_changed;
56   };
57 
58   Fuzzer(std::unique_ptr<opt::IRContext> ir_context,
59          std::unique_ptr<TransformationContext> transformation_context,
60          std::unique_ptr<FuzzerContext> fuzzer_context,
61          MessageConsumer consumer,
62          const std::vector<fuzzerutil::ModuleSupplier>& donor_suppliers,
63          bool enable_all_passes, RepeatedPassStrategy repeated_pass_strategy,
64          bool validate_after_each_fuzzer_pass,
65          spv_validator_options validator_options);
66 
67   // Disables copy/move constructor/assignment operations.
68   Fuzzer(const Fuzzer&) = delete;
69   Fuzzer(Fuzzer&&) = delete;
70   Fuzzer& operator=(const Fuzzer&) = delete;
71   Fuzzer& operator=(Fuzzer&&) = delete;
72 
73   ~Fuzzer();
74 
75   // Transforms |ir_context_| by running a number of randomized fuzzer passes.
76   // Initial facts about the input binary and the context in which it will be
77   // executed are provided with |transformation_context_|.
78   // |num_of_transformations| is equal to the maximum number of transformations
79   // applied in a single call to this method. This parameter is ignored if its
80   // value is equal to 0. Because fuzzing cannot stop mid way through a fuzzer
81   // pass, fuzzing will stop after the fuzzer pass that exceeds
82   // |num_of_transformations| has completed, so that the total number of
83   // transformations may be somewhat larger than this number.
84   Result Run(uint32_t num_of_transformations_to_apply);
85 
86   // Returns the current IR context. It may be invalid if the Run method
87   // returned Status::kFuzzerPassLedToInvalidModule previously.
88   opt::IRContext* GetIRContext();
89 
90   // Returns the sequence of applied transformations.
91   const protobufs::TransformationSequence& GetTransformationSequence() const;
92 
93  private:
94   // A convenience method to add a repeated fuzzer pass to |pass_instances| with
95   // probability |percentage_chance_of_adding_pass|%, or with probability 100%
96   // if |enable_all_passes_| is true.
97   //
98   // All fuzzer passes take members |ir_context_|, |transformation_context_|,
99   // |fuzzer_context_| and |transformation_sequence_out_| as parameters.  Extra
100   // arguments can be provided via |extra_args|.
101   template <typename FuzzerPassT, typename... Args>
102   void MaybeAddRepeatedPass(uint32_t percentage_chance_of_adding_pass,
103                             RepeatedPassInstances* pass_instances,
104                             Args&&... extra_args);
105 
106   // The same as the above, with |percentage_chance_of_adding_pass| == 50%.
107   template <typename FuzzerPassT, typename... Args>
MaybeAddRepeatedPass(RepeatedPassInstances * pass_instances,Args &&...extra_args)108   void MaybeAddRepeatedPass(RepeatedPassInstances* pass_instances,
109                             Args&&... extra_args) {
110     MaybeAddRepeatedPass<FuzzerPassT>(50, pass_instances,
111                                       std::forward<Args>(extra_args)...);
112   }
113 
114   // A convenience method to add a final fuzzer pass to |passes| with
115   // probability 50%, or with probability 100% if |enable_all_passes_| is true.
116   //
117   // All fuzzer passes take members |ir_context_|, |transformation_context_|,
118   // |fuzzer_context_| and |transformation_sequence_out_| as parameters.  Extra
119   // arguments can be provided via |extra_args|.
120   template <typename FuzzerPassT, typename... Args>
121   void MaybeAddFinalPass(std::vector<std::unique_ptr<FuzzerPass>>* passes,
122                          Args&&... extra_args);
123 
124   // Decides whether to apply more repeated passes. The probability decreases as
125   // the number of transformations that have been applied increases.
126   // The described probability is only applied if
127   // |continue_fuzzing_probabilistically| is true.
128   bool ShouldContinueRepeatedPasses(bool continue_fuzzing_probabilistically);
129 
130   // Applies |pass|, which must be a pass constructed with |ir_context|.
131   // If |validate_after_each_fuzzer_pass_| is not set, true is always returned.
132   // Otherwise, true is returned if and only if |ir_context| passes validation,
133   // every block has its enclosing function as its parent, and every
134   // instruction has a distinct unique id.
135   bool ApplyPassAndCheckValidity(FuzzerPass* pass) const;
136 
137   // Message consumer that will be invoked once for each message communicated
138   // from the library.
139   const MessageConsumer consumer_;
140 
141   // Determines whether all passes should be enabled, vs. having passes be
142   // probabilistically enabled.
143   const bool enable_all_passes_;
144 
145   // Determines whether the validator should be invoked after every fuzzer pass.
146   const bool validate_after_each_fuzzer_pass_;
147 
148   // Options to control validation.
149   const spv_validator_options validator_options_;
150 
151   // The number of repeated fuzzer passes that have been applied is kept track
152   // of, in order to enforce a hard limit on the number of times such passes
153   // can be applied.
154   uint32_t num_repeated_passes_applied_;
155 
156   // We use this to determine whether we can continue fuzzing incrementally
157   // since the previous call to the Run method could've returned
158   // kFuzzerPassLedToInvalidModule.
159   bool is_valid_;
160 
161   // Intermediate representation for the module being fuzzed, which gets
162   // mutated as fuzzing proceeds.
163   std::unique_ptr<opt::IRContext> ir_context_;
164 
165   // Contextual information that is required in order to apply
166   // transformations.
167   std::unique_ptr<TransformationContext> transformation_context_;
168 
169   // Provides probabilities that control the fuzzing process.
170   std::unique_ptr<FuzzerContext> fuzzer_context_;
171 
172   // The sequence of transformations that have been applied during fuzzing. It
173   // is initially empty and grows as fuzzer passes are applied.
174   protobufs::TransformationSequence transformation_sequence_out_;
175 
176   // This object contains instances of all fuzzer passes that will participate
177   // in the fuzzing.
178   RepeatedPassInstances pass_instances_;
179 
180   // This object defines the recommendation logic for fuzzer passes.
181   std::unique_ptr<RepeatedPassRecommender> repeated_pass_recommender_;
182 
183   // This object manager a list of fuzzer pass and their available
184   // recommendations.
185   std::unique_ptr<RepeatedPassManager> repeated_pass_manager_;
186 
187   // Some passes that it does not make sense to apply repeatedly, as they do not
188   // unlock other passes.
189   std::vector<std::unique_ptr<FuzzerPass>> final_passes_;
190 };
191 
192 }  // namespace fuzz
193 }  // namespace spvtools
194 
195 #endif  // SOURCE_FUZZ_FUZZER_H_
196