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_store.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(TransformationStoreTest,BasicTest)26 TEST(TransformationStoreTest, BasicTest) {
27   std::string shader = R"(
28                OpCapability Shader
29           %1 = OpExtInstImport "GLSL.std.450"
30                OpMemoryModel Logical GLSL450
31                OpEntryPoint Fragment %4 "main" %92 %52 %53
32                OpExecutionMode %4 OriginUpperLeft
33                OpSource ESSL 310
34                OpDecorate %92 BuiltIn FragCoord
35           %2 = OpTypeVoid
36           %3 = OpTypeFunction %2
37           %6 = OpTypeInt 32 1
38           %7 = OpTypeFloat 32
39           %8 = OpTypeStruct %6 %7
40           %9 = OpTypePointer Function %8
41          %10 = OpTypeFunction %6 %9
42          %14 = OpConstant %6 0
43          %15 = OpTypePointer Function %6
44          %51 = OpTypePointer Private %6
45          %21 = OpConstant %6 2
46          %23 = OpConstant %6 1
47          %24 = OpConstant %7 1
48          %25 = OpTypePointer Function %7
49          %50 = OpTypePointer Private %7
50          %34 = OpTypeBool
51          %35 = OpConstantFalse %34
52          %60 = OpConstantNull %50
53          %61 = OpUndef %51
54          %52 = OpVariable %50 Private
55          %53 = OpVariable %51 Private
56          %80 = OpConstantComposite %8 %21 %24
57          %90 = OpTypeVector %7 4
58          %91 = OpTypePointer Input %90
59          %92 = OpVariable %91 Input
60          %93 = OpConstantComposite %90 %24 %24 %24 %24
61           %4 = OpFunction %2 None %3
62           %5 = OpLabel
63          %20 = OpVariable %9 Function
64          %27 = OpVariable %9 Function ; irrelevant
65          %22 = OpAccessChain %15 %20 %14
66          %44 = OpCopyObject %9 %20
67          %26 = OpAccessChain %25 %20 %23
68          %29 = OpFunctionCall %6 %12 %27
69          %30 = OpAccessChain %15 %20 %14
70          %45 = OpCopyObject %15 %30
71          %81 = OpCopyObject %9 %27 ; irrelevant
72          %33 = OpAccessChain %15 %20 %14
73                OpSelectionMerge %37 None
74                OpBranchConditional %35 %36 %37
75          %36 = OpLabel
76          %38 = OpAccessChain %15 %20 %14
77          %40 = OpAccessChain %15 %20 %14
78          %43 = OpAccessChain %15 %20 %14
79          %82 = OpCopyObject %9 %27 ; irrelevant
80                OpBranch %37
81          %37 = OpLabel
82                OpReturn
83                OpFunctionEnd
84          %12 = OpFunction %6 None %10
85          %11 = OpFunctionParameter %9 ; irrelevant
86          %13 = OpLabel
87          %46 = OpCopyObject %9 %11 ; irrelevant
88          %16 = OpAccessChain %15 %11 %14 ; irrelevant
89          %95 = OpCopyObject %8 %80
90                OpReturnValue %21
91                OpFunctionEnd
92   )";
93 
94   const auto env = SPV_ENV_UNIVERSAL_1_4;
95   const auto consumer = nullptr;
96   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
97   spvtools::ValidatorOptions validator_options;
98   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
99                                                kConsoleMessageConsumer));
100   TransformationContext transformation_context(
101       MakeUnique<FactManager>(context.get()), validator_options);
102   transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
103       27);
104   transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
105       11);
106   transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
107       46);
108   transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
109       16);
110   transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
111       52);
112   transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
113       81);
114   transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
115       82);
116 
117   transformation_context.GetFactManager()->AddFactBlockIsDead(36);
118 
119   // Variables with pointee types:
120   //  52 - ptr_to(7)
121   //  53 - ptr_to(6)
122   //  20 - ptr_to(8)
123   //  27 - ptr_to(8) - irrelevant
124   //  92 - ptr_to(90) - read only
125 
126   // Access chains with pointee type:
127   //  22 - ptr_to(6)
128   //  26 - ptr_to(6)
129   //  30 - ptr_to(6)
130   //  33 - ptr_to(6)
131   //  38 - ptr_to(6)
132   //  40 - ptr_to(6)
133   //  43 - ptr_to(6)
134   //  16 - ptr_to(6) - irrelevant
135 
136   // Copied object with pointee type:
137   //  44 - ptr_to(8)
138   //  45 - ptr_to(6)
139   //  46 - ptr_to(8) - irrelevant
140   //  81 - ptr_to(8) - irrelevant
141   //  82 - ptr_to(8) - irrelevant
142 
143   // Function parameters with pointee type:
144   //  11 - ptr_to(8) - irrelevant
145 
146   // Pointers that cannot be used:
147   //  60 - null
148   //  61 - undefined
149 
150   // Bad: attempt to store to 11 from outside its function
151   ASSERT_FALSE(TransformationStore(
152                    11, 80, MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
153                    .IsApplicable(context.get(), transformation_context));
154 
155   // Bad: pointer is not available
156   ASSERT_FALSE(TransformationStore(
157                    81, 80, MakeInstructionDescriptor(45, SpvOpCopyObject, 0))
158                    .IsApplicable(context.get(), transformation_context));
159 
160   // Bad: attempt to insert before OpVariable
161   ASSERT_FALSE(TransformationStore(
162                    52, 24, MakeInstructionDescriptor(27, SpvOpVariable, 0))
163                    .IsApplicable(context.get(), transformation_context));
164 
165   // Bad: pointer id does not exist
166   ASSERT_FALSE(TransformationStore(
167                    1000, 24, MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
168                    .IsApplicable(context.get(), transformation_context));
169 
170   // Bad: pointer id exists but does not have a type
171   ASSERT_FALSE(TransformationStore(
172                    5, 24, MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
173                    .IsApplicable(context.get(), transformation_context));
174 
175   // Bad: pointer id exists and has a type, but is not a pointer
176   ASSERT_FALSE(TransformationStore(
177                    24, 24, MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
178                    .IsApplicable(context.get(), transformation_context));
179 
180   // Bad: attempt to store to a null pointer
181   ASSERT_FALSE(TransformationStore(
182                    60, 24, MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
183                    .IsApplicable(context.get(), transformation_context));
184 
185   // Bad: attempt to store to an undefined pointer
186   ASSERT_FALSE(TransformationStore(
187                    61, 21, MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
188                    .IsApplicable(context.get(), transformation_context));
189 
190   // Bad: %82 is not available at the program point
191   ASSERT_FALSE(
192       TransformationStore(82, 80, MakeInstructionDescriptor(37, SpvOpReturn, 0))
193           .IsApplicable(context.get(), transformation_context));
194 
195   // Bad: value id does not exist
196   ASSERT_FALSE(TransformationStore(
197                    27, 1000, MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
198                    .IsApplicable(context.get(), transformation_context));
199 
200   // Bad: value id exists but does not have a type
201   ASSERT_FALSE(TransformationStore(
202                    27, 15, MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
203                    .IsApplicable(context.get(), transformation_context));
204 
205   // Bad: value id exists but has the wrong type
206   ASSERT_FALSE(TransformationStore(
207                    27, 14, MakeInstructionDescriptor(38, SpvOpAccessChain, 0))
208                    .IsApplicable(context.get(), transformation_context));
209 
210   // Bad: attempt to store to read-only variable
211   ASSERT_FALSE(TransformationStore(
212                    92, 93, MakeInstructionDescriptor(40, SpvOpAccessChain, 0))
213                    .IsApplicable(context.get(), transformation_context));
214 
215   // Bad: value is not available
216   ASSERT_FALSE(TransformationStore(
217                    27, 95, MakeInstructionDescriptor(40, SpvOpAccessChain, 0))
218                    .IsApplicable(context.get(), transformation_context));
219 
220   // Bad: variable being stored to does not have an irrelevant pointee value,
221   // and the store is not in a dead block.
222   ASSERT_FALSE(TransformationStore(
223                    20, 95, MakeInstructionDescriptor(45, SpvOpCopyObject, 0))
224                    .IsApplicable(context.get(), transformation_context));
225 
226   // The described instruction does not exist.
227   ASSERT_FALSE(TransformationStore(
228                    27, 80, MakeInstructionDescriptor(1000, SpvOpAccessChain, 0))
229                    .IsApplicable(context.get(), transformation_context));
230 
231   {
232     // Store to irrelevant variable from dead block.
233     TransformationStore transformation(
234         27, 80, MakeInstructionDescriptor(38, SpvOpAccessChain, 0));
235     ASSERT_TRUE(
236         transformation.IsApplicable(context.get(), transformation_context));
237     ApplyAndCheckFreshIds(transformation, context.get(),
238                           &transformation_context);
239     ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
240         context.get(), validator_options, kConsoleMessageConsumer));
241   }
242 
243   {
244     // Store to irrelevant variable from live block.
245     TransformationStore transformation(
246         11, 95, MakeInstructionDescriptor(95, SpvOpReturnValue, 0));
247     ASSERT_TRUE(
248         transformation.IsApplicable(context.get(), transformation_context));
249     ApplyAndCheckFreshIds(transformation, context.get(),
250                           &transformation_context);
251     ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
252         context.get(), validator_options, kConsoleMessageConsumer));
253   }
254 
255   {
256     // Store to irrelevant variable from live block.
257     TransformationStore transformation(
258         46, 80, MakeInstructionDescriptor(95, SpvOpReturnValue, 0));
259     ASSERT_TRUE(
260         transformation.IsApplicable(context.get(), transformation_context));
261     ApplyAndCheckFreshIds(transformation, context.get(),
262                           &transformation_context);
263     ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
264         context.get(), validator_options, kConsoleMessageConsumer));
265   }
266 
267   {
268     // Store to irrelevant variable from live block.
269     TransformationStore transformation(
270         16, 21, MakeInstructionDescriptor(95, SpvOpReturnValue, 0));
271     ASSERT_TRUE(
272         transformation.IsApplicable(context.get(), transformation_context));
273     ApplyAndCheckFreshIds(transformation, context.get(),
274                           &transformation_context);
275     ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
276         context.get(), validator_options, kConsoleMessageConsumer));
277   }
278 
279   {
280     // Store to non-irrelevant variable from dead block.
281     TransformationStore transformation(
282         53, 21, MakeInstructionDescriptor(38, SpvOpAccessChain, 0));
283     ASSERT_TRUE(
284         transformation.IsApplicable(context.get(), transformation_context));
285     ApplyAndCheckFreshIds(transformation, context.get(),
286                           &transformation_context);
287     ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
288         context.get(), validator_options, kConsoleMessageConsumer));
289   }
290 
291   std::string after_transformation = R"(
292                OpCapability Shader
293           %1 = OpExtInstImport "GLSL.std.450"
294                OpMemoryModel Logical GLSL450
295                OpEntryPoint Fragment %4 "main" %92 %52 %53
296                OpExecutionMode %4 OriginUpperLeft
297                OpSource ESSL 310
298                OpDecorate %92 BuiltIn FragCoord
299           %2 = OpTypeVoid
300           %3 = OpTypeFunction %2
301           %6 = OpTypeInt 32 1
302           %7 = OpTypeFloat 32
303           %8 = OpTypeStruct %6 %7
304           %9 = OpTypePointer Function %8
305          %10 = OpTypeFunction %6 %9
306          %14 = OpConstant %6 0
307          %15 = OpTypePointer Function %6
308          %51 = OpTypePointer Private %6
309          %21 = OpConstant %6 2
310          %23 = OpConstant %6 1
311          %24 = OpConstant %7 1
312          %25 = OpTypePointer Function %7
313          %50 = OpTypePointer Private %7
314          %34 = OpTypeBool
315          %35 = OpConstantFalse %34
316          %60 = OpConstantNull %50
317          %61 = OpUndef %51
318          %52 = OpVariable %50 Private
319          %53 = OpVariable %51 Private
320          %80 = OpConstantComposite %8 %21 %24
321          %90 = OpTypeVector %7 4
322          %91 = OpTypePointer Input %90
323          %92 = OpVariable %91 Input
324          %93 = OpConstantComposite %90 %24 %24 %24 %24
325           %4 = OpFunction %2 None %3
326           %5 = OpLabel
327          %20 = OpVariable %9 Function
328          %27 = OpVariable %9 Function ; irrelevant
329          %22 = OpAccessChain %15 %20 %14
330          %44 = OpCopyObject %9 %20
331          %26 = OpAccessChain %25 %20 %23
332          %29 = OpFunctionCall %6 %12 %27
333          %30 = OpAccessChain %15 %20 %14
334          %45 = OpCopyObject %15 %30
335          %81 = OpCopyObject %9 %27 ; irrelevant
336          %33 = OpAccessChain %15 %20 %14
337                OpSelectionMerge %37 None
338                OpBranchConditional %35 %36 %37
339          %36 = OpLabel
340                OpStore %27 %80
341                OpStore %53 %21
342          %38 = OpAccessChain %15 %20 %14
343          %40 = OpAccessChain %15 %20 %14
344          %43 = OpAccessChain %15 %20 %14
345          %82 = OpCopyObject %9 %27 ; irrelevant
346                OpBranch %37
347          %37 = OpLabel
348                OpReturn
349                OpFunctionEnd
350          %12 = OpFunction %6 None %10
351          %11 = OpFunctionParameter %9 ; irrelevant
352          %13 = OpLabel
353          %46 = OpCopyObject %9 %11 ; irrelevant
354          %16 = OpAccessChain %15 %11 %14 ; irrelevant
355          %95 = OpCopyObject %8 %80
356                OpStore %11 %95
357                OpStore %46 %80
358                OpStore %16 %21
359                OpReturnValue %21
360                OpFunctionEnd
361   )";
362   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
363 }
364 
TEST(TransformationStoreTest,DoNotAllowStoresToReadOnlyMemory)365 TEST(TransformationStoreTest, DoNotAllowStoresToReadOnlyMemory) {
366   std::string shader = R"(
367                OpCapability Shader
368           %1 = OpExtInstImport "GLSL.std.450"
369                OpMemoryModel Logical GLSL450
370                OpEntryPoint Fragment %4 "main"
371                OpExecutionMode %4 OriginUpperLeft
372                OpSource ESSL 320
373                OpMemberDecorate %10 0 Offset 0
374                OpMemberDecorate %10 1 Offset 4
375                OpDecorate %10 Block
376                OpMemberDecorate %23 0 Offset 0
377                OpDecorate %23 Block
378                OpDecorate %25 DescriptorSet 0
379                OpDecorate %25 Binding 0
380           %2 = OpTypeVoid
381           %3 = OpTypeFunction %2
382           %6 = OpTypeInt 32 1
383           %7 = OpTypePointer Function %6
384           %9 = OpTypeFloat 32
385          %10 = OpTypeStruct %6 %9
386          %11 = OpTypePointer PushConstant %10
387          %12 = OpVariable %11 PushConstant
388          %13 = OpConstant %6 0
389          %14 = OpTypePointer PushConstant %6
390          %17 = OpConstant %6 1
391          %18 = OpTypePointer PushConstant %9
392          %23 = OpTypeStruct %9
393          %24 = OpTypePointer UniformConstant %23
394          %25 = OpVariable %24 UniformConstant
395          %26 = OpTypePointer UniformConstant %9
396          %50 = OpConstant %9 0
397           %4 = OpFunction %2 None %3
398           %5 = OpLabel
399          %15 = OpAccessChain %14 %12 %13
400          %19 = OpAccessChain %18 %12 %17
401          %27 = OpAccessChain %26 %25 %13
402                OpReturn
403                OpFunctionEnd
404   )";
405 
406   const auto env = SPV_ENV_UNIVERSAL_1_3;
407   const auto consumer = nullptr;
408   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
409   spvtools::ValidatorOptions validator_options;
410   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
411                                                kConsoleMessageConsumer));
412   TransformationContext transformation_context(
413       MakeUnique<FactManager>(context.get()), validator_options);
414   transformation_context.GetFactManager()->AddFactBlockIsDead(5);
415 
416   ASSERT_FALSE(
417       TransformationStore(15, 13, MakeInstructionDescriptor(27, SpvOpReturn, 0))
418           .IsApplicable(context.get(), transformation_context));
419   ASSERT_FALSE(
420       TransformationStore(19, 50, MakeInstructionDescriptor(27, SpvOpReturn, 0))
421           .IsApplicable(context.get(), transformation_context));
422   ASSERT_FALSE(
423       TransformationStore(27, 50, MakeInstructionDescriptor(27, SpvOpReturn, 0))
424           .IsApplicable(context.get(), transformation_context));
425 }
426 
427 }  // namespace
428 }  // namespace fuzz
429 }  // namespace spvtools
430