• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2020 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_function_call.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(TransformationFunctionCallTest,BasicTest)26 TEST(TransformationFunctionCallTest, 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 = OpTypePointer Function %6
38           %8 = OpTypeFunction %6 %7
39          %12 = OpTypeFloat 32
40          %13 = OpTypePointer Function %12
41          %14 = OpTypeFunction %6 %7 %13
42          %27 = OpConstant %6 1
43          %50 = OpConstant %12 1
44          %57 = OpTypeBool
45          %58 = OpConstantFalse %57
46         %204 = OpUndef %6
47           %4 = OpFunction %2 None %3
48           %5 = OpLabel
49          %61 = OpVariable %7 Function
50          %62 = OpVariable %7 Function
51          %65 = OpVariable %13 Function
52          %66 = OpVariable %7 Function
53          %68 = OpVariable %13 Function
54          %71 = OpVariable %7 Function
55          %72 = OpVariable %13 Function
56          %73 = OpVariable %7 Function
57          %75 = OpVariable %13 Function
58          %78 = OpVariable %7 Function
59          %98 = OpAccessChain %7 %71
60          %99 = OpCopyObject %7 %71
61                OpSelectionMerge %60 None
62                OpBranchConditional %58 %59 %60
63          %59 = OpLabel
64                OpBranch %60
65          %60 = OpLabel
66                OpReturn
67                OpFunctionEnd
68          %10 = OpFunction %6 None %8
69           %9 = OpFunctionParameter %7
70          %11 = OpLabel
71          %26 = OpLoad %6 %9
72          %28 = OpIAdd %6 %26 %27
73                OpSelectionMerge %97 None
74                OpBranchConditional %58 %96 %97
75          %96 = OpLabel
76                OpBranch %97
77          %97 = OpLabel
78                OpReturnValue %28
79                OpFunctionEnd
80          %17 = OpFunction %6 None %14
81          %15 = OpFunctionParameter %7
82          %16 = OpFunctionParameter %13
83          %18 = OpLabel
84          %31 = OpVariable %7 Function
85          %32 = OpLoad %6 %15
86                OpStore %31 %32
87          %33 = OpFunctionCall %6 %10 %31
88                OpReturnValue %33
89                OpFunctionEnd
90          %21 = OpFunction %6 None %14
91          %19 = OpFunctionParameter %7
92          %20 = OpFunctionParameter %13
93          %22 = OpLabel
94          %36 = OpLoad %6 %19
95          %37 = OpLoad %12 %20
96          %38 = OpConvertFToS %6 %37
97          %39 = OpIAdd %6 %36 %38
98                OpReturnValue %39
99                OpFunctionEnd
100          %24 = OpFunction %6 None %8
101          %23 = OpFunctionParameter %7
102          %25 = OpLabel
103          %44 = OpVariable %7 Function
104          %46 = OpVariable %13 Function
105          %51 = OpVariable %7 Function
106          %52 = OpVariable %13 Function
107          %42 = OpLoad %6 %23
108          %43 = OpConvertSToF %12 %42
109          %45 = OpLoad %6 %23
110                OpStore %44 %45
111                OpStore %46 %43
112          %47 = OpFunctionCall %6 %17 %44 %46
113          %48 = OpLoad %6 %23
114          %49 = OpIAdd %6 %48 %27
115                OpStore %51 %49
116                OpStore %52 %50
117          %53 = OpFunctionCall %6 %17 %51 %52
118          %54 = OpIAdd %6 %47 %53
119                OpReturnValue %54
120                OpFunctionEnd
121         %200 = OpFunction %6 None %14
122         %201 = OpFunctionParameter %7
123         %202 = OpFunctionParameter %13
124         %203 = OpLabel
125                OpSelectionMerge %206 None
126                OpBranchConditional %58 %205 %206
127         %205 = OpLabel
128                OpBranch %206
129         %206 = OpLabel
130                OpReturnValue %204
131                OpFunctionEnd
132   )";
133 
134   const auto env = SPV_ENV_UNIVERSAL_1_4;
135   const auto consumer = nullptr;
136   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
137   spvtools::ValidatorOptions validator_options;
138   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
139                                                kConsoleMessageConsumer));
140   TransformationContext transformation_context(
141       MakeUnique<FactManager>(context.get()), validator_options);
142   transformation_context.GetFactManager()->AddFactBlockIsDead(59);
143   transformation_context.GetFactManager()->AddFactBlockIsDead(11);
144   transformation_context.GetFactManager()->AddFactBlockIsDead(18);
145   transformation_context.GetFactManager()->AddFactBlockIsDead(25);
146   transformation_context.GetFactManager()->AddFactBlockIsDead(96);
147   transformation_context.GetFactManager()->AddFactBlockIsDead(205);
148   transformation_context.GetFactManager()->AddFactFunctionIsLivesafe(21);
149   transformation_context.GetFactManager()->AddFactFunctionIsLivesafe(200);
150   transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
151       71);
152   transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
153       72);
154   transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
155       19);
156   transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
157       20);
158   transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
159       23);
160   transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
161       44);
162   transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
163       46);
164   transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
165       51);
166   transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
167       52);
168 
169   // Livesafe functions with argument types: 21(7, 13), 200(7, 13)
170   // Non-livesafe functions with argument types: 4(), 10(7), 17(7, 13), 24(7)
171   // Call graph edges:
172   //    17 -> 10
173   //    24 -> 17
174 
175   // Bad transformations
176   // Too many arguments
177   ASSERT_FALSE(
178       TransformationFunctionCall(100, 21, {71, 72, 71},
179                                  MakeInstructionDescriptor(59, SpvOpBranch, 0))
180           .IsApplicable(context.get(), transformation_context));
181   // Too few arguments
182   ASSERT_FALSE(TransformationFunctionCall(
183                    100, 21, {71}, MakeInstructionDescriptor(59, SpvOpBranch, 0))
184                    .IsApplicable(context.get(), transformation_context));
185   // Arguments are the wrong way around (types do not match)
186   ASSERT_FALSE(
187       TransformationFunctionCall(100, 21, {72, 71},
188                                  MakeInstructionDescriptor(59, SpvOpBranch, 0))
189           .IsApplicable(context.get(), transformation_context));
190   // 21 is not an appropriate argument
191   ASSERT_FALSE(
192       TransformationFunctionCall(100, 21, {21, 72},
193                                  MakeInstructionDescriptor(59, SpvOpBranch, 0))
194           .IsApplicable(context.get(), transformation_context));
195   // 300 does not exist
196   ASSERT_FALSE(
197       TransformationFunctionCall(100, 21, {300, 72},
198                                  MakeInstructionDescriptor(59, SpvOpBranch, 0))
199           .IsApplicable(context.get(), transformation_context));
200   // 71 is not a function
201   ASSERT_FALSE(
202       TransformationFunctionCall(100, 71, {71, 72},
203                                  MakeInstructionDescriptor(59, SpvOpBranch, 0))
204           .IsApplicable(context.get(), transformation_context));
205   // 500 does not exist
206   ASSERT_FALSE(
207       TransformationFunctionCall(100, 500, {71, 72},
208                                  MakeInstructionDescriptor(59, SpvOpBranch, 0))
209           .IsApplicable(context.get(), transformation_context));
210   // Id is not fresh
211   ASSERT_FALSE(
212       TransformationFunctionCall(21, 21, {71, 72},
213                                  MakeInstructionDescriptor(59, SpvOpBranch, 0))
214           .IsApplicable(context.get(), transformation_context));
215   // Access chain as pointer parameter
216   ASSERT_FALSE(
217       TransformationFunctionCall(100, 21, {98, 72},
218                                  MakeInstructionDescriptor(59, SpvOpBranch, 0))
219           .IsApplicable(context.get(), transformation_context));
220   // Copied object as pointer parameter
221   ASSERT_FALSE(
222       TransformationFunctionCall(100, 21, {99, 72},
223                                  MakeInstructionDescriptor(59, SpvOpBranch, 0))
224           .IsApplicable(context.get(), transformation_context));
225   // Non-livesafe called from original live block
226   ASSERT_FALSE(
227       TransformationFunctionCall(
228           100, 10, {71}, MakeInstructionDescriptor(99, SpvOpSelectionMerge, 0))
229           .IsApplicable(context.get(), transformation_context));
230   // Non-livesafe called from livesafe function
231   ASSERT_FALSE(
232       TransformationFunctionCall(
233           100, 10, {19}, MakeInstructionDescriptor(38, SpvOpConvertFToS, 0))
234           .IsApplicable(context.get(), transformation_context));
235   // Livesafe function called with pointer to non-arbitrary local variable
236   ASSERT_FALSE(
237       TransformationFunctionCall(
238           100, 21, {61, 72}, MakeInstructionDescriptor(38, SpvOpConvertFToS, 0))
239           .IsApplicable(context.get(), transformation_context));
240   // Direct recursion
241   ASSERT_FALSE(TransformationFunctionCall(
242                    100, 4, {}, MakeInstructionDescriptor(59, SpvOpBranch, 0))
243                    .IsApplicable(context.get(), transformation_context));
244   // Indirect recursion
245   ASSERT_FALSE(TransformationFunctionCall(
246                    100, 24, {9}, MakeInstructionDescriptor(96, SpvOpBranch, 0))
247                    .IsApplicable(context.get(), transformation_context));
248   // Parameter 23 is not available at the call site
249   ASSERT_FALSE(
250       TransformationFunctionCall(104, 10, {23},
251                                  MakeInstructionDescriptor(205, SpvOpBranch, 0))
252           .IsApplicable(context.get(), transformation_context));
253 
254   // Good transformations
255   {
256     // Livesafe called from dead block: fine
257     TransformationFunctionCall transformation(
258         100, 21, {71, 72}, MakeInstructionDescriptor(59, SpvOpBranch, 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     // Livesafe called from original live block: fine
268     TransformationFunctionCall transformation(
269         101, 21, {71, 72}, MakeInstructionDescriptor(98, SpvOpAccessChain, 0));
270     ASSERT_TRUE(
271         transformation.IsApplicable(context.get(), transformation_context));
272     ApplyAndCheckFreshIds(transformation, context.get(),
273                           &transformation_context);
274     ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
275         context.get(), validator_options, kConsoleMessageConsumer));
276   }
277   {
278     // Livesafe called from livesafe function: fine
279     TransformationFunctionCall transformation(
280         102, 200, {19, 20}, MakeInstructionDescriptor(36, SpvOpLoad, 0));
281     ASSERT_TRUE(
282         transformation.IsApplicable(context.get(), transformation_context));
283     ApplyAndCheckFreshIds(transformation, context.get(),
284                           &transformation_context);
285     ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
286         context.get(), validator_options, kConsoleMessageConsumer));
287   }
288   {
289     // Dead called from dead block in injected function: fine
290     TransformationFunctionCall transformation(
291         103, 10, {23}, MakeInstructionDescriptor(45, SpvOpLoad, 0));
292     ASSERT_TRUE(
293         transformation.IsApplicable(context.get(), transformation_context));
294     ApplyAndCheckFreshIds(transformation, context.get(),
295                           &transformation_context);
296     ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
297         context.get(), validator_options, kConsoleMessageConsumer));
298   }
299   {
300     // Non-livesafe called from dead block in livesafe function: OK
301     TransformationFunctionCall transformation(
302         104, 10, {201}, MakeInstructionDescriptor(205, SpvOpBranch, 0));
303     ASSERT_TRUE(
304         transformation.IsApplicable(context.get(), transformation_context));
305     ApplyAndCheckFreshIds(transformation, context.get(),
306                           &transformation_context);
307     ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
308         context.get(), validator_options, kConsoleMessageConsumer));
309   }
310   {
311     // Livesafe called from dead block with non-arbitrary parameter
312     TransformationFunctionCall transformation(
313         105, 21, {62, 65}, MakeInstructionDescriptor(59, SpvOpBranch, 0));
314     ASSERT_TRUE(
315         transformation.IsApplicable(context.get(), transformation_context));
316     ApplyAndCheckFreshIds(transformation, context.get(),
317                           &transformation_context);
318     ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
319         context.get(), validator_options, kConsoleMessageConsumer));
320   }
321 
322   std::string after_transformation = R"(
323                OpCapability Shader
324           %1 = OpExtInstImport "GLSL.std.450"
325                OpMemoryModel Logical GLSL450
326                OpEntryPoint Fragment %4 "main"
327                OpExecutionMode %4 OriginUpperLeft
328                OpSource ESSL 310
329           %2 = OpTypeVoid
330           %3 = OpTypeFunction %2
331           %6 = OpTypeInt 32 1
332           %7 = OpTypePointer Function %6
333           %8 = OpTypeFunction %6 %7
334          %12 = OpTypeFloat 32
335          %13 = OpTypePointer Function %12
336          %14 = OpTypeFunction %6 %7 %13
337          %27 = OpConstant %6 1
338          %50 = OpConstant %12 1
339          %57 = OpTypeBool
340          %58 = OpConstantFalse %57
341         %204 = OpUndef %6
342           %4 = OpFunction %2 None %3
343           %5 = OpLabel
344          %61 = OpVariable %7 Function
345          %62 = OpVariable %7 Function
346          %65 = OpVariable %13 Function
347          %66 = OpVariable %7 Function
348          %68 = OpVariable %13 Function
349          %71 = OpVariable %7 Function
350          %72 = OpVariable %13 Function
351          %73 = OpVariable %7 Function
352          %75 = OpVariable %13 Function
353          %78 = OpVariable %7 Function
354         %101 = OpFunctionCall %6 %21 %71 %72
355          %98 = OpAccessChain %7 %71
356          %99 = OpCopyObject %7 %71
357                OpSelectionMerge %60 None
358                OpBranchConditional %58 %59 %60
359          %59 = OpLabel
360         %100 = OpFunctionCall %6 %21 %71 %72
361         %105 = OpFunctionCall %6 %21 %62 %65
362                OpBranch %60
363          %60 = OpLabel
364                OpReturn
365                OpFunctionEnd
366          %10 = OpFunction %6 None %8
367           %9 = OpFunctionParameter %7
368          %11 = OpLabel
369          %26 = OpLoad %6 %9
370          %28 = OpIAdd %6 %26 %27
371                OpSelectionMerge %97 None
372                OpBranchConditional %58 %96 %97
373          %96 = OpLabel
374                OpBranch %97
375          %97 = OpLabel
376                OpReturnValue %28
377                OpFunctionEnd
378          %17 = OpFunction %6 None %14
379          %15 = OpFunctionParameter %7
380          %16 = OpFunctionParameter %13
381          %18 = OpLabel
382          %31 = OpVariable %7 Function
383          %32 = OpLoad %6 %15
384                OpStore %31 %32
385          %33 = OpFunctionCall %6 %10 %31
386                OpReturnValue %33
387                OpFunctionEnd
388          %21 = OpFunction %6 None %14
389          %19 = OpFunctionParameter %7
390          %20 = OpFunctionParameter %13
391          %22 = OpLabel
392         %102 = OpFunctionCall %6 %200 %19 %20
393          %36 = OpLoad %6 %19
394          %37 = OpLoad %12 %20
395          %38 = OpConvertFToS %6 %37
396          %39 = OpIAdd %6 %36 %38
397                OpReturnValue %39
398                OpFunctionEnd
399          %24 = OpFunction %6 None %8
400          %23 = OpFunctionParameter %7
401          %25 = OpLabel
402          %44 = OpVariable %7 Function
403          %46 = OpVariable %13 Function
404          %51 = OpVariable %7 Function
405          %52 = OpVariable %13 Function
406          %42 = OpLoad %6 %23
407          %43 = OpConvertSToF %12 %42
408         %103 = OpFunctionCall %6 %10 %23
409          %45 = OpLoad %6 %23
410                OpStore %44 %45
411                OpStore %46 %43
412          %47 = OpFunctionCall %6 %17 %44 %46
413          %48 = OpLoad %6 %23
414          %49 = OpIAdd %6 %48 %27
415                OpStore %51 %49
416                OpStore %52 %50
417          %53 = OpFunctionCall %6 %17 %51 %52
418          %54 = OpIAdd %6 %47 %53
419                OpReturnValue %54
420                OpFunctionEnd
421         %200 = OpFunction %6 None %14
422         %201 = OpFunctionParameter %7
423         %202 = OpFunctionParameter %13
424         %203 = OpLabel
425                OpSelectionMerge %206 None
426                OpBranchConditional %58 %205 %206
427         %205 = OpLabel
428         %104 = OpFunctionCall %6 %10 %201
429                OpBranch %206
430         %206 = OpLabel
431                OpReturnValue %204
432                OpFunctionEnd
433   )";
434   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
435 }
436 
TEST(TransformationFunctionCallTest,DoNotInvokeEntryPoint)437 TEST(TransformationFunctionCallTest, DoNotInvokeEntryPoint) {
438   std::string shader = R"(
439                OpCapability Shader
440           %1 = OpExtInstImport "GLSL.std.450"
441                OpMemoryModel Logical GLSL450
442                OpEntryPoint Fragment %4 "main"
443                OpExecutionMode %4 OriginUpperLeft
444                OpSource ESSL 310
445           %2 = OpTypeVoid
446           %3 = OpTypeFunction %2
447           %4 = OpFunction %2 None %3
448           %5 = OpLabel
449                OpReturn
450                OpFunctionEnd
451          %10 = OpFunction %2 None %3
452          %11 = OpLabel
453                OpReturn
454                OpFunctionEnd
455   )";
456 
457   const auto env = SPV_ENV_UNIVERSAL_1_4;
458   const auto consumer = nullptr;
459   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
460   spvtools::ValidatorOptions validator_options;
461   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
462                                                kConsoleMessageConsumer));
463   TransformationContext transformation_context(
464       MakeUnique<FactManager>(context.get()), validator_options);
465   transformation_context.GetFactManager()->AddFactBlockIsDead(11);
466 
467   // 4 is an entry point, so it is not legal for it to be the target of a call.
468   ASSERT_FALSE(TransformationFunctionCall(
469                    100, 4, {}, MakeInstructionDescriptor(11, SpvOpReturn, 0))
470                    .IsApplicable(context.get(), transformation_context));
471 }
472 
473 }  // namespace
474 }  // namespace fuzz
475 }  // namespace spvtools
476