fuzzer.h 8.2 KB

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