Roll external/abseil_cpp/ 8f739d18b..917bfee46 (2 commits) (#5887)
[KhronosGroup/SPIRV-Tools.git] / source / fuzz / fuzzer.h
blob4c38977fb9b9c686284af9ea8a1f177b6b8be6dd
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.
15 #ifndef SOURCE_FUZZ_FUZZER_H_
16 #define SOURCE_FUZZ_FUZZER_H_
18 #include <memory>
19 #include <utility>
20 #include <vector>
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"
33 namespace spvtools {
34 namespace fuzz {
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,
49 struct Result {
50 // Status of the fuzzing session.
51 Status status;
53 // Equals to true if new transformations were applied during the previous
54 // fuzzing session.
55 bool is_changed;
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;
74 ~Fuzzer();
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;
94 private:
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
139 // from the library.
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
154 // can be applied.
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.
160 bool is_valid_;
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
167 // transformations.
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
178 // in the fuzzing.
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
185 // recommendations.
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_;
199 } // namespace fuzz
200 } // namespace spvtools
202 #endif // SOURCE_FUZZ_FUZZER_H_