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
15 #include "gtest/gtest.h"
16 #include "source/fuzz/fuzzer_pass_add_opphi_synonyms.h"
17 #include "source/fuzz/fuzzer_util.h"
18 #include "source/fuzz/pseudo_random_generator.h"
19 #include "test/fuzz/fuzz_test_util.h"
20
21 namespace spvtools {
22 namespace fuzz {
23 namespace {
24
25 class FuzzerPassMock : public FuzzerPass {
26 public:
FuzzerPassMock(opt::IRContext * ir_context,TransformationContext * transformation_context,FuzzerContext * fuzzer_context,protobufs::TransformationSequence * transformations)27 FuzzerPassMock(opt::IRContext* ir_context,
28 TransformationContext* transformation_context,
29 FuzzerContext* fuzzer_context,
30 protobufs::TransformationSequence* transformations)
31 : FuzzerPass(ir_context, transformation_context, fuzzer_context,
32 transformations, false) {}
33
34 ~FuzzerPassMock() override = default;
35
GetReachedInstructions() const36 const std::unordered_set<uint32_t>& GetReachedInstructions() const {
37 return reached_ids_;
38 }
39
Apply()40 void Apply() override {
41 ForEachInstructionWithInstructionDescriptor(
42 [this](opt::Function* /*unused*/, opt::BasicBlock* /*unused*/,
43 opt::BasicBlock::iterator inst_it,
44 const protobufs::InstructionDescriptor& /*unused*/) {
45 if (inst_it->result_id()) {
46 reached_ids_.insert(inst_it->result_id());
47 }
48 });
49 }
50
51 private:
52 std::unordered_set<uint32_t> reached_ids_;
53 };
54
TEST(FuzzerPassTest,ForEachInstructionWithInstructionDescriptor)55 TEST(FuzzerPassTest, ForEachInstructionWithInstructionDescriptor) {
56 std::string shader = R"(
57 OpCapability Shader
58 %1 = OpExtInstImport "GLSL.std.450"
59 OpMemoryModel Logical GLSL450
60 OpEntryPoint Fragment %4 "main"
61 OpExecutionMode %4 OriginUpperLeft
62 OpSource ESSL 310
63 %2 = OpTypeVoid
64 %3 = OpTypeFunction %2
65 %6 = OpTypeFloat 32
66 %4 = OpFunction %2 None %3
67 %5 = OpLabel
68 %7 = OpUndef %6
69 OpReturn
70 %8 = OpLabel
71 %9 = OpUndef %6
72 OpReturn
73 OpFunctionEnd
74 )";
75
76 const auto env = SPV_ENV_UNIVERSAL_1_3;
77 const auto consumer = nullptr;
78 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
79 spvtools::ValidatorOptions validator_options;
80 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
81 kConsoleMessageConsumer));
82 TransformationContext transformation_context(
83 MakeUnique<FactManager>(context.get()), validator_options);
84 // Check that %5 is reachable and %8 is unreachable as expected.
85 const auto* dominator_analysis =
86 context->GetDominatorAnalysis(context->GetFunction(4));
87 ASSERT_TRUE(dominator_analysis->IsReachable(5));
88 ASSERT_FALSE(dominator_analysis->IsReachable(8));
89
90 FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0), 100,
91 false);
92 protobufs::TransformationSequence transformations;
93 FuzzerPassMock fuzzer_pass_mock(context.get(), &transformation_context,
94 &fuzzer_context, &transformations);
95 fuzzer_pass_mock.Apply();
96
97 ASSERT_TRUE(fuzzer_pass_mock.GetReachedInstructions().count(7));
98 ASSERT_FALSE(fuzzer_pass_mock.GetReachedInstructions().count(9));
99 }
100
101 } // namespace
102 } // namespace fuzz
103 } // namespace spvtools
104