fuzzer.h 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  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_recommender.h"
  24. #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
  25. #include "source/fuzz/random_generator.h"
  26. #include "source/opt/ir_context.h"
  27. #include "spirv-tools/libspirv.hpp"
  28. namespace spvtools {
  29. namespace fuzz {
  30. // Transforms a SPIR-V module into a semantically equivalent SPIR-V module by
  31. // running a number of randomized fuzzer passes.
  32. class Fuzzer {
  33. public:
  34. // Possible statuses that can result from running the fuzzer.
  35. enum class FuzzerResultStatus {
  36. kComplete,
  37. kFailedToCreateSpirvToolsInterface,
  38. kFuzzerPassLedToInvalidModule,
  39. kInitialBinaryInvalid,
  40. };
  41. struct FuzzerResult {
  42. FuzzerResultStatus status;
  43. std::vector<uint32_t> transformed_binary;
  44. protobufs::TransformationSequence applied_transformations;
  45. };
  46. // Each field of this enum corresponds to an available repeated pass
  47. // strategy, and is used to decide which kind of RepeatedPassManager object
  48. // to create.
  49. enum class RepeatedPassStrategy {
  50. kSimple,
  51. kRandomWithRecommendations,
  52. kLoopedWithRecommendations
  53. };
  54. Fuzzer(spv_target_env target_env, MessageConsumer consumer,
  55. const std::vector<uint32_t>& binary_in,
  56. const protobufs::FactSequence& initial_facts,
  57. const std::vector<fuzzerutil::ModuleSupplier>& donor_suppliers,
  58. std::unique_ptr<RandomGenerator> random_generator,
  59. bool enable_all_passes, RepeatedPassStrategy repeated_pass_strategy,
  60. bool validate_after_each_fuzzer_pass,
  61. spv_validator_options validator_options);
  62. // Disables copy/move constructor/assignment operations.
  63. Fuzzer(const Fuzzer&) = delete;
  64. Fuzzer(Fuzzer&&) = delete;
  65. Fuzzer& operator=(const Fuzzer&) = delete;
  66. Fuzzer& operator=(Fuzzer&&) = delete;
  67. ~Fuzzer();
  68. // Transforms |binary_in_| by running a number of randomized fuzzer passes.
  69. // Initial facts about the input binary and the context in which it will
  70. // execute are provided via |initial_facts_|. A source of donor modules to be
  71. // used by transformations is provided via |donor_suppliers_|. On success,
  72. // returns a successful result status together with the transformed binary and
  73. // the sequence of transformations that were applied. Otherwise, returns an
  74. // appropriate result status together with an empty binary and empty
  75. // transformation sequence.
  76. FuzzerResult Run();
  77. private:
  78. // A convenience method to add a repeated fuzzer pass to |pass_instances| with
  79. // probability |percentage_chance_of_adding_pass|%, or with probability 100%
  80. // if |enable_all_passes_| is true.
  81. //
  82. // All fuzzer passes take members |ir_context_|, |transformation_context_|,
  83. // |fuzzer_context_| and |transformation_sequence_out_| as parameters. Extra
  84. // arguments can be provided via |extra_args|.
  85. template <typename FuzzerPassT, typename... Args>
  86. void MaybeAddRepeatedPass(uint32_t percentage_chance_of_adding_pass,
  87. RepeatedPassInstances* pass_instances,
  88. Args&&... extra_args);
  89. // The same as the above, with |percentage_chance_of_adding_pass| == 50%.
  90. template <typename FuzzerPassT, typename... Args>
  91. void MaybeAddRepeatedPass(RepeatedPassInstances* pass_instances,
  92. Args&&... extra_args) {
  93. MaybeAddRepeatedPass<FuzzerPassT>(50, pass_instances,
  94. std::forward<Args>(extra_args)...);
  95. }
  96. // A convenience method to add a final fuzzer pass to |passes| with
  97. // probability 50%, or with probability 100% if |enable_all_passes_| is true.
  98. //
  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 MaybeAddFinalPass(std::vector<std::unique_ptr<FuzzerPass>>* passes,
  104. Args&&... extra_args);
  105. // Decides whether to apply more repeated passes. The probability decreases as
  106. // the number of transformations that have been applied increases.
  107. bool ShouldContinueFuzzing();
  108. // Applies |pass|, which must be a pass constructed with |ir_context|.
  109. // If |validate_after_each_fuzzer_pass_| is not set, true is always returned.
  110. // Otherwise, true is returned if and only if |ir_context| passes validation,
  111. // every block has its enclosing function as its parent, and every
  112. // instruction has a distinct unique id.
  113. bool ApplyPassAndCheckValidity(FuzzerPass* pass) const;
  114. // Target environment.
  115. const spv_target_env target_env_;
  116. // Message consumer that will be invoked once for each message communicated
  117. // from the library.
  118. MessageConsumer consumer_;
  119. // The initial binary to which fuzzing should be applied.
  120. const std::vector<uint32_t>& binary_in_;
  121. // Initial facts known to hold in advance of applying any transformations.
  122. const protobufs::FactSequence& initial_facts_;
  123. // A source of modules whose contents can be donated into the module being
  124. // fuzzed.
  125. const std::vector<fuzzerutil::ModuleSupplier>& donor_suppliers_;
  126. // Random number generator to control decision making during fuzzing.
  127. std::unique_ptr<RandomGenerator> random_generator_;
  128. // Determines whether all passes should be enabled, vs. having passes be
  129. // probabilistically enabled.
  130. bool enable_all_passes_;
  131. // Controls which type of RepeatedPassManager object to create.
  132. RepeatedPassStrategy repeated_pass_strategy_;
  133. // Determines whether the validator should be invoked after every fuzzer pass.
  134. bool validate_after_each_fuzzer_pass_;
  135. // Options to control validation.
  136. spv_validator_options validator_options_;
  137. // The number of repeated fuzzer passes that have been applied is kept track
  138. // of, in order to enforce a hard limit on the number of times such passes
  139. // can be applied.
  140. uint32_t num_repeated_passes_applied_;
  141. // Intermediate representation for the module being fuzzed, which gets
  142. // mutated as fuzzing proceeds.
  143. std::unique_ptr<opt::IRContext> ir_context_;
  144. // Provides probabilities that control the fuzzing process.
  145. std::unique_ptr<FuzzerContext> fuzzer_context_;
  146. // Contextual information that is required in order to apply transformations.
  147. std::unique_ptr<TransformationContext> transformation_context_;
  148. // The sequence of transformations that have been applied during fuzzing. It
  149. // is initially empty and grows as fuzzer passes are applied.
  150. protobufs::TransformationSequence transformation_sequence_out_;
  151. };
  152. } // namespace fuzz
  153. } // namespace spvtools
  154. #endif // SOURCE_FUZZ_FUZZER_H_