fuzzer_pass_add_loads.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. // Copyright (c) 2020 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_add_loads.h"
  15. #include "source/fuzz/fuzzer_util.h"
  16. #include "source/fuzz/transformation_load.h"
  17. namespace spvtools {
  18. namespace fuzz {
  19. FuzzerPassAddLoads::FuzzerPassAddLoads(
  20. opt::IRContext* ir_context, TransformationContext* transformation_context,
  21. FuzzerContext* fuzzer_context,
  22. protobufs::TransformationSequence* transformations,
  23. bool ignore_inapplicable_transformations)
  24. : FuzzerPass(ir_context, transformation_context, fuzzer_context,
  25. transformations, ignore_inapplicable_transformations) {}
  26. void FuzzerPassAddLoads::Apply() {
  27. ForEachInstructionWithInstructionDescriptor(
  28. [this](opt::Function* function, opt::BasicBlock* block,
  29. opt::BasicBlock::iterator inst_it,
  30. const protobufs::InstructionDescriptor& instruction_descriptor)
  31. -> void {
  32. assert(
  33. inst_it->opcode() ==
  34. spv::Op(instruction_descriptor.target_instruction_opcode()) &&
  35. "The opcode of the instruction we might insert before must be "
  36. "the same as the opcode in the descriptor for the instruction");
  37. // Randomly decide whether to try inserting a load here.
  38. if (!GetFuzzerContext()->ChoosePercentage(
  39. GetFuzzerContext()->GetChanceOfAddingLoad())) {
  40. return;
  41. }
  42. // Check whether it is legitimate to insert a load or atomic load before
  43. // this instruction.
  44. if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpLoad,
  45. inst_it)) {
  46. return;
  47. }
  48. if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpAtomicLoad,
  49. inst_it)) {
  50. return;
  51. }
  52. std::vector<opt::Instruction*> relevant_instructions =
  53. FindAvailableInstructions(
  54. function, block, inst_it,
  55. [](opt::IRContext* context,
  56. opt::Instruction* instruction) -> bool {
  57. if (!instruction->result_id() || !instruction->type_id()) {
  58. return false;
  59. }
  60. switch (instruction->opcode()) {
  61. case spv::Op::OpConstantNull:
  62. case spv::Op::OpUndef:
  63. // Do not allow loading from a null or undefined pointer;
  64. // this might be OK if the block is dead, but for now we
  65. // conservatively avoid it.
  66. return false;
  67. default:
  68. break;
  69. }
  70. return context->get_def_use_mgr()
  71. ->GetDef(instruction->type_id())
  72. ->opcode() == spv::Op::OpTypePointer;
  73. });
  74. // At this point, |relevant_instructions| contains all the pointers
  75. // we might think of loading from.
  76. if (relevant_instructions.empty()) {
  77. return;
  78. }
  79. auto chosen_instruction =
  80. relevant_instructions[GetFuzzerContext()->RandomIndex(
  81. relevant_instructions)];
  82. bool is_atomic_load = false;
  83. uint32_t memory_scope_id = 0;
  84. uint32_t memory_semantics_id = 0;
  85. auto storage_class = static_cast<spv::StorageClass>(
  86. GetIRContext()
  87. ->get_def_use_mgr()
  88. ->GetDef(chosen_instruction->type_id())
  89. ->GetSingleWordInOperand(0));
  90. switch (storage_class) {
  91. case spv::StorageClass::StorageBuffer:
  92. case spv::StorageClass::PhysicalStorageBuffer:
  93. case spv::StorageClass::Workgroup:
  94. case spv::StorageClass::CrossWorkgroup:
  95. case spv::StorageClass::AtomicCounter:
  96. case spv::StorageClass::Image:
  97. if (GetFuzzerContext()->ChoosePercentage(
  98. GetFuzzerContext()->GetChanceOfAddingAtomicLoad())) {
  99. is_atomic_load = true;
  100. memory_scope_id = FindOrCreateConstant(
  101. {uint32_t(spv::Scope::Invocation)},
  102. FindOrCreateIntegerType(32, GetFuzzerContext()->ChooseEven()),
  103. false);
  104. memory_semantics_id = FindOrCreateConstant(
  105. {static_cast<uint32_t>(
  106. fuzzerutil::GetMemorySemanticsForStorageClass(
  107. storage_class))},
  108. FindOrCreateIntegerType(32, GetFuzzerContext()->ChooseEven()),
  109. false);
  110. }
  111. break;
  112. default:
  113. break;
  114. }
  115. // Create and apply the transformation.
  116. ApplyTransformation(TransformationLoad(
  117. GetFuzzerContext()->GetFreshId(), chosen_instruction->result_id(),
  118. is_atomic_load, memory_scope_id, memory_semantics_id,
  119. instruction_descriptor));
  120. });
  121. }
  122. } // namespace fuzz
  123. } // namespace spvtools