1 // Copyright (c) 2019 Google LLC
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
15 #ifndef SOURCE_FUZZ_FUZZER_H_
16 #define SOURCE_FUZZ_FUZZER_H_
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"
36 // Transforms a SPIR-V module into a semantically equivalent SPIR-V module by
37 // running a number of randomized fuzzer passes.
40 // Possible statuses that can result from running the fuzzer.
44 kTransformationLimitReached
,
46 kFuzzerPassLedToInvalidModule
,
50 // Status of the fuzzing session.
53 // Equals to true if new transformations were applied during the previous
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 bool ignore_inapplicable_transformations
= true);
68 // Disables copy/move constructor/assignment operations.
69 Fuzzer(const Fuzzer
&) = delete;
70 Fuzzer(Fuzzer
&&) = delete;
71 Fuzzer
& operator=(const Fuzzer
&) = delete;
72 Fuzzer
& operator=(Fuzzer
&&) = delete;
76 // Transforms |ir_context_| by running a number of randomized fuzzer passes.
77 // Initial facts about the input binary and the context in which it will be
78 // executed are provided with |transformation_context_|.
79 // |num_of_transformations| is equal to the maximum number of transformations
80 // applied in a single call to this method. This parameter is ignored if its
81 // value is equal to 0. Because fuzzing cannot stop mid way through a fuzzer
82 // pass, fuzzing will stop after the fuzzer pass that exceeds
83 // |num_of_transformations| has completed, so that the total number of
84 // transformations may be somewhat larger than this number.
85 Result
Run(uint32_t num_of_transformations_to_apply
);
87 // Returns the current IR context. It may be invalid if the Run method
88 // returned Status::kFuzzerPassLedToInvalidModule previously.
89 opt::IRContext
* GetIRContext();
91 // Returns the sequence of applied transformations.
92 const protobufs::TransformationSequence
& GetTransformationSequence() const;
95 // A convenience method to add a repeated fuzzer pass to |pass_instances| with
96 // probability |percentage_chance_of_adding_pass|%, or with probability 100%
97 // if |enable_all_passes_| is true.
99 // All fuzzer passes take members |ir_context_|, |transformation_context_|,
100 // |fuzzer_context_| and |transformation_sequence_out_| as parameters. Extra
101 // arguments can be provided via |extra_args|.
102 template <typename FuzzerPassT
, typename
... Args
>
103 void MaybeAddRepeatedPass(uint32_t percentage_chance_of_adding_pass
,
104 RepeatedPassInstances
* pass_instances
,
105 Args
&&... extra_args
);
107 // The same as the above, with |percentage_chance_of_adding_pass| == 50%.
108 template <typename FuzzerPassT
, typename
... Args
>
109 void MaybeAddRepeatedPass(RepeatedPassInstances
* pass_instances
,
110 Args
&&... extra_args
) {
111 MaybeAddRepeatedPass
<FuzzerPassT
>(50, pass_instances
,
112 std::forward
<Args
>(extra_args
)...);
115 // A convenience method to add a final fuzzer pass to |passes| with
116 // probability 50%, or with probability 100% if |enable_all_passes_| is true.
118 // All fuzzer passes take members |ir_context_|, |transformation_context_|,
119 // |fuzzer_context_| and |transformation_sequence_out_| as parameters. Extra
120 // arguments can be provided via |extra_args|.
121 template <typename FuzzerPassT
, typename
... Args
>
122 void MaybeAddFinalPass(std::vector
<std::unique_ptr
<FuzzerPass
>>* passes
,
123 Args
&&... extra_args
);
125 // Decides whether to apply more repeated passes. The probability decreases as
126 // the number of transformations that have been applied increases.
127 // The described probability is only applied if
128 // |continue_fuzzing_probabilistically| is true.
129 bool ShouldContinueRepeatedPasses(bool continue_fuzzing_probabilistically
);
131 // Applies |pass|, which must be a pass constructed with |ir_context|.
132 // If |validate_after_each_fuzzer_pass_| is not set, true is always returned.
133 // Otherwise, true is returned if and only if |ir_context| passes validation,
134 // every block has its enclosing function as its parent, and every
135 // instruction has a distinct unique id.
136 bool ApplyPassAndCheckValidity(FuzzerPass
* pass
) const;
138 // Message consumer that will be invoked once for each message communicated
140 const MessageConsumer consumer_
;
142 // Determines whether all passes should be enabled, vs. having passes be
143 // probabilistically enabled.
144 const bool enable_all_passes_
;
146 // Determines whether the validator should be invoked after every fuzzer pass.
147 const bool validate_after_each_fuzzer_pass_
;
149 // Options to control validation.
150 const spv_validator_options validator_options_
;
152 // The number of repeated fuzzer passes that have been applied is kept track
153 // of, in order to enforce a hard limit on the number of times such passes
155 uint32_t num_repeated_passes_applied_
;
157 // We use this to determine whether we can continue fuzzing incrementally
158 // since the previous call to the Run method could've returned
159 // kFuzzerPassLedToInvalidModule.
162 // Intermediate representation for the module being fuzzed, which gets
163 // mutated as fuzzing proceeds.
164 std::unique_ptr
<opt::IRContext
> ir_context_
;
166 // Contextual information that is required in order to apply
168 std::unique_ptr
<TransformationContext
> transformation_context_
;
170 // Provides probabilities that control the fuzzing process.
171 std::unique_ptr
<FuzzerContext
> fuzzer_context_
;
173 // The sequence of transformations that have been applied during fuzzing. It
174 // is initially empty and grows as fuzzer passes are applied.
175 protobufs::TransformationSequence transformation_sequence_out_
;
177 // This object contains instances of all fuzzer passes that will participate
179 RepeatedPassInstances pass_instances_
;
181 // This object defines the recommendation logic for fuzzer passes.
182 std::unique_ptr
<RepeatedPassRecommender
> repeated_pass_recommender_
;
184 // This object manager a list of fuzzer pass and their available
186 std::unique_ptr
<RepeatedPassManager
> repeated_pass_manager_
;
188 // Some passes that it does not make sense to apply repeatedly, as they do not
189 // unlock other passes.
190 std::vector
<std::unique_ptr
<FuzzerPass
>> final_passes_
;
192 // When set, this flag causes inapplicable transformations that should be
193 // applicable by construction to be ignored. This is useful when the fuzzer
194 // is being deployed at scale to test a SPIR-V processing tool, and where it
195 // is desirable to ignore bugs in the fuzzer itself.
196 const bool ignore_inapplicable_transformations_
;
200 } // namespace spvtools
202 #endif // SOURCE_FUZZ_FUZZER_H_