transformation_store.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  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/transformation_store.h"
  15. #include "source/fuzz/fuzzer_util.h"
  16. #include "source/fuzz/instruction_descriptor.h"
  17. namespace spvtools {
  18. namespace fuzz {
  19. TransformationStore::TransformationStore(
  20. const spvtools::fuzz::protobufs::TransformationStore& message)
  21. : message_(message) {}
  22. TransformationStore::TransformationStore(
  23. uint32_t pointer_id, uint32_t value_id,
  24. const protobufs::InstructionDescriptor& instruction_to_insert_before) {
  25. message_.set_pointer_id(pointer_id);
  26. message_.set_value_id(value_id);
  27. *message_.mutable_instruction_to_insert_before() =
  28. instruction_to_insert_before;
  29. }
  30. bool TransformationStore::IsApplicable(
  31. opt::IRContext* ir_context,
  32. const TransformationContext& transformation_context) const {
  33. // The pointer must exist and have a type.
  34. auto pointer = ir_context->get_def_use_mgr()->GetDef(message_.pointer_id());
  35. if (!pointer || !pointer->type_id()) {
  36. return false;
  37. }
  38. // The pointer type must indeed be a pointer.
  39. auto pointer_type = ir_context->get_def_use_mgr()->GetDef(pointer->type_id());
  40. assert(pointer_type && "Type id must be defined.");
  41. if (pointer_type->opcode() != SpvOpTypePointer) {
  42. return false;
  43. }
  44. // The pointer must not be read only.
  45. if (pointer->IsReadOnlyPointer()) {
  46. return false;
  47. }
  48. // We do not want to allow storing to null or undefined pointers.
  49. switch (pointer->opcode()) {
  50. case SpvOpConstantNull:
  51. case SpvOpUndef:
  52. return false;
  53. default:
  54. break;
  55. }
  56. // Determine which instruction we should be inserting before.
  57. auto insert_before =
  58. FindInstruction(message_.instruction_to_insert_before(), ir_context);
  59. // It must exist, ...
  60. if (!insert_before) {
  61. return false;
  62. }
  63. // ... and it must be legitimate to insert a store before it.
  64. if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpStore,
  65. insert_before)) {
  66. return false;
  67. }
  68. // The block we are inserting into needs to be dead, or else the pointee type
  69. // of the pointer we are storing to needs to be irrelevant (otherwise the
  70. // store could impact on the observable behaviour of the module).
  71. if (!transformation_context.GetFactManager()->BlockIsDead(
  72. ir_context->get_instr_block(insert_before)->id()) &&
  73. !transformation_context.GetFactManager()->PointeeValueIsIrrelevant(
  74. message_.pointer_id())) {
  75. return false;
  76. }
  77. // The value being stored needs to exist and have a type.
  78. auto value = ir_context->get_def_use_mgr()->GetDef(message_.value_id());
  79. if (!value || !value->type_id()) {
  80. return false;
  81. }
  82. // The type of the value must match the pointee type.
  83. if (pointer_type->GetSingleWordInOperand(1) != value->type_id()) {
  84. return false;
  85. }
  86. // The pointer needs to be available at the insertion point.
  87. if (!fuzzerutil::IdIsAvailableBeforeInstruction(ir_context, insert_before,
  88. message_.pointer_id())) {
  89. return false;
  90. }
  91. // The value needs to be available at the insertion point.
  92. return fuzzerutil::IdIsAvailableBeforeInstruction(ir_context, insert_before,
  93. message_.value_id());
  94. }
  95. void TransformationStore::Apply(opt::IRContext* ir_context,
  96. TransformationContext* /*unused*/) const {
  97. FindInstruction(message_.instruction_to_insert_before(), ir_context)
  98. ->InsertBefore(MakeUnique<opt::Instruction>(
  99. ir_context, SpvOpStore, 0, 0,
  100. opt::Instruction::OperandList(
  101. {{SPV_OPERAND_TYPE_ID, {message_.pointer_id()}},
  102. {SPV_OPERAND_TYPE_ID, {message_.value_id()}}})));
  103. ir_context->InvalidateAnalysesExceptFor(opt::IRContext::kAnalysisNone);
  104. }
  105. protobufs::Transformation TransformationStore::ToMessage() const {
  106. protobufs::Transformation result;
  107. *result.mutable_store() = message_;
  108. return result;
  109. }
  110. } // namespace fuzz
  111. } // namespace spvtools