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