• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
15 #include "source/fuzz/fuzzer_pass_add_stores.h"
16 
17 #include "source/fuzz/fuzzer_util.h"
18 #include "source/fuzz/transformation_store.h"
19 
20 namespace spvtools {
21 namespace fuzz {
22 
FuzzerPassAddStores(opt::IRContext * ir_context,TransformationContext * transformation_context,FuzzerContext * fuzzer_context,protobufs::TransformationSequence * transformations)23 FuzzerPassAddStores::FuzzerPassAddStores(
24     opt::IRContext* ir_context, TransformationContext* transformation_context,
25     FuzzerContext* fuzzer_context,
26     protobufs::TransformationSequence* transformations)
27     : FuzzerPass(ir_context, transformation_context, fuzzer_context,
28                  transformations) {}
29 
Apply()30 void FuzzerPassAddStores::Apply() {
31   ForEachInstructionWithInstructionDescriptor(
32       [this](opt::Function* function, opt::BasicBlock* block,
33              opt::BasicBlock::iterator inst_it,
34              const protobufs::InstructionDescriptor& instruction_descriptor)
35           -> void {
36         assert(inst_it->opcode() ==
37                    instruction_descriptor.target_instruction_opcode() &&
38                "The opcode of the instruction we might insert before must be "
39                "the same as the opcode in the descriptor for the instruction");
40 
41         // Check whether it is legitimate to insert a store before this
42         // instruction.
43         if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpStore,
44                                                           inst_it)) {
45           return;
46         }
47 
48         // Randomly decide whether to try inserting a store here.
49         if (!GetFuzzerContext()->ChoosePercentage(
50                 GetFuzzerContext()->GetChanceOfAddingStore())) {
51           return;
52         }
53 
54         // Look for pointers we might consider storing to.
55         std::vector<opt::Instruction*> relevant_pointers =
56             FindAvailableInstructions(
57                 function, block, inst_it,
58                 [this, block](opt::IRContext* context,
59                               opt::Instruction* instruction) -> bool {
60                   if (!instruction->result_id() || !instruction->type_id()) {
61                     return false;
62                   }
63                   auto type_inst = context->get_def_use_mgr()->GetDef(
64                       instruction->type_id());
65                   if (type_inst->opcode() != SpvOpTypePointer) {
66                     // Not a pointer.
67                     return false;
68                   }
69                   if (instruction->IsReadOnlyPointer()) {
70                     // Read only: cannot store to it.
71                     return false;
72                   }
73                   switch (instruction->opcode()) {
74                     case SpvOpConstantNull:
75                     case SpvOpUndef:
76                       // Do not allow storing to a null or undefined pointer;
77                       // this might be OK if the block is dead, but for now we
78                       // conservatively avoid it.
79                       return false;
80                     default:
81                       break;
82                   }
83                   return GetTransformationContext()
84                              ->GetFactManager()
85                              ->BlockIsDead(block->id()) ||
86                          GetTransformationContext()
87                              ->GetFactManager()
88                              ->PointeeValueIsIrrelevant(
89                                  instruction->result_id());
90                 });
91 
92         // At this point, |relevant_pointers| contains all the pointers we might
93         // think of storing to.
94         if (relevant_pointers.empty()) {
95           return;
96         }
97 
98         auto pointer = relevant_pointers[GetFuzzerContext()->RandomIndex(
99             relevant_pointers)];
100 
101         std::vector<opt::Instruction*> relevant_values =
102             FindAvailableInstructions(
103                 function, block, inst_it,
104                 [pointer](opt::IRContext* context,
105                           opt::Instruction* instruction) -> bool {
106                   if (!instruction->result_id() || !instruction->type_id()) {
107                     return false;
108                   }
109                   return instruction->type_id() ==
110                          context->get_def_use_mgr()
111                              ->GetDef(pointer->type_id())
112                              ->GetSingleWordInOperand(1);
113                 });
114 
115         if (relevant_values.empty()) {
116           return;
117         }
118 
119         // Choose a value at random, and create and apply a storing
120         // transformation based on it and the pointer.
121         ApplyTransformation(TransformationStore(
122             pointer->result_id(),
123             relevant_values[GetFuzzerContext()->RandomIndex(relevant_values)]
124                 ->result_id(),
125             instruction_descriptor));
126       });
127 }
128 
129 }  // namespace fuzz
130 }  // namespace spvtools
131