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 "source/fuzz/transformation_add_copy_memory.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(TransformationAddCopyMemoryTest,BasicTest)26 TEST(TransformationAddCopyMemoryTest, 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 OpDecorate %19 RelaxedPrecision
35 OpMemberDecorate %66 0 RelaxedPrecision
36 OpDecorate %69 RelaxedPrecision
37 %2 = OpTypeVoid
38 %3 = OpTypeFunction %2
39 %6 = OpTypeBool
40 %7 = OpTypePointer Function %6
41 %78 = OpTypePointer Private %6
42 %8 = OpTypeFunction %6 %7
43 %17 = OpTypeInt 32 1
44 %18 = OpTypePointer Function %17
45 %79 = OpTypePointer Private %17
46 %20 = OpConstant %17 0
47 %21 = OpTypeFloat 32
48 %22 = OpTypePointer Function %21
49 %80 = OpTypePointer Private %21
50 %24 = OpConstant %21 0
51 %25 = OpConstantFalse %6
52 %32 = OpConstantTrue %6
53 %33 = OpTypeVector %21 4
54 %34 = OpTypePointer Function %33
55 %81 = OpTypePointer Private %33
56 %36 = OpConstantComposite %33 %24 %24 %24 %24
57 %37 = OpTypeMatrix %33 4
58 %84 = OpConstantComposite %37 %36 %36 %36 %36
59 %38 = OpTypePointer Function %37
60 %82 = OpTypePointer Private %37
61 %44 = OpConstant %21 1
62 %66 = OpTypeStruct %17 %21 %6 %33 %37
63 %85 = OpConstantComposite %66 %20 %24 %25 %36 %84
64 %67 = OpTypePointer Function %66
65 %83 = OpTypePointer Private %66
66 %86 = OpVariable %79 Private %20
67 %87 = OpUndef %79
68 %88 = OpConstantNull %79
69 %4 = OpFunction %2 None %3
70 %5 = OpLabel
71 %19 = OpVariable %18 Function
72 %23 = OpVariable %22 Function
73 %26 = OpVariable %7 Function
74 %30 = OpVariable %7 Function
75 %35 = OpVariable %34 Function
76 %39 = OpVariable %38 Function
77 %68 = OpVariable %67 Function
78 OpStore %19 %20
79 OpStore %23 %24
80 OpStore %26 %25
81 %27 = OpFunctionCall %6 %10 %26
82 OpSelectionMerge %29 None
83 OpBranchConditional %27 %28 %31
84 %28 = OpLabel
85 %89 = OpCopyObject %18 %19
86 OpBranch %29
87 %31 = OpLabel
88 OpBranch %29
89 %76 = OpLabel
90 %77 = OpLogicalEqual %6 %25 %32
91 OpBranch %29
92 %29 = OpLabel
93 %75 = OpPhi %6 %25 %31 %32 %28 %77 %76
94 OpStore %30 %75
95 %40 = OpLoad %33 %35
96 %41 = OpLoad %33 %35
97 %42 = OpLoad %33 %35
98 %43 = OpLoad %33 %35
99 %45 = OpCompositeExtract %21 %40 0
100 %46 = OpCompositeExtract %21 %40 1
101 %47 = OpCompositeExtract %21 %40 2
102 %48 = OpCompositeExtract %21 %40 3
103 %49 = OpCompositeExtract %21 %41 0
104 %50 = OpCompositeExtract %21 %41 1
105 %51 = OpCompositeExtract %21 %41 2
106 %52 = OpCompositeExtract %21 %41 3
107 %53 = OpCompositeExtract %21 %42 0
108 %54 = OpCompositeExtract %21 %42 1
109 %55 = OpCompositeExtract %21 %42 2
110 %56 = OpCompositeExtract %21 %42 3
111 %57 = OpCompositeExtract %21 %43 0
112 %58 = OpCompositeExtract %21 %43 1
113 %59 = OpCompositeExtract %21 %43 2
114 %60 = OpCompositeExtract %21 %43 3
115 %61 = OpCompositeConstruct %33 %45 %46 %47 %48
116 %62 = OpCompositeConstruct %33 %49 %50 %51 %52
117 %63 = OpCompositeConstruct %33 %53 %54 %55 %56
118 %64 = OpCompositeConstruct %33 %57 %58 %59 %60
119 %65 = OpCompositeConstruct %37 %61 %62 %63 %64
120 OpStore %39 %65
121 %69 = OpLoad %17 %19
122 %70 = OpLoad %21 %23
123 %71 = OpLoad %6 %30
124 %72 = OpLoad %33 %35
125 %73 = OpLoad %37 %39
126 %74 = OpCompositeConstruct %66 %69 %70 %71 %72 %73
127 OpStore %68 %74
128 OpReturn
129 OpFunctionEnd
130 %10 = OpFunction %6 None %8
131 %9 = OpFunctionParameter %7
132 %11 = OpLabel
133 %12 = OpVariable %7 Function
134 %13 = OpLoad %6 %9
135 OpStore %12 %13
136 %14 = OpLoad %6 %12
137 OpReturnValue %14
138 OpFunctionEnd
139 )";
140
141 const auto env = SPV_ENV_UNIVERSAL_1_3;
142 const auto consumer = nullptr;
143 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
144 spvtools::ValidatorOptions validator_options;
145 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
146 kConsoleMessageConsumer));
147 TransformationContext transformation_context(
148 MakeUnique<FactManager>(context.get()), validator_options);
149 // Target id is not fresh (59).
150 ASSERT_FALSE(TransformationAddCopyMemory(
151 MakeInstructionDescriptor(27, SpvOpFunctionCall, 0), 59, 19,
152 SpvStorageClassPrivate, 20)
153 .IsApplicable(context.get(), transformation_context));
154
155 // Instruction descriptor is invalid (id 90 is undefined).
156 ASSERT_FALSE(TransformationAddCopyMemory(
157 MakeInstructionDescriptor(90, SpvOpVariable, 0), 90, 19,
158 SpvStorageClassPrivate, 20)
159 .IsApplicable(context.get(), transformation_context));
160
161 // Cannot insert OpCopyMemory before OpPhi.
162 ASSERT_FALSE(
163 TransformationAddCopyMemory(MakeInstructionDescriptor(75, SpvOpPhi, 0),
164 90, 19, SpvStorageClassPrivate, 20)
165 .IsApplicable(context.get(), transformation_context));
166
167 // Source instruction is invalid.
168 ASSERT_FALSE(TransformationAddCopyMemory(
169 MakeInstructionDescriptor(27, SpvOpFunctionCall, 0), 90, 76,
170 SpvStorageClassPrivate, 0)
171 .IsApplicable(context.get(), transformation_context));
172
173 // Source instruction's type doesn't exist.
174 ASSERT_FALSE(TransformationAddCopyMemory(
175 MakeInstructionDescriptor(27, SpvOpFunctionCall, 0), 90, 5,
176 SpvStorageClassPrivate, 0)
177 .IsApplicable(context.get(), transformation_context));
178
179 // Source instruction's type is invalid.
180 ASSERT_FALSE(
181 TransformationAddCopyMemory(MakeInstructionDescriptor(41, SpvOpLoad, 0),
182 90, 40, SpvStorageClassPrivate, 0)
183 .IsApplicable(context.get(), transformation_context));
184
185 // Source instruction is OpUndef.
186 ASSERT_FALSE(
187 TransformationAddCopyMemory(MakeInstructionDescriptor(41, SpvOpLoad, 0),
188 90, 87, SpvStorageClassPrivate, 0)
189 .IsApplicable(context.get(), transformation_context));
190
191 // Source instruction is OpConstantNull.
192 ASSERT_FALSE(
193 TransformationAddCopyMemory(MakeInstructionDescriptor(41, SpvOpLoad, 0),
194 90, 88, SpvStorageClassPrivate, 0)
195 .IsApplicable(context.get(), transformation_context));
196
197 // Storage class is invalid.
198 ASSERT_FALSE(TransformationAddCopyMemory(
199 MakeInstructionDescriptor(27, SpvOpFunctionCall, 0), 90, 19,
200 SpvStorageClassWorkgroup, 20)
201 .IsApplicable(context.get(), transformation_context));
202
203 // Initializer is 0.
204 ASSERT_FALSE(TransformationAddCopyMemory(
205 MakeInstructionDescriptor(27, SpvOpFunctionCall, 0), 90, 19,
206 SpvStorageClassPrivate, 0)
207 .IsApplicable(context.get(), transformation_context));
208
209 // Initializer has wrong type.
210 ASSERT_FALSE(TransformationAddCopyMemory(
211 MakeInstructionDescriptor(27, SpvOpFunctionCall, 0), 90, 19,
212 SpvStorageClassPrivate, 25)
213 .IsApplicable(context.get(), transformation_context));
214
215 // Source and target instructions are in different functions.
216 ASSERT_FALSE(
217 TransformationAddCopyMemory(MakeInstructionDescriptor(13, SpvOpLoad, 0),
218 90, 19, SpvStorageClassPrivate, 20)
219 .IsApplicable(context.get(), transformation_context));
220
221 // Source instruction doesn't dominate the target instruction.
222 ASSERT_FALSE(TransformationAddCopyMemory(
223 MakeInstructionDescriptor(77, SpvOpLogicalEqual, 0), 90, 89,
224 SpvStorageClassPrivate, 20)
225 .IsApplicable(context.get(), transformation_context));
226
227 // Source and target instructions are the same.
228 ASSERT_FALSE(TransformationAddCopyMemory(
229 MakeInstructionDescriptor(19, SpvOpVariable, 0), 90, 19,
230 SpvStorageClassPrivate, 20)
231 .IsApplicable(context.get(), transformation_context));
232
233 // Correct transformations.
234 uint32_t fresh_id = 90;
235 auto descriptor = MakeInstructionDescriptor(27, SpvOpFunctionCall, 0);
236 std::vector<uint32_t> source_ids = {19, 23, 26, 30, 35, 39, 68, 86};
237 std::vector<uint32_t> initializers = {20, 24, 25, 25, 36, 84, 85, 20};
238 std::vector<SpvStorageClass> storage_classes = {SpvStorageClassPrivate,
239 SpvStorageClassFunction};
240 for (size_t i = 0, n = source_ids.size(); i < n; ++i) {
241 TransformationAddCopyMemory transformation(
242 descriptor, fresh_id, source_ids[i],
243 storage_classes[i % storage_classes.size()], initializers[i]);
244 ASSERT_TRUE(
245 transformation.IsApplicable(context.get(), transformation_context));
246 ApplyAndCheckFreshIds(transformation, context.get(),
247 &transformation_context);
248 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
249 context.get(), validator_options, kConsoleMessageConsumer));
250 ASSERT_TRUE(
251 transformation_context.GetFactManager()->PointeeValueIsIrrelevant(
252 fresh_id));
253 fresh_id++;
254 }
255
256 std::string expected = R"(
257 OpCapability Shader
258 %1 = OpExtInstImport "GLSL.std.450"
259 OpMemoryModel Logical GLSL450
260 OpEntryPoint Fragment %4 "main"
261 OpExecutionMode %4 OriginUpperLeft
262 OpSource ESSL 310
263 OpDecorate %19 RelaxedPrecision
264 OpMemberDecorate %66 0 RelaxedPrecision
265 OpDecorate %69 RelaxedPrecision
266 %2 = OpTypeVoid
267 %3 = OpTypeFunction %2
268 %6 = OpTypeBool
269 %7 = OpTypePointer Function %6
270 %78 = OpTypePointer Private %6
271 %8 = OpTypeFunction %6 %7
272 %17 = OpTypeInt 32 1
273 %18 = OpTypePointer Function %17
274 %79 = OpTypePointer Private %17
275 %20 = OpConstant %17 0
276 %21 = OpTypeFloat 32
277 %22 = OpTypePointer Function %21
278 %80 = OpTypePointer Private %21
279 %24 = OpConstant %21 0
280 %25 = OpConstantFalse %6
281 %32 = OpConstantTrue %6
282 %33 = OpTypeVector %21 4
283 %34 = OpTypePointer Function %33
284 %81 = OpTypePointer Private %33
285 %36 = OpConstantComposite %33 %24 %24 %24 %24
286 %37 = OpTypeMatrix %33 4
287 %84 = OpConstantComposite %37 %36 %36 %36 %36
288 %38 = OpTypePointer Function %37
289 %82 = OpTypePointer Private %37
290 %44 = OpConstant %21 1
291 %66 = OpTypeStruct %17 %21 %6 %33 %37
292 %85 = OpConstantComposite %66 %20 %24 %25 %36 %84
293 %67 = OpTypePointer Function %66
294 %83 = OpTypePointer Private %66
295 %86 = OpVariable %79 Private %20
296 %87 = OpUndef %79
297 %88 = OpConstantNull %79
298 %90 = OpVariable %79 Private %20
299 %92 = OpVariable %78 Private %25
300 %94 = OpVariable %81 Private %36
301 %96 = OpVariable %83 Private %85
302 %4 = OpFunction %2 None %3
303 %5 = OpLabel
304 %97 = OpVariable %18 Function %20
305 %95 = OpVariable %38 Function %84
306 %93 = OpVariable %7 Function %25
307 %91 = OpVariable %22 Function %24
308 %19 = OpVariable %18 Function
309 %23 = OpVariable %22 Function
310 %26 = OpVariable %7 Function
311 %30 = OpVariable %7 Function
312 %35 = OpVariable %34 Function
313 %39 = OpVariable %38 Function
314 %68 = OpVariable %67 Function
315 OpStore %19 %20
316 OpStore %23 %24
317 OpStore %26 %25
318 OpCopyMemory %90 %19
319 OpCopyMemory %91 %23
320 OpCopyMemory %92 %26
321 OpCopyMemory %93 %30
322 OpCopyMemory %94 %35
323 OpCopyMemory %95 %39
324 OpCopyMemory %96 %68
325 OpCopyMemory %97 %86
326 %27 = OpFunctionCall %6 %10 %26
327 OpSelectionMerge %29 None
328 OpBranchConditional %27 %28 %31
329 %28 = OpLabel
330 %89 = OpCopyObject %18 %19
331 OpBranch %29
332 %31 = OpLabel
333 OpBranch %29
334 %76 = OpLabel
335 %77 = OpLogicalEqual %6 %25 %32
336 OpBranch %29
337 %29 = OpLabel
338 %75 = OpPhi %6 %25 %31 %32 %28 %77 %76
339 OpStore %30 %75
340 %40 = OpLoad %33 %35
341 %41 = OpLoad %33 %35
342 %42 = OpLoad %33 %35
343 %43 = OpLoad %33 %35
344 %45 = OpCompositeExtract %21 %40 0
345 %46 = OpCompositeExtract %21 %40 1
346 %47 = OpCompositeExtract %21 %40 2
347 %48 = OpCompositeExtract %21 %40 3
348 %49 = OpCompositeExtract %21 %41 0
349 %50 = OpCompositeExtract %21 %41 1
350 %51 = OpCompositeExtract %21 %41 2
351 %52 = OpCompositeExtract %21 %41 3
352 %53 = OpCompositeExtract %21 %42 0
353 %54 = OpCompositeExtract %21 %42 1
354 %55 = OpCompositeExtract %21 %42 2
355 %56 = OpCompositeExtract %21 %42 3
356 %57 = OpCompositeExtract %21 %43 0
357 %58 = OpCompositeExtract %21 %43 1
358 %59 = OpCompositeExtract %21 %43 2
359 %60 = OpCompositeExtract %21 %43 3
360 %61 = OpCompositeConstruct %33 %45 %46 %47 %48
361 %62 = OpCompositeConstruct %33 %49 %50 %51 %52
362 %63 = OpCompositeConstruct %33 %53 %54 %55 %56
363 %64 = OpCompositeConstruct %33 %57 %58 %59 %60
364 %65 = OpCompositeConstruct %37 %61 %62 %63 %64
365 OpStore %39 %65
366 %69 = OpLoad %17 %19
367 %70 = OpLoad %21 %23
368 %71 = OpLoad %6 %30
369 %72 = OpLoad %33 %35
370 %73 = OpLoad %37 %39
371 %74 = OpCompositeConstruct %66 %69 %70 %71 %72 %73
372 OpStore %68 %74
373 OpReturn
374 OpFunctionEnd
375 %10 = OpFunction %6 None %8
376 %9 = OpFunctionParameter %7
377 %11 = OpLabel
378 %12 = OpVariable %7 Function
379 %13 = OpLoad %6 %9
380 OpStore %12 %13
381 %14 = OpLoad %6 %12
382 OpReturnValue %14
383 OpFunctionEnd
384 )";
385
386 ASSERT_TRUE(IsEqual(env, expected, context.get()));
387 }
388
TEST(TransformationAddCopyMemoryTest,DisallowBufferBlockDecoration)389 TEST(TransformationAddCopyMemoryTest, DisallowBufferBlockDecoration) {
390 std::string shader = R"(
391 OpCapability Shader
392 %1 = OpExtInstImport "GLSL.std.450"
393 OpMemoryModel Logical GLSL450
394 OpEntryPoint GLCompute %4 "main"
395 OpExecutionMode %4 LocalSize 1 1 1
396 OpSource ESSL 320
397 OpName %4 "main"
398 OpName %7 "buf"
399 OpMemberName %7 0 "a"
400 OpMemberName %7 1 "b"
401 OpName %9 ""
402 OpMemberDecorate %7 0 Offset 0
403 OpMemberDecorate %7 1 Offset 4
404 OpDecorate %7 BufferBlock
405 OpDecorate %9 DescriptorSet 0
406 OpDecorate %9 Binding 0
407 %2 = OpTypeVoid
408 %3 = OpTypeFunction %2
409 %6 = OpTypeInt 32 1
410 %10 = OpConstant %6 42
411 %7 = OpTypeStruct %6 %6
412 %8 = OpTypePointer Uniform %7
413 %9 = OpVariable %8 Uniform
414 %50 = OpUndef %7
415 %4 = OpFunction %2 None %3
416 %5 = OpLabel
417 OpReturn
418 OpFunctionEnd
419 )";
420
421 const auto env = SPV_ENV_UNIVERSAL_1_0;
422 const auto consumer = nullptr;
423 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
424 spvtools::ValidatorOptions validator_options;
425 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
426 kConsoleMessageConsumer));
427 TransformationContext transformation_context(
428 MakeUnique<FactManager>(context.get()), validator_options);
429 ASSERT_FALSE(
430 TransformationAddCopyMemory(MakeInstructionDescriptor(5, SpvOpReturn, 0),
431 100, 9, SpvStorageClassPrivate, 50)
432 .IsApplicable(context.get(), transformation_context));
433 }
434
TEST(TransformationAddCopyMemoryTest,DisallowBlockDecoration)435 TEST(TransformationAddCopyMemoryTest, DisallowBlockDecoration) {
436 std::string shader = R"(
437 OpCapability Shader
438 %1 = OpExtInstImport "GLSL.std.450"
439 OpMemoryModel Logical GLSL450
440 OpEntryPoint GLCompute %4 "main" %9
441 OpExecutionMode %4 LocalSize 1 1 1
442 OpSource ESSL 320
443 OpName %4 "main"
444 OpName %7 "buf"
445 OpMemberName %7 0 "a"
446 OpMemberName %7 1 "b"
447 OpName %9 ""
448 OpMemberDecorate %7 0 Offset 0
449 OpMemberDecorate %7 1 Offset 4
450 OpDecorate %7 Block
451 OpDecorate %9 DescriptorSet 0
452 OpDecorate %9 Binding 0
453 %2 = OpTypeVoid
454 %3 = OpTypeFunction %2
455 %6 = OpTypeInt 32 1
456 %10 = OpConstant %6 42
457 %7 = OpTypeStruct %6 %6
458 %8 = OpTypePointer StorageBuffer %7
459 %9 = OpVariable %8 StorageBuffer
460 %50 = OpUndef %7
461 %4 = OpFunction %2 None %3
462 %5 = OpLabel
463 OpReturn
464 OpFunctionEnd
465 )";
466
467 const auto env = SPV_ENV_UNIVERSAL_1_5;
468 const auto consumer = nullptr;
469 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
470 spvtools::ValidatorOptions validator_options;
471 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
472 kConsoleMessageConsumer));
473 TransformationContext transformation_context(
474 MakeUnique<FactManager>(context.get()), validator_options);
475 ASSERT_FALSE(
476 TransformationAddCopyMemory(MakeInstructionDescriptor(5, SpvOpReturn, 0),
477 100, 9, SpvStorageClassPrivate, 50)
478 .IsApplicable(context.get(), transformation_context));
479 }
480
481 } // namespace
482 } // namespace fuzz
483 } // namespace spvtools