fuzzer_pass_obfuscate_constants.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  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_pass_obfuscate_constants.h"
  15. #include <algorithm>
  16. #include <cmath>
  17. #include "source/fuzz/fuzzer_util.h"
  18. #include "source/fuzz/instruction_descriptor.h"
  19. #include "source/fuzz/transformation_replace_boolean_constant_with_constant_binary.h"
  20. #include "source/fuzz/transformation_replace_constant_with_uniform.h"
  21. #include "source/fuzz/uniform_buffer_element_descriptor.h"
  22. #include "source/opt/ir_context.h"
  23. namespace spvtools {
  24. namespace fuzz {
  25. FuzzerPassObfuscateConstants::FuzzerPassObfuscateConstants(
  26. opt::IRContext* ir_context, TransformationContext* transformation_context,
  27. FuzzerContext* fuzzer_context,
  28. protobufs::TransformationSequence* transformations)
  29. : FuzzerPass(ir_context, transformation_context, fuzzer_context,
  30. transformations) {}
  31. FuzzerPassObfuscateConstants::~FuzzerPassObfuscateConstants() = default;
  32. void FuzzerPassObfuscateConstants::ObfuscateBoolConstantViaConstantPair(
  33. uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use,
  34. const std::vector<SpvOp>& greater_than_opcodes,
  35. const std::vector<SpvOp>& less_than_opcodes, uint32_t constant_id_1,
  36. uint32_t constant_id_2, bool first_constant_is_larger) {
  37. auto bool_constant_opcode = GetIRContext()
  38. ->get_def_use_mgr()
  39. ->GetDef(bool_constant_use.id_of_interest())
  40. ->opcode();
  41. assert((bool_constant_opcode == SpvOpConstantFalse ||
  42. bool_constant_opcode == SpvOpConstantTrue) &&
  43. "Precondition: this must be a usage of a boolean constant.");
  44. // Pick an opcode at random. First randomly decide whether to generate
  45. // a 'greater than' or 'less than' kind of opcode, and then select a
  46. // random opcode from the resulting subset.
  47. SpvOp comparison_opcode;
  48. if (GetFuzzerContext()->ChooseEven()) {
  49. comparison_opcode = greater_than_opcodes[GetFuzzerContext()->RandomIndex(
  50. greater_than_opcodes)];
  51. } else {
  52. comparison_opcode =
  53. less_than_opcodes[GetFuzzerContext()->RandomIndex(less_than_opcodes)];
  54. }
  55. // We now need to decide how to order constant_id_1 and constant_id_2 such
  56. // that 'constant_id_1 comparison_opcode constant_id_2' evaluates to the
  57. // boolean constant.
  58. const bool is_greater_than_opcode =
  59. std::find(greater_than_opcodes.begin(), greater_than_opcodes.end(),
  60. comparison_opcode) != greater_than_opcodes.end();
  61. uint32_t lhs_id;
  62. uint32_t rhs_id;
  63. if ((bool_constant_opcode == SpvOpConstantTrue &&
  64. first_constant_is_larger == is_greater_than_opcode) ||
  65. (bool_constant_opcode == SpvOpConstantFalse &&
  66. first_constant_is_larger != is_greater_than_opcode)) {
  67. lhs_id = constant_id_1;
  68. rhs_id = constant_id_2;
  69. } else {
  70. lhs_id = constant_id_2;
  71. rhs_id = constant_id_1;
  72. }
  73. // We can now make a transformation that will replace |bool_constant_use|
  74. // with an expression of the form (written using infix notation):
  75. // |lhs_id| |comparison_opcode| |rhs_id|
  76. auto transformation = TransformationReplaceBooleanConstantWithConstantBinary(
  77. bool_constant_use, lhs_id, rhs_id, comparison_opcode,
  78. GetFuzzerContext()->GetFreshId());
  79. // The transformation should be applicable by construction.
  80. assert(
  81. transformation.IsApplicable(GetIRContext(), *GetTransformationContext()));
  82. // Applying this transformation yields a pointer to the new instruction that
  83. // computes the result of the binary expression.
  84. auto binary_operator_instruction = transformation.ApplyWithResult(
  85. GetIRContext(), GetTransformationContext());
  86. // Add this transformation to the sequence of transformations that have been
  87. // applied.
  88. *GetTransformations()->add_transformation() = transformation.ToMessage();
  89. // Having made a binary expression, there may now be opportunities to further
  90. // obfuscate the constants used as the LHS and RHS of the expression (e.g. by
  91. // replacing them with loads from known uniforms).
  92. //
  93. // We thus consider operands 0 and 1 (LHS and RHS in turn).
  94. for (uint32_t index : {0u, 1u}) {
  95. // We randomly decide, based on the current depth of obfuscation, whether
  96. // to further obfuscate this operand.
  97. if (GetFuzzerContext()->GoDeeperInConstantObfuscation(depth)) {
  98. auto in_operand_use = MakeIdUseDescriptor(
  99. binary_operator_instruction->GetSingleWordInOperand(index),
  100. MakeInstructionDescriptor(binary_operator_instruction->result_id(),
  101. binary_operator_instruction->opcode(), 0),
  102. index);
  103. ObfuscateConstant(depth + 1, in_operand_use);
  104. }
  105. }
  106. }
  107. void FuzzerPassObfuscateConstants::ObfuscateBoolConstantViaFloatConstantPair(
  108. uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use,
  109. uint32_t float_constant_id_1, uint32_t float_constant_id_2) {
  110. auto float_constant_1 = GetIRContext()
  111. ->get_constant_mgr()
  112. ->FindDeclaredConstant(float_constant_id_1)
  113. ->AsFloatConstant();
  114. auto float_constant_2 = GetIRContext()
  115. ->get_constant_mgr()
  116. ->FindDeclaredConstant(float_constant_id_2)
  117. ->AsFloatConstant();
  118. assert(float_constant_1->words() != float_constant_2->words() &&
  119. "The constants should not be identical.");
  120. assert(std::isfinite(float_constant_1->GetValueAsDouble()) &&
  121. "The constants must be finite numbers.");
  122. assert(std::isfinite(float_constant_2->GetValueAsDouble()) &&
  123. "The constants must be finite numbers.");
  124. bool first_constant_is_larger;
  125. assert(float_constant_1->type()->AsFloat()->width() ==
  126. float_constant_2->type()->AsFloat()->width() &&
  127. "First and second floating-point constants must have the same width.");
  128. if (float_constant_1->type()->AsFloat()->width() == 32) {
  129. first_constant_is_larger =
  130. float_constant_1->GetFloat() > float_constant_2->GetFloat();
  131. } else {
  132. assert(float_constant_1->type()->AsFloat()->width() == 64 &&
  133. "Supported floating-point widths are 32 and 64.");
  134. first_constant_is_larger =
  135. float_constant_1->GetDouble() > float_constant_2->GetDouble();
  136. }
  137. std::vector<SpvOp> greater_than_opcodes{
  138. SpvOpFOrdGreaterThan, SpvOpFOrdGreaterThanEqual, SpvOpFUnordGreaterThan,
  139. SpvOpFUnordGreaterThanEqual};
  140. std::vector<SpvOp> less_than_opcodes{
  141. SpvOpFOrdGreaterThan, SpvOpFOrdGreaterThanEqual, SpvOpFUnordGreaterThan,
  142. SpvOpFUnordGreaterThanEqual};
  143. ObfuscateBoolConstantViaConstantPair(
  144. depth, bool_constant_use, greater_than_opcodes, less_than_opcodes,
  145. float_constant_id_1, float_constant_id_2, first_constant_is_larger);
  146. }
  147. void FuzzerPassObfuscateConstants::
  148. ObfuscateBoolConstantViaSignedIntConstantPair(
  149. uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use,
  150. uint32_t signed_int_constant_id_1, uint32_t signed_int_constant_id_2) {
  151. auto signed_int_constant_1 =
  152. GetIRContext()
  153. ->get_constant_mgr()
  154. ->FindDeclaredConstant(signed_int_constant_id_1)
  155. ->AsIntConstant();
  156. auto signed_int_constant_2 =
  157. GetIRContext()
  158. ->get_constant_mgr()
  159. ->FindDeclaredConstant(signed_int_constant_id_2)
  160. ->AsIntConstant();
  161. assert(signed_int_constant_1->words() != signed_int_constant_2->words() &&
  162. "The constants should not be identical.");
  163. bool first_constant_is_larger;
  164. assert(signed_int_constant_1->type()->AsInteger()->width() ==
  165. signed_int_constant_2->type()->AsInteger()->width() &&
  166. "First and second floating-point constants must have the same width.");
  167. assert(signed_int_constant_1->type()->AsInteger()->IsSigned());
  168. assert(signed_int_constant_2->type()->AsInteger()->IsSigned());
  169. if (signed_int_constant_1->type()->AsFloat()->width() == 32) {
  170. first_constant_is_larger =
  171. signed_int_constant_1->GetS32() > signed_int_constant_2->GetS32();
  172. } else {
  173. assert(signed_int_constant_1->type()->AsFloat()->width() == 64 &&
  174. "Supported integer widths are 32 and 64.");
  175. first_constant_is_larger =
  176. signed_int_constant_1->GetS64() > signed_int_constant_2->GetS64();
  177. }
  178. std::vector<SpvOp> greater_than_opcodes{SpvOpSGreaterThan,
  179. SpvOpSGreaterThanEqual};
  180. std::vector<SpvOp> less_than_opcodes{SpvOpSLessThan, SpvOpSLessThanEqual};
  181. ObfuscateBoolConstantViaConstantPair(
  182. depth, bool_constant_use, greater_than_opcodes, less_than_opcodes,
  183. signed_int_constant_id_1, signed_int_constant_id_2,
  184. first_constant_is_larger);
  185. }
  186. void FuzzerPassObfuscateConstants::
  187. ObfuscateBoolConstantViaUnsignedIntConstantPair(
  188. uint32_t depth, const protobufs::IdUseDescriptor& bool_constant_use,
  189. uint32_t unsigned_int_constant_id_1,
  190. uint32_t unsigned_int_constant_id_2) {
  191. auto unsigned_int_constant_1 =
  192. GetIRContext()
  193. ->get_constant_mgr()
  194. ->FindDeclaredConstant(unsigned_int_constant_id_1)
  195. ->AsIntConstant();
  196. auto unsigned_int_constant_2 =
  197. GetIRContext()
  198. ->get_constant_mgr()
  199. ->FindDeclaredConstant(unsigned_int_constant_id_2)
  200. ->AsIntConstant();
  201. assert(unsigned_int_constant_1->words() != unsigned_int_constant_2->words() &&
  202. "The constants should not be identical.");
  203. bool first_constant_is_larger;
  204. assert(unsigned_int_constant_1->type()->AsInteger()->width() ==
  205. unsigned_int_constant_2->type()->AsInteger()->width() &&
  206. "First and second floating-point constants must have the same width.");
  207. assert(!unsigned_int_constant_1->type()->AsInteger()->IsSigned());
  208. assert(!unsigned_int_constant_2->type()->AsInteger()->IsSigned());
  209. if (unsigned_int_constant_1->type()->AsFloat()->width() == 32) {
  210. first_constant_is_larger =
  211. unsigned_int_constant_1->GetU32() > unsigned_int_constant_2->GetU32();
  212. } else {
  213. assert(unsigned_int_constant_1->type()->AsFloat()->width() == 64 &&
  214. "Supported integer widths are 32 and 64.");
  215. first_constant_is_larger =
  216. unsigned_int_constant_1->GetU64() > unsigned_int_constant_2->GetU64();
  217. }
  218. std::vector<SpvOp> greater_than_opcodes{SpvOpUGreaterThan,
  219. SpvOpUGreaterThanEqual};
  220. std::vector<SpvOp> less_than_opcodes{SpvOpULessThan, SpvOpULessThanEqual};
  221. ObfuscateBoolConstantViaConstantPair(
  222. depth, bool_constant_use, greater_than_opcodes, less_than_opcodes,
  223. unsigned_int_constant_id_1, unsigned_int_constant_id_2,
  224. first_constant_is_larger);
  225. }
  226. std::vector<std::vector<uint32_t>>
  227. FuzzerPassObfuscateConstants::GetConstantWordsFromUniformsForType(
  228. uint32_t type_id) {
  229. assert(type_id && "Type id can't be 0");
  230. std::vector<std::vector<uint32_t>> result;
  231. for (const auto& facts_and_types : GetTransformationContext()
  232. ->GetFactManager()
  233. ->GetConstantUniformFactsAndTypes()) {
  234. if (facts_and_types.second != type_id) {
  235. continue;
  236. }
  237. std::vector<uint32_t> words(facts_and_types.first.constant_word().begin(),
  238. facts_and_types.first.constant_word().end());
  239. if (std::find(result.begin(), result.end(), words) == result.end()) {
  240. result.push_back(std::move(words));
  241. }
  242. }
  243. return result;
  244. }
  245. void FuzzerPassObfuscateConstants::ObfuscateBoolConstant(
  246. uint32_t depth, const protobufs::IdUseDescriptor& constant_use) {
  247. // We want to replace the boolean constant use with a binary expression over
  248. // scalar constants, but only if we can then potentially replace the constants
  249. // with uniforms of the same value.
  250. auto available_types_with_uniforms =
  251. GetTransformationContext()
  252. ->GetFactManager()
  253. ->GetTypesForWhichUniformValuesAreKnown();
  254. if (available_types_with_uniforms.empty()) {
  255. // Do not try to obfuscate if we do not have access to any uniform
  256. // elements with known values.
  257. return;
  258. }
  259. auto chosen_type_id =
  260. available_types_with_uniforms[GetFuzzerContext()->RandomIndex(
  261. available_types_with_uniforms)];
  262. auto available_constant_words =
  263. GetConstantWordsFromUniformsForType(chosen_type_id);
  264. if (available_constant_words.size() == 1) {
  265. // TODO(afd): for now we only obfuscate a boolean if there are at least
  266. // two constants available from uniforms, so that we can do a
  267. // comparison between them. It would be good to be able to do the
  268. // obfuscation even if there is only one such constant, if there is
  269. // also another regular constant available.
  270. return;
  271. }
  272. assert(!available_constant_words.empty() &&
  273. "There exists a fact but no constants - impossible");
  274. // We know we have at least two known-to-be-constant uniforms of the chosen
  275. // type. Pick one of them at random.
  276. auto constant_index_1 =
  277. GetFuzzerContext()->RandomIndex(available_constant_words);
  278. uint32_t constant_index_2;
  279. // Now choose another one distinct from the first one.
  280. do {
  281. constant_index_2 =
  282. GetFuzzerContext()->RandomIndex(available_constant_words);
  283. } while (constant_index_1 == constant_index_2);
  284. auto constant_id_1 = FindOrCreateConstant(
  285. available_constant_words[constant_index_1], chosen_type_id, false);
  286. auto constant_id_2 = FindOrCreateConstant(
  287. available_constant_words[constant_index_2], chosen_type_id, false);
  288. assert(constant_id_1 != 0 && constant_id_2 != 0 &&
  289. "We should not find an available constant with an id of 0.");
  290. // Now perform the obfuscation, according to whether the type of the constants
  291. // is float, signed int, or unsigned int.
  292. auto chosen_type = GetIRContext()->get_type_mgr()->GetType(chosen_type_id);
  293. if (chosen_type->AsFloat()) {
  294. ObfuscateBoolConstantViaFloatConstantPair(depth, constant_use,
  295. constant_id_1, constant_id_2);
  296. } else {
  297. assert(chosen_type->AsInteger() &&
  298. "We should only have uniform facts about ints and floats.");
  299. if (chosen_type->AsInteger()->IsSigned()) {
  300. ObfuscateBoolConstantViaSignedIntConstantPair(
  301. depth, constant_use, constant_id_1, constant_id_2);
  302. } else {
  303. ObfuscateBoolConstantViaUnsignedIntConstantPair(
  304. depth, constant_use, constant_id_1, constant_id_2);
  305. }
  306. }
  307. }
  308. void FuzzerPassObfuscateConstants::ObfuscateScalarConstant(
  309. uint32_t /*depth*/, const protobufs::IdUseDescriptor& constant_use) {
  310. // TODO(https://github.com/KhronosGroup/SPIRV-Tools/issues/2670): consider
  311. // additional ways to obfuscate scalar constants.
  312. // Check whether we know that any uniforms are guaranteed to be equal to the
  313. // scalar constant associated with |constant_use|.
  314. auto uniform_descriptors =
  315. GetTransformationContext()
  316. ->GetFactManager()
  317. ->GetUniformDescriptorsForConstant(constant_use.id_of_interest());
  318. if (uniform_descriptors.empty()) {
  319. // No relevant uniforms, so do not obfuscate.
  320. return;
  321. }
  322. // Choose a random available uniform known to be equal to the constant.
  323. const auto& uniform_descriptor =
  324. uniform_descriptors[GetFuzzerContext()->RandomIndex(uniform_descriptors)];
  325. // Make sure the module has OpConstant instructions for each index used to
  326. // access a uniform.
  327. for (auto index : uniform_descriptor.index()) {
  328. FindOrCreateIntegerConstant({index}, 32, true, false);
  329. }
  330. // Make sure the module has OpTypePointer that points to the element type of
  331. // the uniform.
  332. const auto* uniform_variable_instr =
  333. FindUniformVariable(uniform_descriptor, GetIRContext(), true);
  334. assert(uniform_variable_instr &&
  335. "Uniform variable does not exist or not unique.");
  336. const auto* uniform_variable_type_intr =
  337. GetIRContext()->get_def_use_mgr()->GetDef(
  338. uniform_variable_instr->type_id());
  339. assert(uniform_variable_type_intr && "Uniform variable has invalid type");
  340. auto element_type_id = fuzzerutil::WalkCompositeTypeIndices(
  341. GetIRContext(), uniform_variable_type_intr->GetSingleWordInOperand(1),
  342. uniform_descriptor.index());
  343. assert(element_type_id && "Type of uniform variable is invalid");
  344. FindOrCreatePointerType(element_type_id, SpvStorageClassUniform);
  345. // Create, apply and record a transformation to replace the constant use with
  346. // the result of a load from the chosen uniform.
  347. ApplyTransformation(TransformationReplaceConstantWithUniform(
  348. constant_use, uniform_descriptor, GetFuzzerContext()->GetFreshId(),
  349. GetFuzzerContext()->GetFreshId()));
  350. }
  351. void FuzzerPassObfuscateConstants::ObfuscateConstant(
  352. uint32_t depth, const protobufs::IdUseDescriptor& constant_use) {
  353. switch (GetIRContext()
  354. ->get_def_use_mgr()
  355. ->GetDef(constant_use.id_of_interest())
  356. ->opcode()) {
  357. case SpvOpConstantTrue:
  358. case SpvOpConstantFalse:
  359. ObfuscateBoolConstant(depth, constant_use);
  360. break;
  361. case SpvOpConstant:
  362. ObfuscateScalarConstant(depth, constant_use);
  363. break;
  364. default:
  365. assert(false && "The opcode should be one of the above.");
  366. break;
  367. }
  368. }
  369. void FuzzerPassObfuscateConstants::MaybeAddConstantIdUse(
  370. const opt::Instruction& inst, uint32_t in_operand_index,
  371. uint32_t base_instruction_result_id,
  372. const std::map<SpvOp, uint32_t>& skipped_opcode_count,
  373. std::vector<protobufs::IdUseDescriptor>* constant_uses) {
  374. if (inst.GetInOperand(in_operand_index).type != SPV_OPERAND_TYPE_ID) {
  375. // The operand is not an id, so it cannot be a constant id.
  376. return;
  377. }
  378. auto operand_id = inst.GetSingleWordInOperand(in_operand_index);
  379. auto operand_definition =
  380. GetIRContext()->get_def_use_mgr()->GetDef(operand_id);
  381. switch (operand_definition->opcode()) {
  382. case SpvOpConstantFalse:
  383. case SpvOpConstantTrue:
  384. case SpvOpConstant: {
  385. // The operand is a constant id, so make an id use descriptor and record
  386. // it.
  387. protobufs::IdUseDescriptor id_use_descriptor;
  388. id_use_descriptor.set_id_of_interest(operand_id);
  389. id_use_descriptor.mutable_enclosing_instruction()
  390. ->set_target_instruction_opcode(inst.opcode());
  391. id_use_descriptor.mutable_enclosing_instruction()
  392. ->set_base_instruction_result_id(base_instruction_result_id);
  393. id_use_descriptor.mutable_enclosing_instruction()
  394. ->set_num_opcodes_to_ignore(
  395. skipped_opcode_count.find(inst.opcode()) ==
  396. skipped_opcode_count.end()
  397. ? 0
  398. : skipped_opcode_count.at(inst.opcode()));
  399. id_use_descriptor.set_in_operand_index(in_operand_index);
  400. constant_uses->push_back(id_use_descriptor);
  401. } break;
  402. default:
  403. break;
  404. }
  405. }
  406. void FuzzerPassObfuscateConstants::Apply() {
  407. // First, gather up all the constant uses available in the module, by going
  408. // through each block in each function.
  409. std::vector<protobufs::IdUseDescriptor> constant_uses;
  410. for (auto& function : *GetIRContext()->module()) {
  411. for (auto& block : function) {
  412. // For each constant use we encounter we are going to make an id use
  413. // descriptor. An id use is described with respect to a base instruction;
  414. // if there are instructions at the start of the block without result ids,
  415. // the base instruction will have to be the block's label.
  416. uint32_t base_instruction_result_id = block.id();
  417. // An id use descriptor also records how many instructions of a particular
  418. // opcode need to be skipped in order to find the instruction of interest
  419. // from the base instruction. We maintain a mapping that records a skip
  420. // count for each relevant opcode.
  421. std::map<SpvOp, uint32_t> skipped_opcode_count;
  422. // Go through each instruction in the block.
  423. for (auto& inst : block) {
  424. if (inst.HasResultId()) {
  425. // The instruction has a result id, so can be used as the base
  426. // instruction from now on, until another instruction with a result id
  427. // is encountered.
  428. base_instruction_result_id = inst.result_id();
  429. // Opcode skip counts were with respect to the previous base
  430. // instruction and are now irrelevant.
  431. skipped_opcode_count.clear();
  432. }
  433. // The instruction must not be an OpVariable, the only id that an
  434. // OpVariable uses is an initializer id, which has to remain
  435. // constant.
  436. if (inst.opcode() != SpvOpVariable) {
  437. // Consider each operand of the instruction, and add a constant id
  438. // use for the operand if relevant.
  439. for (uint32_t in_operand_index = 0;
  440. in_operand_index < inst.NumInOperands(); in_operand_index++) {
  441. MaybeAddConstantIdUse(inst, in_operand_index,
  442. base_instruction_result_id,
  443. skipped_opcode_count, &constant_uses);
  444. }
  445. }
  446. if (!inst.HasResultId()) {
  447. // The instruction has no result id, so in order to identify future id
  448. // uses for instructions with this opcode from the existing base
  449. // instruction, we need to increase the skip count for this opcode.
  450. skipped_opcode_count[inst.opcode()] =
  451. skipped_opcode_count.find(inst.opcode()) ==
  452. skipped_opcode_count.end()
  453. ? 1
  454. : skipped_opcode_count[inst.opcode()] + 1;
  455. }
  456. }
  457. }
  458. }
  459. // Go through the constant uses in a random order by repeatedly pulling out a
  460. // constant use at a random index.
  461. while (!constant_uses.empty()) {
  462. auto index = GetFuzzerContext()->RandomIndex(constant_uses);
  463. auto constant_use = std::move(constant_uses[index]);
  464. constant_uses.erase(constant_uses.begin() + index);
  465. // Decide probabilistically whether to skip or obfuscate this constant use.
  466. if (!GetFuzzerContext()->ChoosePercentage(
  467. GetFuzzerContext()->GetChanceOfObfuscatingConstant())) {
  468. continue;
  469. }
  470. ObfuscateConstant(0, constant_use);
  471. }
  472. }
  473. } // namespace fuzz
  474. } // namespace spvtools