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