1 // Copyright (c) 2019 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/transformation_load.h"
16
17 #include "gtest/gtest.h"
18 #include "source/fuzz/fuzzer_util.h"
19 #include "source/fuzz/instruction_descriptor.h"
20 #include "test/fuzz/fuzz_test_util.h"
21
22 namespace spvtools {
23 namespace fuzz {
24 namespace {
25
TEST(TransformationLoadTest,BasicTest)26 TEST(TransformationLoadTest, BasicTest) {
27 std::string shader = R"(
28 OpCapability Shader
29 %1 = OpExtInstImport "GLSL.std.450"
30 OpMemoryModel Logical GLSL450
31 OpEntryPoint Fragment %4 "main"
32 OpExecutionMode %4 OriginUpperLeft
33 OpSource ESSL 310
34 %2 = OpTypeVoid
35 %3 = OpTypeFunction %2
36 %6 = OpTypeInt 32 1
37 %7 = OpTypeFloat 32
38 %8 = OpTypeStruct %6 %7
39 %9 = OpTypePointer Function %8
40 %10 = OpTypeFunction %6 %9
41 %14 = OpConstant %6 0
42 %15 = OpTypePointer Function %6
43 %51 = OpTypePointer Private %6
44 %21 = OpConstant %6 2
45 %23 = OpConstant %6 1
46 %24 = OpConstant %7 1
47 %25 = OpTypePointer Function %7
48 %50 = OpTypePointer Private %7
49 %34 = OpTypeBool
50 %35 = OpConstantFalse %34
51 %60 = OpConstantNull %50
52 %61 = OpUndef %51
53 %52 = OpVariable %50 Private
54 %53 = OpVariable %51 Private
55 %4 = OpFunction %2 None %3
56 %5 = OpLabel
57 %20 = OpVariable %9 Function
58 %27 = OpVariable %9 Function ; irrelevant
59 %22 = OpAccessChain %15 %20 %14
60 %44 = OpCopyObject %9 %20
61 %26 = OpAccessChain %25 %20 %23
62 %29 = OpFunctionCall %6 %12 %27
63 %30 = OpAccessChain %15 %20 %14
64 %45 = OpCopyObject %15 %30
65 %33 = OpAccessChain %15 %20 %14
66 OpSelectionMerge %37 None
67 OpBranchConditional %35 %36 %37
68 %36 = OpLabel
69 %38 = OpAccessChain %15 %20 %14
70 %40 = OpAccessChain %15 %20 %14
71 %43 = OpAccessChain %15 %20 %14
72 OpBranch %37
73 %37 = OpLabel
74 OpReturn
75 OpFunctionEnd
76 %12 = OpFunction %6 None %10
77 %11 = OpFunctionParameter %9 ; irrelevant
78 %13 = OpLabel
79 %46 = OpCopyObject %9 %11 ; irrelevant
80 %16 = OpAccessChain %15 %11 %14 ; irrelevant
81 OpReturnValue %21
82 OpFunctionEnd
83 )";
84
85 const auto env = SPV_ENV_UNIVERSAL_1_4;
86 const auto consumer = nullptr;
87 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
88 spvtools::ValidatorOptions validator_options;
89 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
90 kConsoleMessageConsumer));
91 TransformationContext transformation_context(
92 MakeUnique<FactManager>(context.get()), validator_options);
93 transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
94 27);
95 transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
96 11);
97 transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
98 46);
99 transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
100 16);
101 transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
102 52);
103
104 transformation_context.GetFactManager()->AddFactBlockIsDead(36);
105
106 // Variables with pointee types:
107 // 52 - ptr_to(7)
108 // 53 - ptr_to(6)
109 // 20 - ptr_to(8)
110 // 27 - ptr_to(8) - irrelevant
111
112 // Access chains with pointee type:
113 // 22 - ptr_to(6)
114 // 26 - ptr_to(6)
115 // 30 - ptr_to(6)
116 // 33 - ptr_to(6)
117 // 38 - ptr_to(6)
118 // 40 - ptr_to(6)
119 // 43 - ptr_to(6)
120 // 16 - ptr_to(6) - irrelevant
121
122 // Copied object with pointee type:
123 // 44 - ptr_to(8)
124 // 45 - ptr_to(6)
125 // 46 - ptr_to(8) - irrelevant
126
127 // Function parameters with pointee type:
128 // 11 - ptr_to(8) - irrelevant
129
130 // Pointers that cannot be used:
131 // 60 - null
132 // 61 - undefined
133
134 // Bad: id is not fresh
135 ASSERT_FALSE(TransformationLoad(
136 33, 33, MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
137 .IsApplicable(context.get(), transformation_context));
138 // Bad: attempt to load from 11 from outside its function
139 ASSERT_FALSE(TransformationLoad(
140 100, 11, MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
141 .IsApplicable(context.get(), transformation_context));
142
143 // Bad: pointer is not available
144 ASSERT_FALSE(TransformationLoad(
145 100, 33, MakeInstructionDescriptor(45, SpvOpCopyObject, 0))
146 .IsApplicable(context.get(), transformation_context));
147
148 // Bad: attempt to insert before OpVariable
149 ASSERT_FALSE(TransformationLoad(
150 100, 27, MakeInstructionDescriptor(27, SpvOpVariable, 0))
151 .IsApplicable(context.get(), transformation_context));
152
153 // Bad: pointer id does not exist
154 ASSERT_FALSE(
155 TransformationLoad(100, 1000,
156 MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
157 .IsApplicable(context.get(), transformation_context));
158
159 // Bad: pointer id exists but does not have a type
160 ASSERT_FALSE(TransformationLoad(
161 100, 5, MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
162 .IsApplicable(context.get(), transformation_context));
163
164 // Bad: pointer id exists and has a type, but is not a pointer
165 ASSERT_FALSE(TransformationLoad(
166 100, 24, MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
167 .IsApplicable(context.get(), transformation_context));
168
169 // Bad: attempt to load from null pointer
170 ASSERT_FALSE(TransformationLoad(
171 100, 60, MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
172 .IsApplicable(context.get(), transformation_context));
173
174 // Bad: attempt to load from undefined pointer
175 ASSERT_FALSE(TransformationLoad(
176 100, 61, MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
177 .IsApplicable(context.get(), transformation_context));
178 // Bad: %40 is not available at the program point
179 ASSERT_FALSE(
180 TransformationLoad(100, 40, MakeInstructionDescriptor(37, SpvOpReturn, 0))
181 .IsApplicable(context.get(), transformation_context));
182
183 // Bad: The described instruction does not exist
184 ASSERT_FALSE(TransformationLoad(
185 100, 33, MakeInstructionDescriptor(1000, SpvOpReturn, 0))
186 .IsApplicable(context.get(), transformation_context));
187
188 {
189 TransformationLoad transformation(
190 100, 33, MakeInstructionDescriptor(38, SpvOpAccessChain, 0));
191 ASSERT_TRUE(
192 transformation.IsApplicable(context.get(), transformation_context));
193 ApplyAndCheckFreshIds(transformation, context.get(),
194 &transformation_context);
195 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
196 context.get(), validator_options, kConsoleMessageConsumer));
197 }
198
199 {
200 TransformationLoad transformation(
201 101, 46, MakeInstructionDescriptor(16, SpvOpReturnValue, 0));
202 ASSERT_TRUE(
203 transformation.IsApplicable(context.get(), transformation_context));
204 ApplyAndCheckFreshIds(transformation, context.get(),
205 &transformation_context);
206 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
207 context.get(), validator_options, kConsoleMessageConsumer));
208 }
209
210 {
211 TransformationLoad transformation(
212 102, 16, MakeInstructionDescriptor(16, SpvOpReturnValue, 0));
213 ASSERT_TRUE(
214 transformation.IsApplicable(context.get(), transformation_context));
215 ApplyAndCheckFreshIds(transformation, context.get(),
216 &transformation_context);
217 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
218 context.get(), validator_options, kConsoleMessageConsumer));
219 }
220
221 {
222 TransformationLoad transformation(
223 103, 40, MakeInstructionDescriptor(43, SpvOpAccessChain, 0));
224 ASSERT_TRUE(
225 transformation.IsApplicable(context.get(), transformation_context));
226 ApplyAndCheckFreshIds(transformation, context.get(),
227 &transformation_context);
228 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
229 context.get(), validator_options, kConsoleMessageConsumer));
230 }
231
232 std::string after_transformation = R"(
233 OpCapability Shader
234 %1 = OpExtInstImport "GLSL.std.450"
235 OpMemoryModel Logical GLSL450
236 OpEntryPoint Fragment %4 "main"
237 OpExecutionMode %4 OriginUpperLeft
238 OpSource ESSL 310
239 %2 = OpTypeVoid
240 %3 = OpTypeFunction %2
241 %6 = OpTypeInt 32 1
242 %7 = OpTypeFloat 32
243 %8 = OpTypeStruct %6 %7
244 %9 = OpTypePointer Function %8
245 %10 = OpTypeFunction %6 %9
246 %14 = OpConstant %6 0
247 %15 = OpTypePointer Function %6
248 %51 = OpTypePointer Private %6
249 %21 = OpConstant %6 2
250 %23 = OpConstant %6 1
251 %24 = OpConstant %7 1
252 %25 = OpTypePointer Function %7
253 %50 = OpTypePointer Private %7
254 %34 = OpTypeBool
255 %35 = OpConstantFalse %34
256 %60 = OpConstantNull %50
257 %61 = OpUndef %51
258 %52 = OpVariable %50 Private
259 %53 = OpVariable %51 Private
260 %4 = OpFunction %2 None %3
261 %5 = OpLabel
262 %20 = OpVariable %9 Function
263 %27 = OpVariable %9 Function ; irrelevant
264 %22 = OpAccessChain %15 %20 %14
265 %44 = OpCopyObject %9 %20
266 %26 = OpAccessChain %25 %20 %23
267 %29 = OpFunctionCall %6 %12 %27
268 %30 = OpAccessChain %15 %20 %14
269 %45 = OpCopyObject %15 %30
270 %33 = OpAccessChain %15 %20 %14
271 OpSelectionMerge %37 None
272 OpBranchConditional %35 %36 %37
273 %36 = OpLabel
274 %100 = OpLoad %6 %33
275 %38 = OpAccessChain %15 %20 %14
276 %40 = OpAccessChain %15 %20 %14
277 %103 = OpLoad %6 %40
278 %43 = OpAccessChain %15 %20 %14
279 OpBranch %37
280 %37 = OpLabel
281 OpReturn
282 OpFunctionEnd
283 %12 = OpFunction %6 None %10
284 %11 = OpFunctionParameter %9 ; irrelevant
285 %13 = OpLabel
286 %46 = OpCopyObject %9 %11 ; irrelevant
287 %16 = OpAccessChain %15 %11 %14 ; irrelevant
288 %101 = OpLoad %8 %46
289 %102 = OpLoad %6 %16
290 OpReturnValue %21
291 OpFunctionEnd
292 )";
293 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
294 }
295
296 } // namespace
297 } // namespace fuzz
298 } // namespace spvtools
299