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