// Copyright (c) 2020 Vasyl Teliman // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "source/fuzz/fuzzer_pass_add_composite_extract.h" #include "source/fuzz/available_instructions.h" #include "source/fuzz/fuzzer_context.h" #include "source/fuzz/fuzzer_util.h" #include "source/fuzz/instruction_descriptor.h" #include "source/fuzz/transformation_composite_extract.h" namespace spvtools { namespace fuzz { FuzzerPassAddCompositeExtract::FuzzerPassAddCompositeExtract( opt::IRContext* ir_context, TransformationContext* transformation_context, FuzzerContext* fuzzer_context, protobufs::TransformationSequence* transformations) : FuzzerPass(ir_context, transformation_context, fuzzer_context, transformations) {} void FuzzerPassAddCompositeExtract::Apply() { std::vector composite_synonyms; for (const auto* dd : GetTransformationContext()->GetFactManager()->GetAllSynonyms()) { // |dd| must describe a component of a composite. if (!dd->index().empty()) { composite_synonyms.push_back(dd); } } AvailableInstructions available_composites( GetIRContext(), [](opt::IRContext* ir_context, opt::Instruction* inst) { return inst->type_id() && inst->result_id() && fuzzerutil::IsCompositeType( ir_context->get_type_mgr()->GetType(inst->type_id())); }); ForEachInstructionWithInstructionDescriptor( [this, &available_composites, &composite_synonyms]( opt::Function* /*unused*/, opt::BasicBlock* /*unused*/, opt::BasicBlock::iterator inst_it, const protobufs::InstructionDescriptor& instruction_descriptor) { if (!fuzzerutil::CanInsertOpcodeBeforeInstruction(SpvOpCompositeExtract, inst_it)) { return; } if (!GetFuzzerContext()->ChoosePercentage( GetFuzzerContext()->GetChanceOfAddingCompositeExtract())) { return; } std::vector available_synonyms; for (const auto* dd : composite_synonyms) { if (fuzzerutil::IdIsAvailableBeforeInstruction( GetIRContext(), &*inst_it, dd->object())) { available_synonyms.push_back(dd); } } auto candidate_composites = available_composites.GetAvailableBeforeInstruction(&*inst_it); if (available_synonyms.empty() && candidate_composites.empty()) { return; } uint32_t composite_id = 0; std::vector indices; if (available_synonyms.empty() || (!candidate_composites.empty() && GetFuzzerContext()->ChooseEven())) { const auto* inst = candidate_composites[GetFuzzerContext()->RandomIndex( candidate_composites)]; composite_id = inst->result_id(); auto type_id = inst->type_id(); do { uint32_t number_of_members = 0; const auto* type_inst = GetIRContext()->get_def_use_mgr()->GetDef(type_id); assert(type_inst && "Composite instruction has invalid type id"); switch (type_inst->opcode()) { case SpvOpTypeArray: number_of_members = fuzzerutil::GetArraySize(*type_inst, GetIRContext()); break; case SpvOpTypeVector: case SpvOpTypeMatrix: number_of_members = type_inst->GetSingleWordInOperand(1); break; case SpvOpTypeStruct: number_of_members = type_inst->NumInOperands(); break; default: assert(false && "|type_inst| is not a composite"); return; } if (number_of_members == 0) { return; } indices.push_back( GetFuzzerContext()->GetRandomCompositeExtractIndex( number_of_members)); switch (type_inst->opcode()) { case SpvOpTypeArray: case SpvOpTypeVector: case SpvOpTypeMatrix: type_id = type_inst->GetSingleWordInOperand(0); break; case SpvOpTypeStruct: type_id = type_inst->GetSingleWordInOperand(indices.back()); break; default: assert(false && "|type_inst| is not a composite"); return; } } while (fuzzerutil::IsCompositeType( GetIRContext()->get_type_mgr()->GetType(type_id)) && GetFuzzerContext()->ChoosePercentage( GetFuzzerContext() ->GetChanceOfGoingDeeperToExtractComposite())); } else { const auto* dd = available_synonyms[GetFuzzerContext()->RandomIndex( available_synonyms)]; composite_id = dd->object(); indices.assign(dd->index().begin(), dd->index().end()); } assert(composite_id != 0 && !indices.empty() && "Composite object should have been chosen correctly"); ApplyTransformation(TransformationCompositeExtract( instruction_descriptor, GetFuzzerContext()->GetFreshId(), composite_id, indices)); }); } } // namespace fuzz } // namespace spvtools