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