• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_mutate_pointer.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(TransformationMutatePointerTest,BasicTest)26 TEST(TransformationMutatePointerTest, 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          %34 = OpConstant %7 0
39          %36 = OpConstant %6 0
40          %14 = OpTypeVector %7 3
41          %35 = OpConstantComposite %14 %34 %34 %34
42          %15 = OpTypeMatrix %14 2
43           %8 = OpConstant %6 5
44           %9 = OpTypeArray %7 %8
45          %37 = OpConstantComposite %9 %34 %34 %34 %34 %34
46          %11 = OpTypeStruct
47          %38 = OpConstantComposite %11
48          %39 = OpConstantComposite %15 %35 %35
49          %31 = OpTypePointer Function %14
50          %10 = OpTypeStruct %7 %6 %9 %11 %15 %14
51          %40 = OpConstantComposite %10 %34 %36 %37 %38 %39 %35
52          %13 = OpTypePointer Function %10
53          %16 = OpTypePointer Private %10
54          %17 = OpTypePointer Workgroup %10
55          %18 = OpTypeStruct %16
56          %19 = OpTypePointer Private %18
57          %20 = OpVariable %16 Private
58          %21 = OpVariable %17 Workgroup
59          %22 = OpVariable %19 Private
60          %23 = OpTypePointer Output %6
61          %24 = OpVariable %23 Output
62          %27 = OpTypeFunction %2 %13
63          %32 = OpUndef %16
64          %33 = OpConstantNull %16
65           %4 = OpFunction %2 None %3
66           %5 = OpLabel
67                OpReturn
68                OpFunctionEnd
69          %28 = OpFunction %2 None %27
70          %29 = OpFunctionParameter %13
71          %30 = OpLabel
72          %25 = OpVariable %13 Function
73          %26 = OpAccessChain %31 %25 %8
74                OpReturn
75                OpFunctionEnd
76   )";
77 
78   const auto env = SPV_ENV_UNIVERSAL_1_3;
79   const auto consumer = nullptr;
80   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
81   spvtools::ValidatorOptions validator_options;
82   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
83                                                kConsoleMessageConsumer));
84   TransformationContext transformation_context(
85       MakeUnique<FactManager>(context.get()), validator_options);
86   transformation_context.GetFactManager()->AddFactIdIsIrrelevant(35);
87   transformation_context.GetFactManager()->AddFactIdIsIrrelevant(39);
88 
89   const auto insert_before = MakeInstructionDescriptor(26, SpvOpReturn, 0);
90 
91   // 20 is not a fresh id.
92   ASSERT_FALSE(TransformationMutatePointer(20, 20, insert_before)
93                    .IsApplicable(context.get(), transformation_context));
94 
95   // |insert_before| instruction descriptor is invalid.
96   ASSERT_FALSE(TransformationMutatePointer(
97                    20, 70, MakeInstructionDescriptor(26, SpvOpStore, 0))
98                    .IsApplicable(context.get(), transformation_context));
99 
100   // Can't insert OpLoad before OpVariable.
101   ASSERT_FALSE(TransformationMutatePointer(
102                    20, 70, MakeInstructionDescriptor(26, SpvOpVariable, 0))
103                    .IsApplicable(context.get(), transformation_context));
104 
105   // |pointer_id| doesn't exist in the module.
106   ASSERT_FALSE(TransformationMutatePointer(70, 70, insert_before)
107                    .IsApplicable(context.get(), transformation_context));
108 
109   // |pointer_id| doesn't have a type id.
110   ASSERT_FALSE(TransformationMutatePointer(11, 70, insert_before)
111                    .IsApplicable(context.get(), transformation_context));
112 
113   // |pointer_id| is a result id of OpUndef.
114   ASSERT_FALSE(TransformationMutatePointer(32, 70, insert_before)
115                    .IsApplicable(context.get(), transformation_context));
116 
117   // |pointer_id| is a result id of OpConstantNull.
118   ASSERT_FALSE(TransformationMutatePointer(33, 70, insert_before)
119                    .IsApplicable(context.get(), transformation_context));
120 
121   // |pointer_id| is not a pointer instruction.
122   ASSERT_FALSE(TransformationMutatePointer(8, 70, insert_before)
123                    .IsApplicable(context.get(), transformation_context));
124 
125   // |pointer_id| has invalid storage class
126   ASSERT_FALSE(TransformationMutatePointer(24, 70, insert_before)
127                    .IsApplicable(context.get(), transformation_context));
128 
129   // |pointer_id|'s pointee contains non-scalar and non-composite constituents.
130   ASSERT_FALSE(TransformationMutatePointer(22, 70, insert_before)
131                    .IsApplicable(context.get(), transformation_context));
132 
133   // There is no irrelevant zero constant to insert into the |pointer_id|.
134   ASSERT_FALSE(TransformationMutatePointer(20, 70, insert_before)
135                    .IsApplicable(context.get(), transformation_context));
136 
137   // |pointer_id| is not available before |insert_before|.
138   ASSERT_FALSE(TransformationMutatePointer(
139                    26, 70, MakeInstructionDescriptor(26, SpvOpAccessChain, 0))
140                    .IsApplicable(context.get(), transformation_context));
141 
142   transformation_context.GetFactManager()->AddFactIdIsIrrelevant(40);
143 
144   uint32_t fresh_id = 70;
145   uint32_t pointer_ids[] = {
146       20,  // Mutate Private variable.
147       21,  // Mutate Workgroup variable.
148       25,  // Mutate Function variable.
149       29,  // Mutate function parameter.
150       26,  // Mutate OpAccessChain.
151   };
152 
153   for (auto pointer_id : pointer_ids) {
154     TransformationMutatePointer transformation(pointer_id, fresh_id++,
155                                                insert_before);
156     ASSERT_TRUE(
157         transformation.IsApplicable(context.get(), transformation_context));
158     ApplyAndCheckFreshIds(transformation, context.get(),
159                           &transformation_context);
160     ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
161         context.get(), validator_options, kConsoleMessageConsumer));
162   }
163 
164   std::string after_transformation = R"(
165                OpCapability Shader
166           %1 = OpExtInstImport "GLSL.std.450"
167                OpMemoryModel Logical GLSL450
168                OpEntryPoint Fragment %4 "main"
169                OpExecutionMode %4 OriginUpperLeft
170                OpSource ESSL 310
171           %2 = OpTypeVoid
172           %3 = OpTypeFunction %2
173           %6 = OpTypeInt 32 1
174           %7 = OpTypeFloat 32
175          %34 = OpConstant %7 0
176          %36 = OpConstant %6 0
177          %14 = OpTypeVector %7 3
178          %35 = OpConstantComposite %14 %34 %34 %34
179          %15 = OpTypeMatrix %14 2
180           %8 = OpConstant %6 5
181           %9 = OpTypeArray %7 %8
182          %37 = OpConstantComposite %9 %34 %34 %34 %34 %34
183          %11 = OpTypeStruct
184          %38 = OpConstantComposite %11
185          %39 = OpConstantComposite %15 %35 %35
186          %31 = OpTypePointer Function %14
187          %10 = OpTypeStruct %7 %6 %9 %11 %15 %14
188          %40 = OpConstantComposite %10 %34 %36 %37 %38 %39 %35
189          %13 = OpTypePointer Function %10
190          %16 = OpTypePointer Private %10
191          %17 = OpTypePointer Workgroup %10
192          %18 = OpTypeStruct %16
193          %19 = OpTypePointer Private %18
194          %20 = OpVariable %16 Private
195          %21 = OpVariable %17 Workgroup
196          %22 = OpVariable %19 Private
197          %23 = OpTypePointer Output %6
198          %24 = OpVariable %23 Output
199          %27 = OpTypeFunction %2 %13
200          %32 = OpUndef %16
201          %33 = OpConstantNull %16
202           %4 = OpFunction %2 None %3
203           %5 = OpLabel
204                OpReturn
205                OpFunctionEnd
206          %28 = OpFunction %2 None %27
207          %29 = OpFunctionParameter %13
208          %30 = OpLabel
209          %25 = OpVariable %13 Function
210          %26 = OpAccessChain %31 %25 %8
211 
212          ; modified Private variable
213          %70 = OpLoad %10 %20
214                OpStore %20 %40
215                OpStore %20 %70
216 
217          ; modified Workgroup variable
218          %71 = OpLoad %10 %21
219                OpStore %21 %40
220                OpStore %21 %71
221 
222          ; modified Function variable
223          %72 = OpLoad %10 %25
224                OpStore %25 %40
225                OpStore %25 %72
226 
227          ; modified function parameter
228          %73 = OpLoad %10 %29
229                OpStore %29 %40
230                OpStore %29 %73
231 
232          ; modified OpAccessChain
233          %74 = OpLoad %14 %26
234                OpStore %26 %35
235                OpStore %26 %74
236 
237                OpReturn
238                OpFunctionEnd
239   )";
240 
241   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
242 }
243 
TEST(TransformationMutatePointerTest,HandlesUnreachableBlocks)244 TEST(TransformationMutatePointerTest, HandlesUnreachableBlocks) {
245   std::string shader = R"(
246                OpCapability Shader
247           %1 = OpExtInstImport "GLSL.std.450"
248                OpMemoryModel Logical GLSL450
249                OpEntryPoint Fragment %4 "main"
250                OpExecutionMode %4 OriginUpperLeft
251                OpSource ESSL 310
252           %2 = OpTypeVoid
253           %3 = OpTypeFunction %2
254           %6 = OpTypeInt 32 1
255           %7 = OpConstant %6 0
256           %8 = OpTypePointer Function %6
257          %11 = OpTypePointer Private %6
258          %12 = OpVariable %11 Private
259           %4 = OpFunction %2 None %3
260           %5 = OpLabel
261           %9 = OpVariable %8 Function
262                OpReturn
263          %10 = OpLabel
264                OpReturn
265                OpFunctionEnd
266   )";
267 
268   const auto env = SPV_ENV_UNIVERSAL_1_3;
269   const auto consumer = nullptr;
270   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
271   spvtools::ValidatorOptions validator_options;
272   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
273                                                kConsoleMessageConsumer));
274   TransformationContext transformation_context(
275       MakeUnique<FactManager>(context.get()), validator_options);
276   transformation_context.GetFactManager()->AddFactIdIsIrrelevant(7);
277 
278   ASSERT_FALSE(
279       context->GetDominatorAnalysis(context->GetFunction(4))->IsReachable(10));
280 
281   const auto insert_before = MakeInstructionDescriptor(10, SpvOpReturn, 0);
282 
283   // Can mutate a global variable in an unreachable block.
284   TransformationMutatePointer transformation(12, 50, insert_before);
285   ASSERT_TRUE(
286       transformation.IsApplicable(context.get(), transformation_context));
287   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
288   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
289                                                kConsoleMessageConsumer));
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"
296                OpExecutionMode %4 OriginUpperLeft
297                OpSource ESSL 310
298           %2 = OpTypeVoid
299           %3 = OpTypeFunction %2
300           %6 = OpTypeInt 32 1
301           %7 = OpConstant %6 0
302           %8 = OpTypePointer Function %6
303          %11 = OpTypePointer Private %6
304          %12 = OpVariable %11 Private
305           %4 = OpFunction %2 None %3
306           %5 = OpLabel
307           %9 = OpVariable %8 Function
308                OpReturn
309          %10 = OpLabel
310          %50 = OpLoad %6 %12
311                OpStore %12 %7
312                OpStore %12 %50
313                OpReturn
314                OpFunctionEnd
315   )";
316 
317   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
318 }
319 
320 }  // namespace
321 }  // namespace fuzz
322 }  // namespace spvtools
323