fuzzer.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  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. #include "source/fuzz/fuzzer.h"
  15. #include <cassert>
  16. #include <memory>
  17. #include <numeric>
  18. #include <sstream>
  19. #include "source/fuzz/fact_manager/fact_manager.h"
  20. #include "source/fuzz/fuzzer_context.h"
  21. #include "source/fuzz/fuzzer_pass_add_access_chains.h"
  22. #include "source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.h"
  23. #include "source/fuzz/fuzzer_pass_add_composite_extract.h"
  24. #include "source/fuzz/fuzzer_pass_add_composite_inserts.h"
  25. #include "source/fuzz/fuzzer_pass_add_composite_types.h"
  26. #include "source/fuzz/fuzzer_pass_add_copy_memory.h"
  27. #include "source/fuzz/fuzzer_pass_add_dead_blocks.h"
  28. #include "source/fuzz/fuzzer_pass_add_dead_breaks.h"
  29. #include "source/fuzz/fuzzer_pass_add_dead_continues.h"
  30. #include "source/fuzz/fuzzer_pass_add_equation_instructions.h"
  31. #include "source/fuzz/fuzzer_pass_add_function_calls.h"
  32. #include "source/fuzz/fuzzer_pass_add_global_variables.h"
  33. #include "source/fuzz/fuzzer_pass_add_image_sample_unused_components.h"
  34. #include "source/fuzz/fuzzer_pass_add_loads.h"
  35. #include "source/fuzz/fuzzer_pass_add_local_variables.h"
  36. #include "source/fuzz/fuzzer_pass_add_loop_preheaders.h"
  37. #include "source/fuzz/fuzzer_pass_add_loops_to_create_int_constant_synonyms.h"
  38. #include "source/fuzz/fuzzer_pass_add_no_contraction_decorations.h"
  39. #include "source/fuzz/fuzzer_pass_add_opphi_synonyms.h"
  40. #include "source/fuzz/fuzzer_pass_add_parameters.h"
  41. #include "source/fuzz/fuzzer_pass_add_relaxed_decorations.h"
  42. #include "source/fuzz/fuzzer_pass_add_stores.h"
  43. #include "source/fuzz/fuzzer_pass_add_synonyms.h"
  44. #include "source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.h"
  45. #include "source/fuzz/fuzzer_pass_adjust_branch_weights.h"
  46. #include "source/fuzz/fuzzer_pass_adjust_function_controls.h"
  47. #include "source/fuzz/fuzzer_pass_adjust_loop_controls.h"
  48. #include "source/fuzz/fuzzer_pass_adjust_memory_operands_masks.h"
  49. #include "source/fuzz/fuzzer_pass_adjust_selection_controls.h"
  50. #include "source/fuzz/fuzzer_pass_apply_id_synonyms.h"
  51. #include "source/fuzz/fuzzer_pass_construct_composites.h"
  52. #include "source/fuzz/fuzzer_pass_copy_objects.h"
  53. #include "source/fuzz/fuzzer_pass_donate_modules.h"
  54. #include "source/fuzz/fuzzer_pass_duplicate_regions_with_selections.h"
  55. #include "source/fuzz/fuzzer_pass_expand_vector_reductions.h"
  56. #include "source/fuzz/fuzzer_pass_flatten_conditional_branches.h"
  57. #include "source/fuzz/fuzzer_pass_inline_functions.h"
  58. #include "source/fuzz/fuzzer_pass_interchange_signedness_of_integer_operands.h"
  59. #include "source/fuzz/fuzzer_pass_interchange_zero_like_constants.h"
  60. #include "source/fuzz/fuzzer_pass_invert_comparison_operators.h"
  61. #include "source/fuzz/fuzzer_pass_make_vector_operations_dynamic.h"
  62. #include "source/fuzz/fuzzer_pass_merge_blocks.h"
  63. #include "source/fuzz/fuzzer_pass_merge_function_returns.h"
  64. #include "source/fuzz/fuzzer_pass_mutate_pointers.h"
  65. #include "source/fuzz/fuzzer_pass_obfuscate_constants.h"
  66. #include "source/fuzz/fuzzer_pass_outline_functions.h"
  67. #include "source/fuzz/fuzzer_pass_permute_blocks.h"
  68. #include "source/fuzz/fuzzer_pass_permute_function_parameters.h"
  69. #include "source/fuzz/fuzzer_pass_permute_instructions.h"
  70. #include "source/fuzz/fuzzer_pass_permute_phi_operands.h"
  71. #include "source/fuzz/fuzzer_pass_propagate_instructions_down.h"
  72. #include "source/fuzz/fuzzer_pass_propagate_instructions_up.h"
  73. #include "source/fuzz/fuzzer_pass_push_ids_through_variables.h"
  74. #include "source/fuzz/fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.h"
  75. #include "source/fuzz/fuzzer_pass_replace_branches_from_dead_blocks_with_exits.h"
  76. #include "source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.h"
  77. #include "source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.h"
  78. #include "source/fuzz/fuzzer_pass_replace_irrelevant_ids.h"
  79. #include "source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.h"
  80. #include "source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.h"
  81. #include "source/fuzz/fuzzer_pass_replace_opphi_ids_from_dead_predecessors.h"
  82. #include "source/fuzz/fuzzer_pass_replace_opselects_with_conditional_branches.h"
  83. #include "source/fuzz/fuzzer_pass_replace_parameter_with_global.h"
  84. #include "source/fuzz/fuzzer_pass_replace_params_with_struct.h"
  85. #include "source/fuzz/fuzzer_pass_split_blocks.h"
  86. #include "source/fuzz/fuzzer_pass_swap_commutable_operands.h"
  87. #include "source/fuzz/fuzzer_pass_swap_conditional_branch_operands.h"
  88. #include "source/fuzz/fuzzer_pass_toggle_access_chain_instruction.h"
  89. #include "source/fuzz/fuzzer_pass_wrap_regions_in_selections.h"
  90. #include "source/fuzz/pass_management/repeated_pass_manager.h"
  91. #include "source/fuzz/pass_management/repeated_pass_manager_looped_with_recommendations.h"
  92. #include "source/fuzz/pass_management/repeated_pass_manager_random_with_recommendations.h"
  93. #include "source/fuzz/pass_management/repeated_pass_manager_simple.h"
  94. #include "source/fuzz/pass_management/repeated_pass_recommender_standard.h"
  95. #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
  96. #include "source/fuzz/transformation_context.h"
  97. #include "source/opt/build_module.h"
  98. #include "source/spirv_fuzzer_options.h"
  99. #include "source/util/make_unique.h"
  100. namespace spvtools {
  101. namespace fuzz {
  102. namespace {
  103. const uint32_t kIdBoundGap = 100;
  104. } // namespace
  105. Fuzzer::Fuzzer(spv_target_env target_env, MessageConsumer consumer,
  106. const std::vector<uint32_t>& binary_in,
  107. const protobufs::FactSequence& initial_facts,
  108. const std::vector<fuzzerutil::ModuleSupplier>& donor_suppliers,
  109. std::unique_ptr<RandomGenerator> random_generator,
  110. bool enable_all_passes,
  111. RepeatedPassStrategy repeated_pass_strategy,
  112. bool validate_after_each_fuzzer_pass,
  113. spv_validator_options validator_options)
  114. : target_env_(target_env),
  115. consumer_(std::move(consumer)),
  116. binary_in_(binary_in),
  117. initial_facts_(initial_facts),
  118. donor_suppliers_(donor_suppliers),
  119. random_generator_(std::move(random_generator)),
  120. enable_all_passes_(enable_all_passes),
  121. repeated_pass_strategy_(repeated_pass_strategy),
  122. validate_after_each_fuzzer_pass_(validate_after_each_fuzzer_pass),
  123. validator_options_(validator_options),
  124. num_repeated_passes_applied_(0),
  125. ir_context_(nullptr),
  126. fuzzer_context_(nullptr),
  127. transformation_context_(nullptr),
  128. transformation_sequence_out_() {}
  129. Fuzzer::~Fuzzer() = default;
  130. template <typename FuzzerPassT, typename... Args>
  131. void Fuzzer::MaybeAddRepeatedPass(uint32_t percentage_chance_of_adding_pass,
  132. RepeatedPassInstances* pass_instances,
  133. Args&&... extra_args) {
  134. if (enable_all_passes_ ||
  135. fuzzer_context_->ChoosePercentage(percentage_chance_of_adding_pass)) {
  136. pass_instances->SetPass(MakeUnique<FuzzerPassT>(
  137. ir_context_.get(), transformation_context_.get(), fuzzer_context_.get(),
  138. &transformation_sequence_out_, std::forward<Args>(extra_args)...));
  139. }
  140. }
  141. template <typename FuzzerPassT, typename... Args>
  142. void Fuzzer::MaybeAddFinalPass(std::vector<std::unique_ptr<FuzzerPass>>* passes,
  143. Args&&... extra_args) {
  144. if (enable_all_passes_ || fuzzer_context_->ChooseEven()) {
  145. passes->push_back(MakeUnique<FuzzerPassT>(
  146. ir_context_.get(), transformation_context_.get(), fuzzer_context_.get(),
  147. &transformation_sequence_out_, std::forward<Args>(extra_args)...));
  148. }
  149. }
  150. bool Fuzzer::ApplyPassAndCheckValidity(FuzzerPass* pass) const {
  151. pass->Apply();
  152. return !validate_after_each_fuzzer_pass_ ||
  153. fuzzerutil::IsValidAndWellFormed(ir_context_.get(), validator_options_,
  154. consumer_);
  155. }
  156. Fuzzer::FuzzerResult Fuzzer::Run() {
  157. // Check compatibility between the library version being linked with and the
  158. // header files being used.
  159. GOOGLE_PROTOBUF_VERIFY_VERSION;
  160. assert(ir_context_ == nullptr && fuzzer_context_ == nullptr &&
  161. transformation_context_ == nullptr &&
  162. transformation_sequence_out_.transformation_size() == 0 &&
  163. "'Run' must not be invoked more than once.");
  164. spvtools::SpirvTools tools(target_env_);
  165. tools.SetMessageConsumer(consumer_);
  166. if (!tools.IsValid()) {
  167. consumer_(SPV_MSG_ERROR, nullptr, {},
  168. "Failed to create SPIRV-Tools interface; stopping.");
  169. return {Fuzzer::FuzzerResultStatus::kFailedToCreateSpirvToolsInterface,
  170. std::vector<uint32_t>(), protobufs::TransformationSequence()};
  171. }
  172. // Initial binary should be valid.
  173. if (!tools.Validate(&binary_in_[0], binary_in_.size(), validator_options_)) {
  174. consumer_(SPV_MSG_ERROR, nullptr, {},
  175. "Initial binary is invalid; stopping.");
  176. return {Fuzzer::FuzzerResultStatus::kInitialBinaryInvalid,
  177. std::vector<uint32_t>(), protobufs::TransformationSequence()};
  178. }
  179. // Build the module from the input binary.
  180. ir_context_ =
  181. BuildModule(target_env_, consumer_, binary_in_.data(), binary_in_.size());
  182. assert(ir_context_);
  183. // The fuzzer will introduce new ids into the module. The module's id bound
  184. // gives the smallest id that can be used for this purpose. We add an offset
  185. // to this so that there is a sizeable gap between the ids used in the
  186. // original module and the ids used for fuzzing, as a readability aid.
  187. //
  188. // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2541) consider the
  189. // case where the maximum id bound is reached.
  190. auto minimum_fresh_id = ir_context_->module()->id_bound() + kIdBoundGap;
  191. fuzzer_context_ =
  192. MakeUnique<FuzzerContext>(random_generator_.get(), minimum_fresh_id);
  193. transformation_context_ = MakeUnique<TransformationContext>(
  194. MakeUnique<FactManager>(ir_context_.get()), validator_options_);
  195. transformation_context_->GetFactManager()->AddInitialFacts(consumer_,
  196. initial_facts_);
  197. RepeatedPassInstances pass_instances{};
  198. // The following passes are likely to be very useful: many other passes
  199. // introduce synonyms, irrelevant ids and constants that these passes can work
  200. // with. We thus enable them with high probability.
  201. MaybeAddRepeatedPass<FuzzerPassObfuscateConstants>(90, &pass_instances);
  202. MaybeAddRepeatedPass<FuzzerPassApplyIdSynonyms>(90, &pass_instances);
  203. MaybeAddRepeatedPass<FuzzerPassReplaceIrrelevantIds>(90, &pass_instances);
  204. do {
  205. // Each call to MaybeAddRepeatedPass randomly decides whether the given pass
  206. // should be enabled, and adds an instance of the pass to |pass_instances|
  207. // if it is enabled.
  208. MaybeAddRepeatedPass<FuzzerPassAddAccessChains>(&pass_instances);
  209. MaybeAddRepeatedPass<FuzzerPassAddBitInstructionSynonyms>(&pass_instances);
  210. MaybeAddRepeatedPass<FuzzerPassAddCompositeExtract>(&pass_instances);
  211. MaybeAddRepeatedPass<FuzzerPassAddCompositeInserts>(&pass_instances);
  212. MaybeAddRepeatedPass<FuzzerPassAddCompositeTypes>(&pass_instances);
  213. MaybeAddRepeatedPass<FuzzerPassAddCopyMemory>(&pass_instances);
  214. MaybeAddRepeatedPass<FuzzerPassAddDeadBlocks>(&pass_instances);
  215. MaybeAddRepeatedPass<FuzzerPassAddDeadBreaks>(&pass_instances);
  216. MaybeAddRepeatedPass<FuzzerPassAddDeadContinues>(&pass_instances);
  217. MaybeAddRepeatedPass<FuzzerPassAddEquationInstructions>(&pass_instances);
  218. MaybeAddRepeatedPass<FuzzerPassAddFunctionCalls>(&pass_instances);
  219. MaybeAddRepeatedPass<FuzzerPassAddGlobalVariables>(&pass_instances);
  220. MaybeAddRepeatedPass<FuzzerPassAddImageSampleUnusedComponents>(
  221. &pass_instances);
  222. MaybeAddRepeatedPass<FuzzerPassAddLoads>(&pass_instances);
  223. MaybeAddRepeatedPass<FuzzerPassAddLocalVariables>(&pass_instances);
  224. MaybeAddRepeatedPass<FuzzerPassAddLoopPreheaders>(&pass_instances);
  225. MaybeAddRepeatedPass<FuzzerPassAddLoopsToCreateIntConstantSynonyms>(
  226. &pass_instances);
  227. MaybeAddRepeatedPass<FuzzerPassAddOpPhiSynonyms>(&pass_instances);
  228. MaybeAddRepeatedPass<FuzzerPassAddParameters>(&pass_instances);
  229. MaybeAddRepeatedPass<FuzzerPassAddRelaxedDecorations>(&pass_instances);
  230. MaybeAddRepeatedPass<FuzzerPassAddStores>(&pass_instances);
  231. MaybeAddRepeatedPass<FuzzerPassAddSynonyms>(&pass_instances);
  232. MaybeAddRepeatedPass<FuzzerPassAddVectorShuffleInstructions>(
  233. &pass_instances);
  234. MaybeAddRepeatedPass<FuzzerPassConstructComposites>(&pass_instances);
  235. MaybeAddRepeatedPass<FuzzerPassCopyObjects>(&pass_instances);
  236. MaybeAddRepeatedPass<FuzzerPassDonateModules>(&pass_instances,
  237. donor_suppliers_);
  238. MaybeAddRepeatedPass<FuzzerPassDuplicateRegionsWithSelections>(
  239. &pass_instances);
  240. MaybeAddRepeatedPass<FuzzerPassExpandVectorReductions>(&pass_instances);
  241. MaybeAddRepeatedPass<FuzzerPassFlattenConditionalBranches>(&pass_instances);
  242. MaybeAddRepeatedPass<FuzzerPassInlineFunctions>(&pass_instances);
  243. MaybeAddRepeatedPass<FuzzerPassInvertComparisonOperators>(&pass_instances);
  244. MaybeAddRepeatedPass<FuzzerPassMakeVectorOperationsDynamic>(
  245. &pass_instances);
  246. MaybeAddRepeatedPass<FuzzerPassMergeBlocks>(&pass_instances);
  247. MaybeAddRepeatedPass<FuzzerPassMergeFunctionReturns>(&pass_instances);
  248. MaybeAddRepeatedPass<FuzzerPassMutatePointers>(&pass_instances);
  249. MaybeAddRepeatedPass<FuzzerPassOutlineFunctions>(&pass_instances);
  250. MaybeAddRepeatedPass<FuzzerPassPermuteBlocks>(&pass_instances);
  251. MaybeAddRepeatedPass<FuzzerPassPermuteFunctionParameters>(&pass_instances);
  252. MaybeAddRepeatedPass<FuzzerPassPermuteInstructions>(&pass_instances);
  253. MaybeAddRepeatedPass<FuzzerPassPropagateInstructionsDown>(&pass_instances);
  254. MaybeAddRepeatedPass<FuzzerPassPropagateInstructionsUp>(&pass_instances);
  255. MaybeAddRepeatedPass<FuzzerPassPushIdsThroughVariables>(&pass_instances);
  256. MaybeAddRepeatedPass<FuzzerPassReplaceAddsSubsMulsWithCarryingExtended>(
  257. &pass_instances);
  258. MaybeAddRepeatedPass<FuzzerPassReplaceBranchesFromDeadBlocksWithExits>(
  259. &pass_instances);
  260. MaybeAddRepeatedPass<FuzzerPassReplaceCopyMemoriesWithLoadsStores>(
  261. &pass_instances);
  262. MaybeAddRepeatedPass<FuzzerPassReplaceCopyObjectsWithStoresLoads>(
  263. &pass_instances);
  264. MaybeAddRepeatedPass<FuzzerPassReplaceLoadsStoresWithCopyMemories>(
  265. &pass_instances);
  266. MaybeAddRepeatedPass<FuzzerPassReplaceParameterWithGlobal>(&pass_instances);
  267. MaybeAddRepeatedPass<FuzzerPassReplaceLinearAlgebraInstructions>(
  268. &pass_instances);
  269. MaybeAddRepeatedPass<FuzzerPassReplaceOpPhiIdsFromDeadPredecessors>(
  270. &pass_instances);
  271. MaybeAddRepeatedPass<FuzzerPassReplaceOpSelectsWithConditionalBranches>(
  272. &pass_instances);
  273. MaybeAddRepeatedPass<FuzzerPassReplaceParamsWithStruct>(&pass_instances);
  274. MaybeAddRepeatedPass<FuzzerPassSplitBlocks>(&pass_instances);
  275. MaybeAddRepeatedPass<FuzzerPassSwapBranchConditionalOperands>(
  276. &pass_instances);
  277. MaybeAddRepeatedPass<FuzzerPassWrapRegionsInSelections>(&pass_instances);
  278. // There is a theoretical possibility that no pass instances were created
  279. // until now; loop again if so.
  280. } while (pass_instances.GetPasses().empty());
  281. RepeatedPassRecommenderStandard pass_recommender(&pass_instances,
  282. fuzzer_context_.get());
  283. std::unique_ptr<RepeatedPassManager> repeated_pass_manager = nullptr;
  284. switch (repeated_pass_strategy_) {
  285. case RepeatedPassStrategy::kSimple:
  286. repeated_pass_manager = MakeUnique<RepeatedPassManagerSimple>(
  287. fuzzer_context_.get(), &pass_instances);
  288. break;
  289. case RepeatedPassStrategy::kLoopedWithRecommendations:
  290. repeated_pass_manager =
  291. MakeUnique<RepeatedPassManagerLoopedWithRecommendations>(
  292. fuzzer_context_.get(), &pass_instances, &pass_recommender);
  293. break;
  294. case RepeatedPassStrategy::kRandomWithRecommendations:
  295. repeated_pass_manager =
  296. MakeUnique<RepeatedPassManagerRandomWithRecommendations>(
  297. fuzzer_context_.get(), &pass_instances, &pass_recommender);
  298. break;
  299. }
  300. do {
  301. if (!ApplyPassAndCheckValidity(
  302. repeated_pass_manager->ChoosePass(transformation_sequence_out_))) {
  303. return {Fuzzer::FuzzerResultStatus::kFuzzerPassLedToInvalidModule,
  304. std::vector<uint32_t>(), protobufs::TransformationSequence()};
  305. }
  306. } while (ShouldContinueFuzzing());
  307. // Now apply some passes that it does not make sense to apply repeatedly,
  308. // as they do not unlock other passes.
  309. std::vector<std::unique_ptr<FuzzerPass>> final_passes;
  310. MaybeAddFinalPass<FuzzerPassAdjustBranchWeights>(&final_passes);
  311. MaybeAddFinalPass<FuzzerPassAdjustFunctionControls>(&final_passes);
  312. MaybeAddFinalPass<FuzzerPassAdjustLoopControls>(&final_passes);
  313. MaybeAddFinalPass<FuzzerPassAdjustMemoryOperandsMasks>(&final_passes);
  314. MaybeAddFinalPass<FuzzerPassAdjustSelectionControls>(&final_passes);
  315. MaybeAddFinalPass<FuzzerPassAddNoContractionDecorations>(&final_passes);
  316. MaybeAddFinalPass<FuzzerPassInterchangeSignednessOfIntegerOperands>(
  317. &final_passes);
  318. MaybeAddFinalPass<FuzzerPassInterchangeZeroLikeConstants>(&final_passes);
  319. MaybeAddFinalPass<FuzzerPassPermutePhiOperands>(&final_passes);
  320. MaybeAddFinalPass<FuzzerPassSwapCommutableOperands>(&final_passes);
  321. MaybeAddFinalPass<FuzzerPassToggleAccessChainInstruction>(&final_passes);
  322. for (auto& pass : final_passes) {
  323. if (!ApplyPassAndCheckValidity(pass.get())) {
  324. return {Fuzzer::FuzzerResultStatus::kFuzzerPassLedToInvalidModule,
  325. std::vector<uint32_t>(), protobufs::TransformationSequence()};
  326. }
  327. }
  328. // Encode the module as a binary.
  329. std::vector<uint32_t> binary_out;
  330. ir_context_->module()->ToBinary(&binary_out, false);
  331. return {Fuzzer::FuzzerResultStatus::kComplete, std::move(binary_out),
  332. std::move(transformation_sequence_out_)};
  333. }
  334. bool Fuzzer::ShouldContinueFuzzing() {
  335. // There's a risk that fuzzing could get stuck, if none of the enabled fuzzer
  336. // passes are able to apply any transformations. To guard against this we
  337. // count the number of times some repeated pass has been applied and ensure
  338. // that fuzzing stops if the number of repeated passes hits the limit on the
  339. // number of transformations that can be applied.
  340. assert(
  341. num_repeated_passes_applied_ <=
  342. fuzzer_context_->GetTransformationLimit() &&
  343. "The number of repeated passes applied must not exceed its upper limit.");
  344. if (ir_context_->module()->id_bound() >= fuzzer_context_->GetIdBoundLimit()) {
  345. return false;
  346. }
  347. if (num_repeated_passes_applied_ ==
  348. fuzzer_context_->GetTransformationLimit()) {
  349. // Stop because fuzzing has got stuck.
  350. return false;
  351. }
  352. auto transformations_applied_so_far =
  353. static_cast<uint32_t>(transformation_sequence_out_.transformation_size());
  354. if (transformations_applied_so_far >=
  355. fuzzer_context_->GetTransformationLimit()) {
  356. // Stop because we have reached the transformation limit.
  357. return false;
  358. }
  359. // If we have applied T transformations so far, and the limit on the number of
  360. // transformations to apply is L (where T < L), the chance that we will
  361. // continue fuzzing is:
  362. //
  363. // 1 - T/(2*L)
  364. //
  365. // That is, the chance of continuing decreases as more transformations are
  366. // applied. Using 2*L instead of L increases the number of transformations
  367. // that are applied on average.
  368. auto chance_of_continuing = static_cast<uint32_t>(
  369. 100.0 * (1.0 - (static_cast<double>(transformations_applied_so_far) /
  370. (2.0 * static_cast<double>(
  371. fuzzer_context_->GetTransformationLimit())))));
  372. if (!fuzzer_context_->ChoosePercentage(chance_of_continuing)) {
  373. // We have probabilistically decided to stop.
  374. return false;
  375. }
  376. // Continue fuzzing!
  377. num_repeated_passes_applied_++;
  378. return true;
  379. }
  380. } // namespace fuzz
  381. } // namespace spvtools