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/fuzzer_pass_add_useful_constructs.h"
16 #include "source/fuzz/pseudo_random_generator.h"
17 #include "source/fuzz/uniform_buffer_element_descriptor.h"
18 #include "test/fuzz/fuzz_test_util.h"
19
20 namespace spvtools {
21 namespace fuzz {
22 namespace {
23
AddFactHelper(FactManager * fact_manager,opt::IRContext * context,uint32_t word,const protobufs::UniformBufferElementDescriptor & descriptor)24 bool AddFactHelper(
25 FactManager* fact_manager, opt::IRContext* context, uint32_t word,
26 const protobufs::UniformBufferElementDescriptor& descriptor) {
27 protobufs::FactConstantUniform constant_uniform_fact;
28 constant_uniform_fact.add_constant_word(word);
29 *constant_uniform_fact.mutable_uniform_buffer_element_descriptor() =
30 descriptor;
31 protobufs::Fact fact;
32 *fact.mutable_constant_uniform_fact() = constant_uniform_fact;
33 return fact_manager->AddFact(fact, context);
34 }
35
TEST(FuzzerPassAddUsefulConstructsTest,CheckBasicStuffIsAdded)36 TEST(FuzzerPassAddUsefulConstructsTest, CheckBasicStuffIsAdded) {
37 // The SPIR-V came from the following empty GLSL shader:
38 //
39 // #version 450
40 //
41 // void main()
42 // {
43 // }
44
45 std::string shader = R"(
46 OpCapability Shader
47 %1 = OpExtInstImport "GLSL.std.450"
48 OpMemoryModel Logical GLSL450
49 OpEntryPoint Fragment %4 "main"
50 OpExecutionMode %4 OriginUpperLeft
51 OpSource GLSL 450
52 OpName %4 "main"
53 %2 = OpTypeVoid
54 %3 = OpTypeFunction %2
55 %4 = OpFunction %2 None %3
56 %5 = OpLabel
57 OpReturn
58 OpFunctionEnd
59 )";
60
61 const auto env = SPV_ENV_UNIVERSAL_1_3;
62 const auto consumer = nullptr;
63 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
64 ASSERT_TRUE(IsValid(env, context.get()));
65
66 FactManager fact_manager;
67 spvtools::ValidatorOptions validator_options;
68 TransformationContext transformation_context(&fact_manager,
69 validator_options);
70
71 FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0).get(), 100);
72 protobufs::TransformationSequence transformation_sequence;
73
74 FuzzerPassAddUsefulConstructs pass(context.get(), &transformation_context,
75 &fuzzer_context, &transformation_sequence);
76 pass.Apply();
77 ASSERT_TRUE(IsValid(env, context.get()));
78
79 std::string after = R"(
80 OpCapability Shader
81 %1 = OpExtInstImport "GLSL.std.450"
82 OpMemoryModel Logical GLSL450
83 OpEntryPoint Fragment %4 "main"
84 OpExecutionMode %4 OriginUpperLeft
85 OpSource GLSL 450
86 OpName %4 "main"
87 %2 = OpTypeVoid
88 %3 = OpTypeFunction %2
89 %100 = OpTypeBool
90 %101 = OpTypeInt 32 1
91 %102 = OpTypeInt 32 0
92 %103 = OpTypeFloat 32
93 %104 = OpConstantTrue %100
94 %105 = OpConstantFalse %100
95 %106 = OpConstant %101 0
96 %107 = OpConstant %101 1
97 %108 = OpConstant %102 0
98 %109 = OpConstant %102 1
99 %110 = OpConstant %103 0
100 %111 = OpConstant %103 1
101 %4 = OpFunction %2 None %3
102 %5 = OpLabel
103 OpReturn
104 OpFunctionEnd
105 )";
106 ASSERT_TRUE(IsEqual(env, after, context.get()));
107 }
108
TEST(FuzzerPassAddUsefulConstructsTest,CheckTypesIndicesAndConstantsAddedForUniformFacts)109 TEST(FuzzerPassAddUsefulConstructsTest,
110 CheckTypesIndicesAndConstantsAddedForUniformFacts) {
111 // The SPIR-V came from the following GLSL shader:
112 //
113 // #version 450
114 //
115 // struct S {
116 // int x;
117 // float y;
118 // int z;
119 // int w;
120 // };
121 //
122 // uniform buf {
123 // S s;
124 // uint w[10];
125 // };
126 //
127 // void main() {
128 // }
129
130 std::string shader = R"(
131 OpCapability Shader
132 %1 = OpExtInstImport "GLSL.std.450"
133 OpMemoryModel Logical GLSL450
134 OpEntryPoint Fragment %4 "main"
135 OpExecutionMode %4 OriginUpperLeft
136 OpSource GLSL 450
137 OpName %4 "main"
138 OpName %8 "S"
139 OpMemberName %8 0 "x"
140 OpMemberName %8 1 "y"
141 OpMemberName %8 2 "z"
142 OpMemberName %8 3 "w"
143 OpName %12 "buf"
144 OpMemberName %12 0 "s"
145 OpMemberName %12 1 "w"
146 OpName %14 ""
147 OpMemberDecorate %8 0 Offset 0
148 OpMemberDecorate %8 1 Offset 4
149 OpMemberDecorate %8 2 Offset 8
150 OpMemberDecorate %8 3 Offset 12
151 OpDecorate %11 ArrayStride 16
152 OpMemberDecorate %12 0 Offset 0
153 OpMemberDecorate %12 1 Offset 16
154 OpDecorate %12 Block
155 OpDecorate %14 DescriptorSet 0
156 OpDecorate %14 Binding 0
157 %2 = OpTypeVoid
158 %3 = OpTypeFunction %2
159 %6 = OpTypeInt 32 1
160 %7 = OpTypeFloat 32
161 %8 = OpTypeStruct %6 %7 %6 %6
162 %9 = OpTypeInt 32 0
163 %10 = OpConstant %9 10
164 %11 = OpTypeArray %9 %10
165 %12 = OpTypeStruct %8 %11
166 %13 = OpTypePointer Uniform %12
167 %14 = OpVariable %13 Uniform
168 %4 = OpFunction %2 None %3
169 %5 = OpLabel
170 OpReturn
171 OpFunctionEnd
172 )";
173
174 const auto env = SPV_ENV_UNIVERSAL_1_3;
175 const auto consumer = nullptr;
176 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
177 ASSERT_TRUE(IsValid(env, context.get()));
178
179 FactManager fact_manager;
180 spvtools::ValidatorOptions validator_options;
181 TransformationContext transformation_context(&fact_manager,
182 validator_options);
183
184 FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0).get(), 100);
185 protobufs::TransformationSequence transformation_sequence;
186
187 // Add some uniform facts.
188
189 // buf.s.x == 200
190 ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 200,
191 MakeUniformBufferElementDescriptor(0, 0, {0, 0})));
192
193 // buf.s.y == 0.5
194 const float float_value = 0.5;
195 uint32_t float_value_as_uint;
196 memcpy(&float_value_as_uint, &float_value, sizeof(float_value));
197 ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), float_value_as_uint,
198 MakeUniformBufferElementDescriptor(0, 0, {0, 1})));
199
200 // buf.s.z == 300
201 ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 300,
202 MakeUniformBufferElementDescriptor(0, 0, {0, 2})));
203
204 // buf.s.w == 400
205 ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 400,
206 MakeUniformBufferElementDescriptor(0, 0, {0, 3})));
207
208 // buf.w[6] = 22
209 ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 22,
210 MakeUniformBufferElementDescriptor(0, 0, {1, 6})));
211
212 // buf.w[8] = 23
213 ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 23,
214 MakeUniformBufferElementDescriptor(0, 0, {1, 8})));
215
216 // Assert some things about the module that are not true prior to adding the
217 // pass
218
219 {
220 // No uniform int pointer
221 opt::analysis::Integer temp_type_signed_int(32, true);
222 opt::analysis::Integer* registered_type_signed_int =
223 context->get_type_mgr()
224 ->GetRegisteredType(&temp_type_signed_int)
225 ->AsInteger();
226 opt::analysis::Pointer type_pointer_uniform_signed_int(
227 registered_type_signed_int, SpvStorageClassUniform);
228 ASSERT_EQ(0,
229 context->get_type_mgr()->GetId(&type_pointer_uniform_signed_int));
230
231 // No uniform uint pointer
232 opt::analysis::Integer temp_type_unsigned_int(32, false);
233 opt::analysis::Integer* registered_type_unsigned_int =
234 context->get_type_mgr()
235 ->GetRegisteredType(&temp_type_unsigned_int)
236 ->AsInteger();
237 opt::analysis::Pointer type_pointer_uniform_unsigned_int(
238 registered_type_unsigned_int, SpvStorageClassUniform);
239 ASSERT_EQ(
240 0, context->get_type_mgr()->GetId(&type_pointer_uniform_unsigned_int));
241
242 // No uniform float pointer
243 opt::analysis::Float temp_type_float(32);
244 opt::analysis::Float* registered_type_float =
245 context->get_type_mgr()->GetRegisteredType(&temp_type_float)->AsFloat();
246 opt::analysis::Pointer type_pointer_uniform_float(registered_type_float,
247 SpvStorageClassUniform);
248 ASSERT_EQ(0, context->get_type_mgr()->GetId(&type_pointer_uniform_float));
249
250 // No int constants 200, 300 nor 400
251 opt::analysis::IntConstant int_constant_200(registered_type_signed_int,
252 {200});
253 opt::analysis::IntConstant int_constant_300(registered_type_signed_int,
254 {300});
255 opt::analysis::IntConstant int_constant_400(registered_type_signed_int,
256 {400});
257 ASSERT_EQ(nullptr,
258 context->get_constant_mgr()->FindConstant(&int_constant_200));
259 ASSERT_EQ(nullptr,
260 context->get_constant_mgr()->FindConstant(&int_constant_300));
261 ASSERT_EQ(nullptr,
262 context->get_constant_mgr()->FindConstant(&int_constant_400));
263
264 // No float constant 0.5
265 opt::analysis::FloatConstant float_constant_zero_point_five(
266 registered_type_float, {float_value_as_uint});
267 ASSERT_EQ(nullptr, context->get_constant_mgr()->FindConstant(
268 &float_constant_zero_point_five));
269
270 // No uint constant 22
271 opt::analysis::IntConstant uint_constant_22(registered_type_unsigned_int,
272 {22});
273 ASSERT_EQ(nullptr,
274 context->get_constant_mgr()->FindConstant(&uint_constant_22));
275
276 // No uint constant 23
277 opt::analysis::IntConstant uint_constant_23(registered_type_unsigned_int,
278 {23});
279 ASSERT_EQ(nullptr,
280 context->get_constant_mgr()->FindConstant(&uint_constant_23));
281
282 // No int constants 0, 1, 2, 3, 6, 8
283 opt::analysis::IntConstant int_constant_0(registered_type_signed_int, {0});
284 opt::analysis::IntConstant int_constant_1(registered_type_signed_int, {1});
285 opt::analysis::IntConstant int_constant_2(registered_type_signed_int, {2});
286 opt::analysis::IntConstant int_constant_3(registered_type_signed_int, {3});
287 opt::analysis::IntConstant int_constant_6(registered_type_signed_int, {6});
288 opt::analysis::IntConstant int_constant_8(registered_type_signed_int, {8});
289 ASSERT_EQ(nullptr,
290 context->get_constant_mgr()->FindConstant(&int_constant_0));
291 ASSERT_EQ(nullptr,
292 context->get_constant_mgr()->FindConstant(&int_constant_1));
293 ASSERT_EQ(nullptr,
294 context->get_constant_mgr()->FindConstant(&int_constant_2));
295 ASSERT_EQ(nullptr,
296 context->get_constant_mgr()->FindConstant(&int_constant_3));
297 ASSERT_EQ(nullptr,
298 context->get_constant_mgr()->FindConstant(&int_constant_6));
299 ASSERT_EQ(nullptr,
300 context->get_constant_mgr()->FindConstant(&int_constant_8));
301 }
302
303 FuzzerPassAddUsefulConstructs pass(context.get(), &transformation_context,
304 &fuzzer_context, &transformation_sequence);
305 pass.Apply();
306 ASSERT_TRUE(IsValid(env, context.get()));
307
308 // Now assert some things about the module that should be true following the
309 // pass.
310
311 // We reconstruct all necessary types and constants to guard against the type
312 // and constant managers for the module having been invalidated.
313
314 {
315 // Uniform int pointer now present
316 opt::analysis::Integer temp_type_signed_int(32, true);
317 opt::analysis::Integer* registered_type_signed_int =
318 context->get_type_mgr()
319 ->GetRegisteredType(&temp_type_signed_int)
320 ->AsInteger();
321 opt::analysis::Pointer type_pointer_uniform_signed_int(
322 registered_type_signed_int, SpvStorageClassUniform);
323 ASSERT_NE(0,
324 context->get_type_mgr()->GetId(&type_pointer_uniform_signed_int));
325
326 // Uniform uint pointer now present
327 opt::analysis::Integer temp_type_unsigned_int(32, false);
328 opt::analysis::Integer* registered_type_unsigned_int =
329 context->get_type_mgr()
330 ->GetRegisteredType(&temp_type_unsigned_int)
331 ->AsInteger();
332 opt::analysis::Pointer type_pointer_uniform_unsigned_int(
333 registered_type_unsigned_int, SpvStorageClassUniform);
334 ASSERT_NE(
335 0, context->get_type_mgr()->GetId(&type_pointer_uniform_unsigned_int));
336
337 // Uniform float pointer now present
338 opt::analysis::Float temp_type_float(32);
339 opt::analysis::Float* registered_type_float =
340 context->get_type_mgr()->GetRegisteredType(&temp_type_float)->AsFloat();
341 opt::analysis::Pointer type_pointer_uniform_float(registered_type_float,
342 SpvStorageClassUniform);
343 ASSERT_NE(0, context->get_type_mgr()->GetId(&type_pointer_uniform_float));
344
345 // int constants 200, 300, 400 now present
346 opt::analysis::IntConstant int_constant_200(registered_type_signed_int,
347 {200});
348 opt::analysis::IntConstant int_constant_300(registered_type_signed_int,
349 {300});
350 opt::analysis::IntConstant int_constant_400(registered_type_signed_int,
351 {400});
352 ASSERT_NE(nullptr,
353 context->get_constant_mgr()->FindConstant(&int_constant_200));
354 ASSERT_NE(nullptr,
355 context->get_constant_mgr()->FindConstant(&int_constant_300));
356 ASSERT_NE(nullptr,
357 context->get_constant_mgr()->FindConstant(&int_constant_400));
358
359 // float constant 0.5 now present
360 opt::analysis::FloatConstant float_constant_zero_point_five(
361 registered_type_float, {float_value_as_uint});
362 ASSERT_NE(nullptr, context->get_constant_mgr()->FindConstant(
363 &float_constant_zero_point_five));
364
365 // uint constant 22 now present
366 opt::analysis::IntConstant uint_constant_22(registered_type_unsigned_int,
367 {22});
368 ASSERT_NE(nullptr,
369 context->get_constant_mgr()->FindConstant(&uint_constant_22));
370
371 // uint constant 23 now present
372 opt::analysis::IntConstant uint_constant_23(registered_type_unsigned_int,
373 {23});
374 ASSERT_NE(nullptr,
375 context->get_constant_mgr()->FindConstant(&uint_constant_23));
376
377 // int constants 0, 1, 2, 3, 6, 8 now present
378 opt::analysis::IntConstant int_constant_0(registered_type_signed_int, {0});
379 opt::analysis::IntConstant int_constant_1(registered_type_signed_int, {1});
380 opt::analysis::IntConstant int_constant_2(registered_type_signed_int, {2});
381 opt::analysis::IntConstant int_constant_3(registered_type_signed_int, {3});
382 opt::analysis::IntConstant int_constant_6(registered_type_signed_int, {6});
383 opt::analysis::IntConstant int_constant_8(registered_type_signed_int, {8});
384 ASSERT_NE(nullptr,
385 context->get_constant_mgr()->FindConstant(&int_constant_0));
386 ASSERT_NE(nullptr,
387 context->get_constant_mgr()->FindConstant(&int_constant_1));
388 ASSERT_NE(nullptr,
389 context->get_constant_mgr()->FindConstant(&int_constant_2));
390 ASSERT_NE(nullptr,
391 context->get_constant_mgr()->FindConstant(&int_constant_3));
392 ASSERT_NE(nullptr,
393 context->get_constant_mgr()->FindConstant(&int_constant_6));
394 ASSERT_NE(nullptr,
395 context->get_constant_mgr()->FindConstant(&int_constant_8));
396 }
397 }
398
399 } // namespace
400 } // namespace fuzz
401 } // namespace spvtools
402