// Copyright (c) 2019 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "source/fuzz/fuzzer_pass_add_useful_constructs.h" #include "source/fuzz/pseudo_random_generator.h" #include "source/fuzz/uniform_buffer_element_descriptor.h" #include "test/fuzz/fuzz_test_util.h" namespace spvtools { namespace fuzz { namespace { bool AddFactHelper( FactManager* fact_manager, opt::IRContext* context, uint32_t word, const protobufs::UniformBufferElementDescriptor& descriptor) { protobufs::FactConstantUniform constant_uniform_fact; constant_uniform_fact.add_constant_word(word); *constant_uniform_fact.mutable_uniform_buffer_element_descriptor() = descriptor; protobufs::Fact fact; *fact.mutable_constant_uniform_fact() = constant_uniform_fact; return fact_manager->AddFact(fact, context); } TEST(FuzzerPassAddUsefulConstructsTest, CheckBasicStuffIsAdded) { // The SPIR-V came from the following empty GLSL shader: // // #version 450 // // void main() // { // } std::string shader = R"( OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %4 "main" OpExecutionMode %4 OriginUpperLeft OpSource GLSL 450 OpName %4 "main" %2 = OpTypeVoid %3 = OpTypeFunction %2 %4 = OpFunction %2 None %3 %5 = OpLabel OpReturn OpFunctionEnd )"; const auto env = SPV_ENV_UNIVERSAL_1_3; const auto consumer = nullptr; const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); ASSERT_TRUE(IsValid(env, context.get())); FactManager fact_manager; FuzzerContext fuzzer_context(MakeUnique(0).get(), 100); protobufs::TransformationSequence transformation_sequence; FuzzerPassAddUsefulConstructs pass(context.get(), &fact_manager, &fuzzer_context, &transformation_sequence); pass.Apply(); ASSERT_TRUE(IsValid(env, context.get())); std::string after = R"( OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %4 "main" OpExecutionMode %4 OriginUpperLeft OpSource GLSL 450 OpName %4 "main" %2 = OpTypeVoid %3 = OpTypeFunction %2 %100 = OpTypeBool %101 = OpTypeInt 32 1 %102 = OpTypeInt 32 0 %103 = OpTypeFloat 32 %104 = OpConstantTrue %100 %105 = OpConstantFalse %100 %106 = OpConstant %101 0 %107 = OpConstant %101 1 %108 = OpConstant %102 0 %109 = OpConstant %102 1 %110 = OpConstant %103 0 %111 = OpConstant %103 1 %4 = OpFunction %2 None %3 %5 = OpLabel OpReturn OpFunctionEnd )"; ASSERT_TRUE(IsEqual(env, after, context.get())); } TEST(FuzzerPassAddUsefulConstructsTest, CheckTypesIndicesAndConstantsAddedForUniformFacts) { // The SPIR-V came from the following GLSL shader: // // #version 450 // // struct S { // int x; // float y; // int z; // int w; // }; // // uniform buf { // S s; // uint w[10]; // }; // // void main() { // } std::string shader = R"( OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Fragment %4 "main" OpExecutionMode %4 OriginUpperLeft OpSource GLSL 450 OpName %4 "main" OpName %8 "S" OpMemberName %8 0 "x" OpMemberName %8 1 "y" OpMemberName %8 2 "z" OpMemberName %8 3 "w" OpName %12 "buf" OpMemberName %12 0 "s" OpMemberName %12 1 "w" OpName %14 "" OpMemberDecorate %8 0 Offset 0 OpMemberDecorate %8 1 Offset 4 OpMemberDecorate %8 2 Offset 8 OpMemberDecorate %8 3 Offset 12 OpDecorate %11 ArrayStride 16 OpMemberDecorate %12 0 Offset 0 OpMemberDecorate %12 1 Offset 16 OpDecorate %12 Block OpDecorate %14 DescriptorSet 0 OpDecorate %14 Binding 0 %2 = OpTypeVoid %3 = OpTypeFunction %2 %6 = OpTypeInt 32 1 %7 = OpTypeFloat 32 %8 = OpTypeStruct %6 %7 %6 %6 %9 = OpTypeInt 32 0 %10 = OpConstant %9 10 %11 = OpTypeArray %9 %10 %12 = OpTypeStruct %8 %11 %13 = OpTypePointer Uniform %12 %14 = OpVariable %13 Uniform %4 = OpFunction %2 None %3 %5 = OpLabel OpReturn OpFunctionEnd )"; const auto env = SPV_ENV_UNIVERSAL_1_3; const auto consumer = nullptr; const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption); ASSERT_TRUE(IsValid(env, context.get())); FactManager fact_manager; FuzzerContext fuzzer_context(MakeUnique(0).get(), 100); protobufs::TransformationSequence transformation_sequence; // Add some uniform facts. // buf.s.x == 200 ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 200, MakeUniformBufferElementDescriptor(0, 0, {0, 0}))); // buf.s.y == 0.5 const float float_value = 0.5; uint32_t float_value_as_uint; memcpy(&float_value_as_uint, &float_value, sizeof(float_value)); ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), float_value_as_uint, MakeUniformBufferElementDescriptor(0, 0, {0, 1}))); // buf.s.z == 300 ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 300, MakeUniformBufferElementDescriptor(0, 0, {0, 2}))); // buf.s.w == 400 ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 400, MakeUniformBufferElementDescriptor(0, 0, {0, 3}))); // buf.w[6] = 22 ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 22, MakeUniformBufferElementDescriptor(0, 0, {1, 6}))); // buf.w[8] = 23 ASSERT_TRUE(AddFactHelper(&fact_manager, context.get(), 23, MakeUniformBufferElementDescriptor(0, 0, {1, 8}))); // Assert some things about the module that are not true prior to adding the // pass { // No uniform int pointer opt::analysis::Integer temp_type_signed_int(32, true); opt::analysis::Integer* registered_type_signed_int = context->get_type_mgr() ->GetRegisteredType(&temp_type_signed_int) ->AsInteger(); opt::analysis::Pointer type_pointer_uniform_signed_int( registered_type_signed_int, SpvStorageClassUniform); ASSERT_EQ(0, context->get_type_mgr()->GetId(&type_pointer_uniform_signed_int)); // No uniform uint pointer opt::analysis::Integer temp_type_unsigned_int(32, false); opt::analysis::Integer* registered_type_unsigned_int = context->get_type_mgr() ->GetRegisteredType(&temp_type_unsigned_int) ->AsInteger(); opt::analysis::Pointer type_pointer_uniform_unsigned_int( registered_type_unsigned_int, SpvStorageClassUniform); ASSERT_EQ( 0, context->get_type_mgr()->GetId(&type_pointer_uniform_unsigned_int)); // No uniform float pointer opt::analysis::Float temp_type_float(32); opt::analysis::Float* registered_type_float = context->get_type_mgr()->GetRegisteredType(&temp_type_float)->AsFloat(); opt::analysis::Pointer type_pointer_uniform_float(registered_type_float, SpvStorageClassUniform); ASSERT_EQ(0, context->get_type_mgr()->GetId(&type_pointer_uniform_float)); // No int constants 200, 300 nor 400 opt::analysis::IntConstant int_constant_200(registered_type_signed_int, {200}); opt::analysis::IntConstant int_constant_300(registered_type_signed_int, {300}); opt::analysis::IntConstant int_constant_400(registered_type_signed_int, {400}); ASSERT_EQ(nullptr, context->get_constant_mgr()->FindConstant(&int_constant_200)); ASSERT_EQ(nullptr, context->get_constant_mgr()->FindConstant(&int_constant_300)); ASSERT_EQ(nullptr, context->get_constant_mgr()->FindConstant(&int_constant_400)); // No float constant 0.5 opt::analysis::FloatConstant float_constant_zero_point_five( registered_type_float, {float_value_as_uint}); ASSERT_EQ(nullptr, context->get_constant_mgr()->FindConstant( &float_constant_zero_point_five)); // No uint constant 22 opt::analysis::IntConstant uint_constant_22(registered_type_unsigned_int, {22}); ASSERT_EQ(nullptr, context->get_constant_mgr()->FindConstant(&uint_constant_22)); // No uint constant 23 opt::analysis::IntConstant uint_constant_23(registered_type_unsigned_int, {23}); ASSERT_EQ(nullptr, context->get_constant_mgr()->FindConstant(&uint_constant_23)); // No int constants 0, 1, 2, 3, 6, 8 opt::analysis::IntConstant int_constant_0(registered_type_signed_int, {0}); opt::analysis::IntConstant int_constant_1(registered_type_signed_int, {1}); opt::analysis::IntConstant int_constant_2(registered_type_signed_int, {2}); opt::analysis::IntConstant int_constant_3(registered_type_signed_int, {3}); opt::analysis::IntConstant int_constant_6(registered_type_signed_int, {6}); opt::analysis::IntConstant int_constant_8(registered_type_signed_int, {8}); ASSERT_EQ(nullptr, context->get_constant_mgr()->FindConstant(&int_constant_0)); ASSERT_EQ(nullptr, context->get_constant_mgr()->FindConstant(&int_constant_1)); ASSERT_EQ(nullptr, context->get_constant_mgr()->FindConstant(&int_constant_2)); ASSERT_EQ(nullptr, context->get_constant_mgr()->FindConstant(&int_constant_3)); ASSERT_EQ(nullptr, context->get_constant_mgr()->FindConstant(&int_constant_6)); ASSERT_EQ(nullptr, context->get_constant_mgr()->FindConstant(&int_constant_8)); } FuzzerPassAddUsefulConstructs pass(context.get(), &fact_manager, &fuzzer_context, &transformation_sequence); pass.Apply(); ASSERT_TRUE(IsValid(env, context.get())); // Now assert some things about the module that should be true following the // pass. // We reconstruct all necessary types and constants to guard against the type // and constant managers for the module having been invalidated. { // Uniform int pointer now present opt::analysis::Integer temp_type_signed_int(32, true); opt::analysis::Integer* registered_type_signed_int = context->get_type_mgr() ->GetRegisteredType(&temp_type_signed_int) ->AsInteger(); opt::analysis::Pointer type_pointer_uniform_signed_int( registered_type_signed_int, SpvStorageClassUniform); ASSERT_NE(0, context->get_type_mgr()->GetId(&type_pointer_uniform_signed_int)); // Uniform uint pointer now present opt::analysis::Integer temp_type_unsigned_int(32, false); opt::analysis::Integer* registered_type_unsigned_int = context->get_type_mgr() ->GetRegisteredType(&temp_type_unsigned_int) ->AsInteger(); opt::analysis::Pointer type_pointer_uniform_unsigned_int( registered_type_unsigned_int, SpvStorageClassUniform); ASSERT_NE( 0, context->get_type_mgr()->GetId(&type_pointer_uniform_unsigned_int)); // Uniform float pointer now present opt::analysis::Float temp_type_float(32); opt::analysis::Float* registered_type_float = context->get_type_mgr()->GetRegisteredType(&temp_type_float)->AsFloat(); opt::analysis::Pointer type_pointer_uniform_float(registered_type_float, SpvStorageClassUniform); ASSERT_NE(0, context->get_type_mgr()->GetId(&type_pointer_uniform_float)); // int constants 200, 300, 400 now present opt::analysis::IntConstant int_constant_200(registered_type_signed_int, {200}); opt::analysis::IntConstant int_constant_300(registered_type_signed_int, {300}); opt::analysis::IntConstant int_constant_400(registered_type_signed_int, {400}); ASSERT_NE(nullptr, context->get_constant_mgr()->FindConstant(&int_constant_200)); ASSERT_NE(nullptr, context->get_constant_mgr()->FindConstant(&int_constant_300)); ASSERT_NE(nullptr, context->get_constant_mgr()->FindConstant(&int_constant_400)); // float constant 0.5 now present opt::analysis::FloatConstant float_constant_zero_point_five( registered_type_float, {float_value_as_uint}); ASSERT_NE(nullptr, context->get_constant_mgr()->FindConstant( &float_constant_zero_point_five)); // uint constant 22 now present opt::analysis::IntConstant uint_constant_22(registered_type_unsigned_int, {22}); ASSERT_NE(nullptr, context->get_constant_mgr()->FindConstant(&uint_constant_22)); // uint constant 23 now present opt::analysis::IntConstant uint_constant_23(registered_type_unsigned_int, {23}); ASSERT_NE(nullptr, context->get_constant_mgr()->FindConstant(&uint_constant_23)); // int constants 0, 1, 2, 3, 6, 8 now present opt::analysis::IntConstant int_constant_0(registered_type_signed_int, {0}); opt::analysis::IntConstant int_constant_1(registered_type_signed_int, {1}); opt::analysis::IntConstant int_constant_2(registered_type_signed_int, {2}); opt::analysis::IntConstant int_constant_3(registered_type_signed_int, {3}); opt::analysis::IntConstant int_constant_6(registered_type_signed_int, {6}); opt::analysis::IntConstant int_constant_8(registered_type_signed_int, {8}); ASSERT_NE(nullptr, context->get_constant_mgr()->FindConstant(&int_constant_0)); ASSERT_NE(nullptr, context->get_constant_mgr()->FindConstant(&int_constant_1)); ASSERT_NE(nullptr, context->get_constant_mgr()->FindConstant(&int_constant_2)); ASSERT_NE(nullptr, context->get_constant_mgr()->FindConstant(&int_constant_3)); ASSERT_NE(nullptr, context->get_constant_mgr()->FindConstant(&int_constant_6)); ASSERT_NE(nullptr, context->get_constant_mgr()->FindConstant(&int_constant_8)); } } } // namespace } // namespace fuzz } // namespace spvtools