fuzzer_pass_add_composite_extract.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. // Copyright (c) 2020 Vasyl Teliman
  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_composite_extract.h"
  15. #include "source/fuzz/available_instructions.h"
  16. #include "source/fuzz/fuzzer_context.h"
  17. #include "source/fuzz/fuzzer_util.h"
  18. #include "source/fuzz/instruction_descriptor.h"
  19. #include "source/fuzz/transformation_composite_extract.h"
  20. namespace spvtools {
  21. namespace fuzz {
  22. FuzzerPassAddCompositeExtract::FuzzerPassAddCompositeExtract(
  23. opt::IRContext* ir_context, TransformationContext* transformation_context,
  24. FuzzerContext* fuzzer_context,
  25. protobufs::TransformationSequence* transformations,
  26. bool ignore_inapplicable_transformations)
  27. : FuzzerPass(ir_context, transformation_context, fuzzer_context,
  28. transformations, ignore_inapplicable_transformations) {}
  29. void FuzzerPassAddCompositeExtract::Apply() {
  30. std::vector<const protobufs::DataDescriptor*> composite_synonyms;
  31. for (const auto* dd :
  32. GetTransformationContext()->GetFactManager()->GetAllSynonyms()) {
  33. // |dd| must describe a component of a composite.
  34. if (!dd->index().empty()) {
  35. composite_synonyms.push_back(dd);
  36. }
  37. }
  38. AvailableInstructions available_composites(
  39. GetIRContext(), [](opt::IRContext* ir_context, opt::Instruction* inst) {
  40. return inst->type_id() && inst->result_id() &&
  41. fuzzerutil::IsCompositeType(
  42. ir_context->get_type_mgr()->GetType(inst->type_id()));
  43. });
  44. ForEachInstructionWithInstructionDescriptor(
  45. [this, &available_composites, &composite_synonyms](
  46. opt::Function* /*unused*/, opt::BasicBlock* /*unused*/,
  47. opt::BasicBlock::iterator inst_it,
  48. const protobufs::InstructionDescriptor& instruction_descriptor) {
  49. if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(
  50. spv::Op::OpCompositeExtract, inst_it)) {
  51. return;
  52. }
  53. if (!GetFuzzerContext()->ChoosePercentage(
  54. GetFuzzerContext()->GetChanceOfAddingCompositeExtract())) {
  55. return;
  56. }
  57. std::vector<const protobufs::DataDescriptor*> available_synonyms;
  58. for (const auto* dd : composite_synonyms) {
  59. if (fuzzerutil::IdIsAvailableBeforeInstruction(
  60. GetIRContext(), &*inst_it, dd->object())) {
  61. available_synonyms.push_back(dd);
  62. }
  63. }
  64. auto candidate_composites =
  65. available_composites.GetAvailableBeforeInstruction(&*inst_it);
  66. if (available_synonyms.empty() && candidate_composites.empty()) {
  67. return;
  68. }
  69. uint32_t composite_id = 0;
  70. std::vector<uint32_t> indices;
  71. if (available_synonyms.empty() || (!candidate_composites.empty() &&
  72. GetFuzzerContext()->ChooseEven())) {
  73. const auto* inst =
  74. candidate_composites[GetFuzzerContext()->RandomIndex(
  75. candidate_composites)];
  76. composite_id = inst->result_id();
  77. auto type_id = inst->type_id();
  78. do {
  79. uint32_t number_of_members = 0;
  80. const auto* type_inst =
  81. GetIRContext()->get_def_use_mgr()->GetDef(type_id);
  82. assert(type_inst && "Composite instruction has invalid type id");
  83. switch (type_inst->opcode()) {
  84. case spv::Op::OpTypeArray:
  85. number_of_members =
  86. fuzzerutil::GetArraySize(*type_inst, GetIRContext());
  87. break;
  88. case spv::Op::OpTypeVector:
  89. case spv::Op::OpTypeMatrix:
  90. number_of_members = type_inst->GetSingleWordInOperand(1);
  91. break;
  92. case spv::Op::OpTypeStruct:
  93. number_of_members = type_inst->NumInOperands();
  94. break;
  95. default:
  96. assert(false && "|type_inst| is not a composite");
  97. return;
  98. }
  99. if (number_of_members == 0) {
  100. return;
  101. }
  102. indices.push_back(
  103. GetFuzzerContext()->GetRandomCompositeExtractIndex(
  104. number_of_members));
  105. switch (type_inst->opcode()) {
  106. case spv::Op::OpTypeArray:
  107. case spv::Op::OpTypeVector:
  108. case spv::Op::OpTypeMatrix:
  109. type_id = type_inst->GetSingleWordInOperand(0);
  110. break;
  111. case spv::Op::OpTypeStruct:
  112. type_id = type_inst->GetSingleWordInOperand(indices.back());
  113. break;
  114. default:
  115. assert(false && "|type_inst| is not a composite");
  116. return;
  117. }
  118. } while (fuzzerutil::IsCompositeType(
  119. GetIRContext()->get_type_mgr()->GetType(type_id)) &&
  120. GetFuzzerContext()->ChoosePercentage(
  121. GetFuzzerContext()
  122. ->GetChanceOfGoingDeeperToExtractComposite()));
  123. } else {
  124. const auto* dd = available_synonyms[GetFuzzerContext()->RandomIndex(
  125. available_synonyms)];
  126. composite_id = dd->object();
  127. indices.assign(dd->index().begin(), dd->index().end());
  128. }
  129. assert(composite_id != 0 && !indices.empty() &&
  130. "Composite object should have been chosen correctly");
  131. ApplyTransformation(TransformationCompositeExtract(
  132. instruction_descriptor, GetFuzzerContext()->GetFreshId(),
  133. composite_id, indices));
  134. });
  135. }
  136. } // namespace fuzz
  137. } // namespace spvtools