fuzzer_pass_add_stores.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  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_stores.h"
  15. #include "source/fuzz/fuzzer_util.h"
  16. #include "source/fuzz/transformation_store.h"
  17. namespace spvtools {
  18. namespace fuzz {
  19. FuzzerPassAddStores::FuzzerPassAddStores(
  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 FuzzerPassAddStores::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 store here.
  38. if (!GetFuzzerContext()->ChoosePercentage(
  39. GetFuzzerContext()->GetChanceOfAddingStore())) {
  40. return;
  41. }
  42. // Check whether it is legitimate to insert a store before this
  43. // instruction.
  44. if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(spv::Op::OpStore,
  45. inst_it)) {
  46. return;
  47. }
  48. if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
  49. spv::Op::OpAtomicStore, inst_it)) {
  50. return;
  51. }
  52. // Look for pointers we might consider storing to.
  53. std::vector<opt::Instruction*> relevant_pointers =
  54. FindAvailableInstructions(
  55. function, block, inst_it,
  56. [this, block](opt::IRContext* context,
  57. opt::Instruction* instruction) -> bool {
  58. if (!instruction->result_id() || !instruction->type_id()) {
  59. return false;
  60. }
  61. auto type_inst = context->get_def_use_mgr()->GetDef(
  62. instruction->type_id());
  63. if (type_inst->opcode() != spv::Op::OpTypePointer) {
  64. // Not a pointer.
  65. return false;
  66. }
  67. if (instruction->IsReadOnlyPointer()) {
  68. // Read only: cannot store to it.
  69. return false;
  70. }
  71. switch (instruction->opcode()) {
  72. case spv::Op::OpConstantNull:
  73. case spv::Op::OpUndef:
  74. // Do not allow storing to a null or undefined pointer;
  75. // this might be OK if the block is dead, but for now we
  76. // conservatively avoid it.
  77. return false;
  78. default:
  79. break;
  80. }
  81. return GetTransformationContext()
  82. ->GetFactManager()
  83. ->BlockIsDead(block->id()) ||
  84. GetTransformationContext()
  85. ->GetFactManager()
  86. ->PointeeValueIsIrrelevant(
  87. instruction->result_id());
  88. });
  89. // At this point, |relevant_pointers| contains all the pointers we might
  90. // think of storing to.
  91. if (relevant_pointers.empty()) {
  92. return;
  93. }
  94. auto pointer = relevant_pointers[GetFuzzerContext()->RandomIndex(
  95. relevant_pointers)];
  96. std::vector<opt::Instruction*> relevant_values =
  97. FindAvailableInstructions(
  98. function, block, inst_it,
  99. [pointer](opt::IRContext* context,
  100. opt::Instruction* instruction) -> bool {
  101. if (!instruction->result_id() || !instruction->type_id()) {
  102. return false;
  103. }
  104. return instruction->type_id() ==
  105. context->get_def_use_mgr()
  106. ->GetDef(pointer->type_id())
  107. ->GetSingleWordInOperand(1);
  108. });
  109. if (relevant_values.empty()) {
  110. return;
  111. }
  112. bool is_atomic_store = false;
  113. uint32_t memory_scope_id = 0;
  114. uint32_t memory_semantics_id = 0;
  115. auto storage_class =
  116. static_cast<spv::StorageClass>(GetIRContext()
  117. ->get_def_use_mgr()
  118. ->GetDef(pointer->type_id())
  119. ->GetSingleWordInOperand(0));
  120. switch (storage_class) {
  121. case spv::StorageClass::StorageBuffer:
  122. case spv::StorageClass::PhysicalStorageBuffer:
  123. case spv::StorageClass::Workgroup:
  124. case spv::StorageClass::CrossWorkgroup:
  125. case spv::StorageClass::AtomicCounter:
  126. case spv::StorageClass::Image:
  127. if (GetFuzzerContext()->ChoosePercentage(
  128. GetFuzzerContext()->GetChanceOfAddingAtomicStore())) {
  129. is_atomic_store = true;
  130. memory_scope_id = FindOrCreateConstant(
  131. {uint32_t(spv::Scope::Invocation)},
  132. FindOrCreateIntegerType(32, GetFuzzerContext()->ChooseEven()),
  133. false);
  134. memory_semantics_id = FindOrCreateConstant(
  135. {static_cast<uint32_t>(
  136. fuzzerutil::GetMemorySemanticsForStorageClass(
  137. storage_class))},
  138. FindOrCreateIntegerType(32, GetFuzzerContext()->ChooseEven()),
  139. false);
  140. }
  141. break;
  142. default:
  143. break;
  144. }
  145. // Create and apply the transformation.
  146. ApplyTransformation(TransformationStore(
  147. pointer->result_id(), is_atomic_store, memory_scope_id,
  148. memory_semantics_id,
  149. relevant_values[GetFuzzerContext()->RandomIndex(relevant_values)]
  150. ->result_id(),
  151. instruction_descriptor));
  152. });
  153. }
  154. } // namespace fuzz
  155. } // namespace spvtools