fuzzer.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  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 "source/fuzz/fuzzer_context.h"
  19. #include "source/fuzz/fuzzer_pass_add_access_chains.h"
  20. #include "source/fuzz/fuzzer_pass_add_bit_instruction_synonyms.h"
  21. #include "source/fuzz/fuzzer_pass_add_composite_extract.h"
  22. #include "source/fuzz/fuzzer_pass_add_composite_inserts.h"
  23. #include "source/fuzz/fuzzer_pass_add_composite_types.h"
  24. #include "source/fuzz/fuzzer_pass_add_copy_memory.h"
  25. #include "source/fuzz/fuzzer_pass_add_dead_blocks.h"
  26. #include "source/fuzz/fuzzer_pass_add_dead_breaks.h"
  27. #include "source/fuzz/fuzzer_pass_add_dead_continues.h"
  28. #include "source/fuzz/fuzzer_pass_add_equation_instructions.h"
  29. #include "source/fuzz/fuzzer_pass_add_function_calls.h"
  30. #include "source/fuzz/fuzzer_pass_add_global_variables.h"
  31. #include "source/fuzz/fuzzer_pass_add_image_sample_unused_components.h"
  32. #include "source/fuzz/fuzzer_pass_add_loads.h"
  33. #include "source/fuzz/fuzzer_pass_add_local_variables.h"
  34. #include "source/fuzz/fuzzer_pass_add_loop_preheaders.h"
  35. #include "source/fuzz/fuzzer_pass_add_loops_to_create_int_constant_synonyms.h"
  36. #include "source/fuzz/fuzzer_pass_add_no_contraction_decorations.h"
  37. #include "source/fuzz/fuzzer_pass_add_opphi_synonyms.h"
  38. #include "source/fuzz/fuzzer_pass_add_parameters.h"
  39. #include "source/fuzz/fuzzer_pass_add_relaxed_decorations.h"
  40. #include "source/fuzz/fuzzer_pass_add_stores.h"
  41. #include "source/fuzz/fuzzer_pass_add_synonyms.h"
  42. #include "source/fuzz/fuzzer_pass_add_vector_shuffle_instructions.h"
  43. #include "source/fuzz/fuzzer_pass_adjust_branch_weights.h"
  44. #include "source/fuzz/fuzzer_pass_adjust_function_controls.h"
  45. #include "source/fuzz/fuzzer_pass_adjust_loop_controls.h"
  46. #include "source/fuzz/fuzzer_pass_adjust_memory_operands_masks.h"
  47. #include "source/fuzz/fuzzer_pass_adjust_selection_controls.h"
  48. #include "source/fuzz/fuzzer_pass_apply_id_synonyms.h"
  49. #include "source/fuzz/fuzzer_pass_construct_composites.h"
  50. #include "source/fuzz/fuzzer_pass_copy_objects.h"
  51. #include "source/fuzz/fuzzer_pass_donate_modules.h"
  52. #include "source/fuzz/fuzzer_pass_duplicate_regions_with_selections.h"
  53. #include "source/fuzz/fuzzer_pass_expand_vector_reductions.h"
  54. #include "source/fuzz/fuzzer_pass_flatten_conditional_branches.h"
  55. #include "source/fuzz/fuzzer_pass_inline_functions.h"
  56. #include "source/fuzz/fuzzer_pass_interchange_signedness_of_integer_operands.h"
  57. #include "source/fuzz/fuzzer_pass_interchange_zero_like_constants.h"
  58. #include "source/fuzz/fuzzer_pass_invert_comparison_operators.h"
  59. #include "source/fuzz/fuzzer_pass_make_vector_operations_dynamic.h"
  60. #include "source/fuzz/fuzzer_pass_merge_blocks.h"
  61. #include "source/fuzz/fuzzer_pass_merge_function_returns.h"
  62. #include "source/fuzz/fuzzer_pass_mutate_pointers.h"
  63. #include "source/fuzz/fuzzer_pass_obfuscate_constants.h"
  64. #include "source/fuzz/fuzzer_pass_outline_functions.h"
  65. #include "source/fuzz/fuzzer_pass_permute_blocks.h"
  66. #include "source/fuzz/fuzzer_pass_permute_function_parameters.h"
  67. #include "source/fuzz/fuzzer_pass_permute_function_variables.h"
  68. #include "source/fuzz/fuzzer_pass_permute_instructions.h"
  69. #include "source/fuzz/fuzzer_pass_permute_phi_operands.h"
  70. #include "source/fuzz/fuzzer_pass_propagate_instructions_down.h"
  71. #include "source/fuzz/fuzzer_pass_propagate_instructions_up.h"
  72. #include "source/fuzz/fuzzer_pass_push_ids_through_variables.h"
  73. #include "source/fuzz/fuzzer_pass_replace_adds_subs_muls_with_carrying_extended.h"
  74. #include "source/fuzz/fuzzer_pass_replace_branches_from_dead_blocks_with_exits.h"
  75. #include "source/fuzz/fuzzer_pass_replace_copy_memories_with_loads_stores.h"
  76. #include "source/fuzz/fuzzer_pass_replace_copy_objects_with_stores_loads.h"
  77. #include "source/fuzz/fuzzer_pass_replace_irrelevant_ids.h"
  78. #include "source/fuzz/fuzzer_pass_replace_linear_algebra_instructions.h"
  79. #include "source/fuzz/fuzzer_pass_replace_loads_stores_with_copy_memories.h"
  80. #include "source/fuzz/fuzzer_pass_replace_opphi_ids_from_dead_predecessors.h"
  81. #include "source/fuzz/fuzzer_pass_replace_opselects_with_conditional_branches.h"
  82. #include "source/fuzz/fuzzer_pass_replace_parameter_with_global.h"
  83. #include "source/fuzz/fuzzer_pass_replace_params_with_struct.h"
  84. #include "source/fuzz/fuzzer_pass_split_blocks.h"
  85. #include "source/fuzz/fuzzer_pass_swap_commutable_operands.h"
  86. #include "source/fuzz/fuzzer_pass_swap_conditional_branch_operands.h"
  87. #include "source/fuzz/fuzzer_pass_swap_functions.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/fuzzer_pass_wrap_vector_synonym.h"
  91. #include "source/fuzz/pass_management/repeated_pass_manager.h"
  92. #include "source/fuzz/pass_management/repeated_pass_recommender_standard.h"
  93. #include "source/fuzz/protobufs/spirvfuzz_protobufs.h"
  94. #include "source/fuzz/transformation_context.h"
  95. #include "source/opt/build_module.h"
  96. #include "source/spirv_fuzzer_options.h"
  97. #include "source/util/make_unique.h"
  98. namespace spvtools {
  99. namespace fuzz {
  100. Fuzzer::Fuzzer(std::unique_ptr<opt::IRContext> ir_context,
  101. std::unique_ptr<TransformationContext> transformation_context,
  102. std::unique_ptr<FuzzerContext> fuzzer_context,
  103. MessageConsumer consumer,
  104. const std::vector<fuzzerutil::ModuleSupplier>& donor_suppliers,
  105. bool enable_all_passes,
  106. RepeatedPassStrategy repeated_pass_strategy,
  107. bool validate_after_each_fuzzer_pass,
  108. spv_validator_options validator_options,
  109. bool ignore_inapplicable_transformations /* = true */)
  110. : consumer_(std::move(consumer)),
  111. enable_all_passes_(enable_all_passes),
  112. validate_after_each_fuzzer_pass_(validate_after_each_fuzzer_pass),
  113. validator_options_(validator_options),
  114. num_repeated_passes_applied_(0),
  115. is_valid_(true),
  116. ir_context_(std::move(ir_context)),
  117. transformation_context_(std::move(transformation_context)),
  118. fuzzer_context_(std::move(fuzzer_context)),
  119. transformation_sequence_out_(),
  120. pass_instances_(),
  121. repeated_pass_recommender_(nullptr),
  122. repeated_pass_manager_(nullptr),
  123. final_passes_(),
  124. ignore_inapplicable_transformations_(
  125. ignore_inapplicable_transformations) {
  126. assert(ir_context_ && "IRContext is not initialized");
  127. assert(fuzzer_context_ && "FuzzerContext is not initialized");
  128. assert(transformation_context_ && "TransformationContext is not initialized");
  129. assert(fuzzerutil::IsValidAndWellFormed(ir_context_.get(), validator_options_,
  130. consumer_) &&
  131. "IRContext is invalid");
  132. // The following passes are likely to be very useful: many other passes
  133. // introduce synonyms, irrelevant ids and constants that these passes can work
  134. // with. We thus enable them with high probability.
  135. MaybeAddRepeatedPass<FuzzerPassObfuscateConstants>(90, &pass_instances_);
  136. MaybeAddRepeatedPass<FuzzerPassApplyIdSynonyms>(90, &pass_instances_);
  137. MaybeAddRepeatedPass<FuzzerPassReplaceIrrelevantIds>(90, &pass_instances_);
  138. do {
  139. // Each call to MaybeAddRepeatedPass randomly decides whether the given pass
  140. // should be enabled, and adds an instance of the pass to |pass_instances|
  141. // if it is enabled.
  142. MaybeAddRepeatedPass<FuzzerPassAddAccessChains>(&pass_instances_);
  143. MaybeAddRepeatedPass<FuzzerPassAddBitInstructionSynonyms>(&pass_instances_);
  144. MaybeAddRepeatedPass<FuzzerPassAddCompositeExtract>(&pass_instances_);
  145. MaybeAddRepeatedPass<FuzzerPassAddCompositeInserts>(&pass_instances_);
  146. MaybeAddRepeatedPass<FuzzerPassAddCompositeTypes>(&pass_instances_);
  147. MaybeAddRepeatedPass<FuzzerPassAddCopyMemory>(&pass_instances_);
  148. MaybeAddRepeatedPass<FuzzerPassAddDeadBlocks>(&pass_instances_);
  149. MaybeAddRepeatedPass<FuzzerPassAddDeadBreaks>(&pass_instances_);
  150. MaybeAddRepeatedPass<FuzzerPassAddDeadContinues>(&pass_instances_);
  151. MaybeAddRepeatedPass<FuzzerPassAddEquationInstructions>(&pass_instances_);
  152. MaybeAddRepeatedPass<FuzzerPassAddFunctionCalls>(&pass_instances_);
  153. MaybeAddRepeatedPass<FuzzerPassAddGlobalVariables>(&pass_instances_);
  154. MaybeAddRepeatedPass<FuzzerPassAddImageSampleUnusedComponents>(
  155. &pass_instances_);
  156. MaybeAddRepeatedPass<FuzzerPassAddLoads>(&pass_instances_);
  157. MaybeAddRepeatedPass<FuzzerPassAddLocalVariables>(&pass_instances_);
  158. MaybeAddRepeatedPass<FuzzerPassAddLoopPreheaders>(&pass_instances_);
  159. MaybeAddRepeatedPass<FuzzerPassAddLoopsToCreateIntConstantSynonyms>(
  160. &pass_instances_);
  161. MaybeAddRepeatedPass<FuzzerPassAddOpPhiSynonyms>(&pass_instances_);
  162. MaybeAddRepeatedPass<FuzzerPassAddParameters>(&pass_instances_);
  163. MaybeAddRepeatedPass<FuzzerPassAddRelaxedDecorations>(&pass_instances_);
  164. MaybeAddRepeatedPass<FuzzerPassAddStores>(&pass_instances_);
  165. MaybeAddRepeatedPass<FuzzerPassAddSynonyms>(&pass_instances_);
  166. MaybeAddRepeatedPass<FuzzerPassAddVectorShuffleInstructions>(
  167. &pass_instances_);
  168. MaybeAddRepeatedPass<FuzzerPassConstructComposites>(&pass_instances_);
  169. MaybeAddRepeatedPass<FuzzerPassCopyObjects>(&pass_instances_);
  170. MaybeAddRepeatedPass<FuzzerPassDonateModules>(&pass_instances_,
  171. donor_suppliers);
  172. MaybeAddRepeatedPass<FuzzerPassDuplicateRegionsWithSelections>(
  173. &pass_instances_);
  174. MaybeAddRepeatedPass<FuzzerPassExpandVectorReductions>(&pass_instances_);
  175. MaybeAddRepeatedPass<FuzzerPassFlattenConditionalBranches>(
  176. &pass_instances_);
  177. MaybeAddRepeatedPass<FuzzerPassInlineFunctions>(&pass_instances_);
  178. MaybeAddRepeatedPass<FuzzerPassInvertComparisonOperators>(&pass_instances_);
  179. MaybeAddRepeatedPass<FuzzerPassMakeVectorOperationsDynamic>(
  180. &pass_instances_);
  181. MaybeAddRepeatedPass<FuzzerPassMergeBlocks>(&pass_instances_);
  182. MaybeAddRepeatedPass<FuzzerPassMergeFunctionReturns>(&pass_instances_);
  183. MaybeAddRepeatedPass<FuzzerPassMutatePointers>(&pass_instances_);
  184. MaybeAddRepeatedPass<FuzzerPassOutlineFunctions>(&pass_instances_);
  185. MaybeAddRepeatedPass<FuzzerPassPermuteBlocks>(&pass_instances_);
  186. MaybeAddRepeatedPass<FuzzerPassPermuteFunctionParameters>(&pass_instances_);
  187. MaybeAddRepeatedPass<FuzzerPassPermuteInstructions>(&pass_instances_);
  188. MaybeAddRepeatedPass<FuzzerPassPropagateInstructionsDown>(&pass_instances_);
  189. MaybeAddRepeatedPass<FuzzerPassPropagateInstructionsUp>(&pass_instances_);
  190. MaybeAddRepeatedPass<FuzzerPassPushIdsThroughVariables>(&pass_instances_);
  191. MaybeAddRepeatedPass<FuzzerPassReplaceAddsSubsMulsWithCarryingExtended>(
  192. &pass_instances_);
  193. MaybeAddRepeatedPass<FuzzerPassReplaceBranchesFromDeadBlocksWithExits>(
  194. &pass_instances_);
  195. MaybeAddRepeatedPass<FuzzerPassReplaceCopyMemoriesWithLoadsStores>(
  196. &pass_instances_);
  197. MaybeAddRepeatedPass<FuzzerPassReplaceCopyObjectsWithStoresLoads>(
  198. &pass_instances_);
  199. MaybeAddRepeatedPass<FuzzerPassReplaceLoadsStoresWithCopyMemories>(
  200. &pass_instances_);
  201. MaybeAddRepeatedPass<FuzzerPassReplaceParameterWithGlobal>(
  202. &pass_instances_);
  203. MaybeAddRepeatedPass<FuzzerPassReplaceLinearAlgebraInstructions>(
  204. &pass_instances_);
  205. MaybeAddRepeatedPass<FuzzerPassReplaceOpPhiIdsFromDeadPredecessors>(
  206. &pass_instances_);
  207. MaybeAddRepeatedPass<FuzzerPassReplaceOpSelectsWithConditionalBranches>(
  208. &pass_instances_);
  209. MaybeAddRepeatedPass<FuzzerPassReplaceParamsWithStruct>(&pass_instances_);
  210. MaybeAddRepeatedPass<FuzzerPassSplitBlocks>(&pass_instances_);
  211. MaybeAddRepeatedPass<FuzzerPassSwapBranchConditionalOperands>(
  212. &pass_instances_);
  213. MaybeAddRepeatedPass<FuzzerPassWrapRegionsInSelections>(&pass_instances_);
  214. MaybeAddRepeatedPass<FuzzerPassWrapVectorSynonym>(&pass_instances_);
  215. // There is a theoretical possibility that no pass instances were created
  216. // until now; loop again if so.
  217. } while (pass_instances_.GetPasses().empty());
  218. repeated_pass_recommender_ = MakeUnique<RepeatedPassRecommenderStandard>(
  219. &pass_instances_, fuzzer_context_.get());
  220. repeated_pass_manager_ = RepeatedPassManager::Create(
  221. repeated_pass_strategy, fuzzer_context_.get(), &pass_instances_,
  222. repeated_pass_recommender_.get());
  223. MaybeAddFinalPass<FuzzerPassAdjustBranchWeights>(&final_passes_);
  224. MaybeAddFinalPass<FuzzerPassAdjustFunctionControls>(&final_passes_);
  225. MaybeAddFinalPass<FuzzerPassAdjustLoopControls>(&final_passes_);
  226. MaybeAddFinalPass<FuzzerPassAdjustMemoryOperandsMasks>(&final_passes_);
  227. MaybeAddFinalPass<FuzzerPassAdjustSelectionControls>(&final_passes_);
  228. MaybeAddFinalPass<FuzzerPassAddNoContractionDecorations>(&final_passes_);
  229. if (!fuzzer_context_->IsWgslCompatible()) {
  230. // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/4214):
  231. // this is disabled temporarily due to some issues in the Tint compiler.
  232. // Enable it back when the issues are resolved.
  233. MaybeAddFinalPass<FuzzerPassInterchangeSignednessOfIntegerOperands>(
  234. &final_passes_);
  235. }
  236. MaybeAddFinalPass<FuzzerPassInterchangeZeroLikeConstants>(&final_passes_);
  237. MaybeAddFinalPass<FuzzerPassPermuteFunctionVariables>(&final_passes_);
  238. MaybeAddFinalPass<FuzzerPassPermutePhiOperands>(&final_passes_);
  239. MaybeAddFinalPass<FuzzerPassSwapCommutableOperands>(&final_passes_);
  240. MaybeAddFinalPass<FuzzerPassSwapFunctions>(&final_passes_);
  241. MaybeAddFinalPass<FuzzerPassToggleAccessChainInstruction>(&final_passes_);
  242. }
  243. Fuzzer::~Fuzzer() = default;
  244. template <typename FuzzerPassT, typename... Args>
  245. void Fuzzer::MaybeAddRepeatedPass(uint32_t percentage_chance_of_adding_pass,
  246. RepeatedPassInstances* pass_instances,
  247. Args&&... extra_args) {
  248. if (enable_all_passes_ ||
  249. fuzzer_context_->ChoosePercentage(percentage_chance_of_adding_pass)) {
  250. pass_instances->SetPass(MakeUnique<FuzzerPassT>(
  251. ir_context_.get(), transformation_context_.get(), fuzzer_context_.get(),
  252. &transformation_sequence_out_, ignore_inapplicable_transformations_,
  253. std::forward<Args>(extra_args)...));
  254. }
  255. }
  256. template <typename FuzzerPassT, typename... Args>
  257. void Fuzzer::MaybeAddFinalPass(std::vector<std::unique_ptr<FuzzerPass>>* passes,
  258. Args&&... extra_args) {
  259. if (enable_all_passes_ || fuzzer_context_->ChooseEven()) {
  260. passes->push_back(MakeUnique<FuzzerPassT>(
  261. ir_context_.get(), transformation_context_.get(), fuzzer_context_.get(),
  262. &transformation_sequence_out_, ignore_inapplicable_transformations_,
  263. std::forward<Args>(extra_args)...));
  264. }
  265. }
  266. bool Fuzzer::ApplyPassAndCheckValidity(FuzzerPass* pass) const {
  267. pass->Apply();
  268. return !validate_after_each_fuzzer_pass_ ||
  269. fuzzerutil::IsValidAndWellFormed(ir_context_.get(), validator_options_,
  270. consumer_);
  271. }
  272. opt::IRContext* Fuzzer::GetIRContext() { return ir_context_.get(); }
  273. const protobufs::TransformationSequence& Fuzzer::GetTransformationSequence()
  274. const {
  275. return transformation_sequence_out_;
  276. }
  277. Fuzzer::Result Fuzzer::Run(uint32_t num_of_transformations_to_apply) {
  278. assert(is_valid_ && "The module was invalidated during the previous fuzzing");
  279. const auto initial_num_of_transformations =
  280. static_cast<uint32_t>(transformation_sequence_out_.transformation_size());
  281. auto status = Status::kComplete;
  282. do {
  283. if (!ApplyPassAndCheckValidity(
  284. repeated_pass_manager_->ChoosePass(transformation_sequence_out_))) {
  285. status = Status::kFuzzerPassLedToInvalidModule;
  286. break;
  287. }
  288. // Check that the module is small enough.
  289. if (ir_context_->module()->id_bound() >=
  290. fuzzer_context_->GetIdBoundLimit()) {
  291. status = Status::kModuleTooBig;
  292. break;
  293. }
  294. auto transformations_applied_so_far = static_cast<uint32_t>(
  295. transformation_sequence_out_.transformation_size());
  296. assert(transformations_applied_so_far >= initial_num_of_transformations &&
  297. "Number of transformations cannot decrease");
  298. // Check if we've already applied the maximum number of transformations.
  299. if (transformations_applied_so_far >=
  300. fuzzer_context_->GetTransformationLimit()) {
  301. status = Status::kTransformationLimitReached;
  302. break;
  303. }
  304. // Check that we've not got stuck (this can happen if the only available
  305. // fuzzer passes are not able to apply any transformations, or can only
  306. // apply very few transformations).
  307. if (num_repeated_passes_applied_ >=
  308. fuzzer_context_->GetTransformationLimit()) {
  309. status = Status::kFuzzerStuck;
  310. break;
  311. }
  312. // Check whether we've exceeded the number of transformations we can apply
  313. // in a single call to this method.
  314. if (num_of_transformations_to_apply != 0 &&
  315. transformations_applied_so_far - initial_num_of_transformations >=
  316. num_of_transformations_to_apply) {
  317. status = Status::kComplete;
  318. break;
  319. }
  320. } while (ShouldContinueRepeatedPasses(num_of_transformations_to_apply == 0));
  321. if (status != Status::kFuzzerPassLedToInvalidModule) {
  322. // We apply this transformations despite the fact that we might exceed
  323. // |num_of_transformations_to_apply|. This is not a problem for us since
  324. // these fuzzer passes are relatively simple yet might trigger some bugs.
  325. for (auto& pass : final_passes_) {
  326. if (!ApplyPassAndCheckValidity(pass.get())) {
  327. status = Status::kFuzzerPassLedToInvalidModule;
  328. break;
  329. }
  330. }
  331. }
  332. is_valid_ = status != Status::kFuzzerPassLedToInvalidModule;
  333. return {status, static_cast<uint32_t>(
  334. transformation_sequence_out_.transformation_size()) !=
  335. initial_num_of_transformations};
  336. }
  337. bool Fuzzer::ShouldContinueRepeatedPasses(
  338. bool continue_fuzzing_probabilistically) {
  339. if (continue_fuzzing_probabilistically) {
  340. // If we have applied T transformations so far, and the limit on the number
  341. // of transformations to apply is L (where T < L), the chance that we will
  342. // continue fuzzing is:
  343. //
  344. // 1 - T/(2*L)
  345. //
  346. // That is, the chance of continuing decreases as more transformations are
  347. // applied. Using 2*L instead of L increases the number of transformations
  348. // that are applied on average.
  349. auto transformations_applied_so_far = static_cast<uint32_t>(
  350. transformation_sequence_out_.transformation_size());
  351. auto chance_of_continuing = static_cast<uint32_t>(
  352. 100.0 *
  353. (1.0 - (static_cast<double>(transformations_applied_so_far) /
  354. (2.0 * static_cast<double>(
  355. fuzzer_context_->GetTransformationLimit())))));
  356. if (!fuzzer_context_->ChoosePercentage(chance_of_continuing)) {
  357. // We have probabilistically decided to stop.
  358. return false;
  359. }
  360. }
  361. // Continue fuzzing!
  362. num_repeated_passes_applied_++;
  363. return true;
  364. }
  365. } // namespace fuzz
  366. } // namespace spvtools