Path: blob/main_old/src/tests/compiler_tests/ExpressionLimit_test.cpp
1693 views
//1// Copyright 2002 The ANGLE Project Authors. All rights reserved.2// Use of this source code is governed by a BSD-style license that can be3// found in the LICENSE file.4//5#include <sstream>6#include <string>7#include <vector>8#include "GLSLANG/ShaderLang.h"9#include "angle_gl.h"10#include "gtest/gtest.h"1112class ExpressionLimitTest : public testing::Test13{14protected:15static const int kMaxExpressionComplexity = 16;16static const int kMaxCallStackDepth = 16;17static const int kMaxFunctionParameters = 16;18static const char *kExpressionTooComplex;19static const char *kCallStackTooDeep;20static const char *kHasRecursion;21static const char *kTooManyParameters;22static const char *kTooComplexSwitch;23static const char *kGlobalVariableInit;2425virtual void SetUp()26{27memset(&resources, 0, sizeof(resources));2829GenerateResources(&resources);30}3132// Set up the per compile resources33static void GenerateResources(ShBuiltInResources *res)34{35sh::InitBuiltInResources(res);3637res->MaxVertexAttribs = 8;38res->MaxVertexUniformVectors = 128;39res->MaxVaryingVectors = 8;40res->MaxVertexTextureImageUnits = 0;41res->MaxCombinedTextureImageUnits = 8;42res->MaxTextureImageUnits = 8;43res->MaxFragmentUniformVectors = 16;44res->MaxDrawBuffers = 1;4546res->OES_standard_derivatives = 0;47res->OES_EGL_image_external = 0;4849res->MaxExpressionComplexity = kMaxExpressionComplexity;50res->MaxCallStackDepth = kMaxCallStackDepth;51res->MaxFunctionParameters = kMaxFunctionParameters;52}5354static void GenerateLongExpression(int length, std::stringstream *ss)55{56for (int ii = 0; ii < length; ++ii)57{58*ss << "+ vec4(" << ii << ")";59}60}6162static std::string GenerateShaderWithLongExpression(int length)63{64static const char *shaderStart =65R"(precision mediump float;66uniform vec4 u_color;67void main()68{69gl_FragColor = u_color70)";7172std::stringstream ss;73ss << shaderStart;74GenerateLongExpression(length, &ss);75ss << "; }";7677return ss.str();78}7980static std::string GenerateShaderWithUnusedLongExpression(int length)81{82static const char *shaderStart =83R"(precision mediump float;84uniform vec4 u_color;85void main()86{87gl_FragColor = u_color;88}89vec4 someFunction() {90return u_color91)";9293std::stringstream ss;9495ss << shaderStart;96GenerateLongExpression(length, &ss);97ss << "; }";9899return ss.str();100}101102static void GenerateDeepFunctionStack(int length, std::stringstream *ss)103{104static const char *shaderStart =105R"(precision mediump float;106uniform vec4 u_color;107vec4 function0() {108return u_color;109}110)";111112*ss << shaderStart;113for (int ii = 0; ii < length; ++ii)114{115*ss << "vec4 function" << (ii + 1) << "() {\n"116<< " return function" << ii << "();\n"117<< "}\n";118}119}120121static std::string GenerateShaderWithDeepFunctionStack(int length)122{123std::stringstream ss;124125GenerateDeepFunctionStack(length, &ss);126127ss << "void main() {\n"128<< " gl_FragColor = function" << length << "();\n"129<< "}";130131return ss.str();132}133134static std::string GenerateShaderWithUnusedDeepFunctionStack(int length)135{136std::stringstream ss;137138GenerateDeepFunctionStack(length, &ss);139140ss << "void main() {\n"141<< " gl_FragColor = vec4(0,0,0,0);\n"142<< "}";143144return ss.str();145}146147static std::string GenerateShaderWithFunctionParameters(int parameters)148{149std::stringstream ss;150151ss << "precision mediump float;\n"152<< "\n"153<< "float foo(";154for (int i = 0; i < parameters; ++i)155{156ss << "float f" << i;157if (i + 1 < parameters)158{159ss << ", ";160}161}162ss << ")\n"163<< "{\n"164<< " return f0;\n"165<< "}\n"166<< "\n"167<< "void main()\n"168<< "{\n"169<< " gl_FragColor = vec4(0,0,0,0);\n"170<< "}";171172return ss.str();173}174175static std::string GenerateShaderWithNestingInsideSwitch(int nesting)176{177std::stringstream shaderString;178shaderString <<179R"(#version 300 es180uniform int u;181182void main()183{184int x;185switch (u)186{187case 0:188x = x)";189for (int i = 0; i < nesting; ++i)190{191shaderString << " + x";192}193shaderString <<194R"(;195} // switch (u)196})";197return shaderString.str();198}199200static std::string GenerateShaderWithNestingInsideGlobalInitializer(int nesting)201{202std::stringstream shaderString;203shaderString <<204R"(uniform int u;205int x = u)";206207for (int i = 0; i < nesting; ++i)208{209shaderString << " + u";210}211shaderString << R"(;212void main()213{214gl_FragColor = vec4(0.0);215})";216return shaderString.str();217}218219// Compiles a shader and if there's an error checks for a specific220// substring in the error log. This way we know the error is specific221// to the issue we are testing.222bool CheckShaderCompilation(ShHandle compiler,223const char *source,224ShCompileOptions compileOptions,225const char *expected_error)226{227bool success = sh::Compile(compiler, &source, 1, compileOptions) != 0;228if (success)229{230success = !expected_error;231}232else233{234std::string log = sh::GetInfoLog(compiler);235if (expected_error)236success = log.find(expected_error) != std::string::npos;237238EXPECT_TRUE(success) << log << "\n----shader----\n" << source;239}240return success;241}242243ShBuiltInResources resources;244};245246const char *ExpressionLimitTest::kExpressionTooComplex = "Expression too complex";247const char *ExpressionLimitTest::kCallStackTooDeep = "Call stack too deep";248const char *ExpressionLimitTest::kHasRecursion =249"Recursive function call in the following call chain";250const char *ExpressionLimitTest::kTooManyParameters = "Function has too many parameters";251const char *ExpressionLimitTest::kTooComplexSwitch =252"too complex expressions inside a switch statement";253const char *ExpressionLimitTest::kGlobalVariableInit =254"global variable initializers must be constant expressions";255256TEST_F(ExpressionLimitTest, ExpressionComplexity)257{258ShShaderSpec spec = SH_WEBGL_SPEC;259ShShaderOutput output = SH_ESSL_OUTPUT;260ShHandle vertexCompiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &resources);261ShCompileOptions compileOptions = SH_LIMIT_EXPRESSION_COMPLEXITY;262263// Test expression under the limit passes.264EXPECT_TRUE(CheckShaderCompilation(265vertexCompiler, GenerateShaderWithLongExpression(kMaxExpressionComplexity - 10).c_str(),266compileOptions, nullptr));267// Test expression over the limit fails.268EXPECT_TRUE(CheckShaderCompilation(269vertexCompiler, GenerateShaderWithLongExpression(kMaxExpressionComplexity + 10).c_str(),270compileOptions, kExpressionTooComplex));271// Test expression over the limit without a limit does not fail.272EXPECT_TRUE(CheckShaderCompilation(273vertexCompiler, GenerateShaderWithLongExpression(kMaxExpressionComplexity + 10).c_str(),274compileOptions & ~SH_LIMIT_EXPRESSION_COMPLEXITY, nullptr));275sh::Destruct(vertexCompiler);276}277278TEST_F(ExpressionLimitTest, UnusedExpressionComplexity)279{280ShShaderSpec spec = SH_WEBGL_SPEC;281ShShaderOutput output = SH_ESSL_OUTPUT;282ShHandle vertexCompiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &resources);283ShCompileOptions compileOptions = SH_LIMIT_EXPRESSION_COMPLEXITY;284285// Test expression under the limit passes.286EXPECT_TRUE(CheckShaderCompilation(287vertexCompiler,288GenerateShaderWithUnusedLongExpression(kMaxExpressionComplexity - 10).c_str(),289compileOptions, nullptr));290// Test expression over the limit fails.291EXPECT_TRUE(CheckShaderCompilation(292vertexCompiler,293GenerateShaderWithUnusedLongExpression(kMaxExpressionComplexity + 10).c_str(),294compileOptions, kExpressionTooComplex));295// Test expression over the limit without a limit does not fail.296EXPECT_TRUE(CheckShaderCompilation(297vertexCompiler,298GenerateShaderWithUnusedLongExpression(kMaxExpressionComplexity + 10).c_str(),299compileOptions & ~SH_LIMIT_EXPRESSION_COMPLEXITY, nullptr));300sh::Destruct(vertexCompiler);301}302303TEST_F(ExpressionLimitTest, CallStackDepth)304{305ShShaderSpec spec = SH_WEBGL_SPEC;306ShShaderOutput output = SH_ESSL_OUTPUT;307ShHandle vertexCompiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &resources);308ShCompileOptions compileOptions = SH_LIMIT_CALL_STACK_DEPTH;309310// Test call stack under the limit passes.311EXPECT_TRUE(CheckShaderCompilation(312vertexCompiler, GenerateShaderWithDeepFunctionStack(kMaxCallStackDepth - 10).c_str(),313compileOptions, nullptr));314// Test call stack over the limit fails.315EXPECT_TRUE(CheckShaderCompilation(316vertexCompiler, GenerateShaderWithDeepFunctionStack(kMaxCallStackDepth + 10).c_str(),317compileOptions, kCallStackTooDeep));318// Test call stack over the limit without limit does not fail.319EXPECT_TRUE(CheckShaderCompilation(320vertexCompiler, GenerateShaderWithDeepFunctionStack(kMaxCallStackDepth + 10).c_str(),321compileOptions & ~SH_LIMIT_CALL_STACK_DEPTH, nullptr));322sh::Destruct(vertexCompiler);323}324325TEST_F(ExpressionLimitTest, UnusedCallStackDepth)326{327ShShaderSpec spec = SH_WEBGL_SPEC;328ShShaderOutput output = SH_ESSL_OUTPUT;329ShHandle vertexCompiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &resources);330ShCompileOptions compileOptions = SH_LIMIT_CALL_STACK_DEPTH;331332// Test call stack under the limit passes.333EXPECT_TRUE(CheckShaderCompilation(334vertexCompiler, GenerateShaderWithUnusedDeepFunctionStack(kMaxCallStackDepth - 10).c_str(),335compileOptions, nullptr));336// Test call stack over the limit fails.337EXPECT_TRUE(CheckShaderCompilation(338vertexCompiler, GenerateShaderWithUnusedDeepFunctionStack(kMaxCallStackDepth + 10).c_str(),339compileOptions, kCallStackTooDeep));340// Test call stack over the limit without limit does not fail.341EXPECT_TRUE(CheckShaderCompilation(342vertexCompiler, GenerateShaderWithUnusedDeepFunctionStack(kMaxCallStackDepth + 10).c_str(),343compileOptions & ~SH_LIMIT_CALL_STACK_DEPTH, nullptr));344sh::Destruct(vertexCompiler);345}346347TEST_F(ExpressionLimitTest, Recursion)348{349ShShaderSpec spec = SH_WEBGL_SPEC;350ShShaderOutput output = SH_ESSL_OUTPUT;351ShHandle vertexCompiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &resources);352ShCompileOptions compileOptions = 0;353354static const char *shaderWithRecursion0 =355R"(precision mediump float;356uniform vec4 u_color;357vec4 someFunc() {358return someFunc();359}360361void main() {362gl_FragColor = u_color * someFunc();363}364)";365366static const char *shaderWithRecursion1 =367R"(precision mediump float;368uniform vec4 u_color;369370vec4 someFunc();371372vec4 someFunc1() {373return someFunc();374}375376vec4 someFunc() {377return someFunc1();378}379380void main() {381gl_FragColor = u_color * someFunc();382}383)";384385static const char *shaderWithRecursion2 =386R"(precision mediump float;387uniform vec4 u_color;388vec4 someFunc() {389if (u_color.x > 0.5) {390return someFunc();391} else {392return vec4(1);393}394}395396void main() {397gl_FragColor = someFunc();398}399)";400401static const char *shaderWithRecursion3 =402R"(precision mediump float;403uniform vec4 u_color;404vec4 someFunc() {405if (u_color.x > 0.5) {406return vec4(1);407} else {408return someFunc();409}410}411412void main() {413gl_FragColor = someFunc();414}415)";416417static const char *shaderWithRecursion4 =418R"(precision mediump float;419uniform vec4 u_color;420vec4 someFunc() {421return (u_color.x > 0.5) ? vec4(1) : someFunc();422}423424void main() {425gl_FragColor = someFunc();426}427)";428429static const char *shaderWithRecursion5 =430R"(precision mediump float;431uniform vec4 u_color;432vec4 someFunc() {433return (u_color.x > 0.5) ? someFunc() : vec4(1);434}435436void main() {437gl_FragColor = someFunc();438}439)";440441static const char *shaderWithRecursion6 =442R"(precision mediump float;443uniform vec4 u_color;444vec4 someFunc() {445return someFunc();446}447448void main() {449gl_FragColor = u_color;450}451)";452453static const char *shaderWithNoRecursion =454R"(precision mediump float;455uniform vec4 u_color;456457vec3 rgb(int r, int g, int b) {458return vec3(float(r) / 255.0, float(g) / 255.0, float(b) / 255.0);459}460461void main() {462vec3 hairColor0 = rgb(151, 200, 234);463vec3 faceColor2 = rgb(183, 148, 133);464gl_FragColor = u_color + vec4(hairColor0 + faceColor2, 0);465}466)";467468static const char *shaderWithRecursion7 =469R"(precision mediump float;470uniform vec4 u_color;471472vec4 function2() {473return u_color;474}475476vec4 function1() {477vec4 a = function2();478vec4 b = function1();479return a + b;480}481482void main() {483gl_FragColor = function1();484}485)";486487static const char *shaderWithRecursion8 =488R"(precision mediump float;489uniform vec4 u_color;490491vec4 function1();492493vec4 function3() {494return function1();495}496497vec4 function2() {498return function3();499}500501vec4 function1() {502return function2();503}504505void main() {506gl_FragColor = function1();507}508)";509510// Check simple recursions fails.511EXPECT_TRUE(CheckShaderCompilation(vertexCompiler, shaderWithRecursion0, compileOptions,512kHasRecursion));513// Check simple recursions fails.514EXPECT_TRUE(CheckShaderCompilation(vertexCompiler, shaderWithRecursion1, compileOptions,515kHasRecursion));516// Check if recursions fails.517EXPECT_TRUE(CheckShaderCompilation(vertexCompiler, shaderWithRecursion2, compileOptions,518kHasRecursion));519// Check if recursions fails.520EXPECT_TRUE(CheckShaderCompilation(vertexCompiler, shaderWithRecursion3, compileOptions,521kHasRecursion));522// Check ternary recursions fails.523EXPECT_TRUE(CheckShaderCompilation(vertexCompiler, shaderWithRecursion4, compileOptions,524kHasRecursion));525// Check ternary recursions fails.526EXPECT_TRUE(CheckShaderCompilation(vertexCompiler, shaderWithRecursion5, compileOptions,527kHasRecursion));528529// Check some more forms of recursion530EXPECT_TRUE(CheckShaderCompilation(vertexCompiler, shaderWithRecursion6, compileOptions,531kHasRecursion));532EXPECT_TRUE(CheckShaderCompilation(vertexCompiler, shaderWithRecursion7, compileOptions,533kHasRecursion));534EXPECT_TRUE(CheckShaderCompilation(vertexCompiler, shaderWithRecursion8, compileOptions,535kHasRecursion));536// Check unused recursions fails if limiting call stack537// since we check all paths.538EXPECT_TRUE(CheckShaderCompilation(vertexCompiler, shaderWithRecursion6,539compileOptions | SH_LIMIT_CALL_STACK_DEPTH, kHasRecursion));540541// Check unused recursions passes.542EXPECT_TRUE(543CheckShaderCompilation(vertexCompiler, shaderWithNoRecursion, compileOptions, nullptr));544// Check unused recursions passes if limiting call stack.545EXPECT_TRUE(CheckShaderCompilation(vertexCompiler, shaderWithNoRecursion,546compileOptions | SH_LIMIT_CALL_STACK_DEPTH, nullptr));547sh::Destruct(vertexCompiler);548}549550TEST_F(ExpressionLimitTest, FunctionParameterCount)551{552ShShaderSpec spec = SH_WEBGL_SPEC;553ShShaderOutput output = SH_ESSL_OUTPUT;554ShHandle compiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &resources);555ShCompileOptions compileOptions = SH_LIMIT_EXPRESSION_COMPLEXITY;556557// Test parameters under the limit succeeds.558EXPECT_TRUE(CheckShaderCompilation(559compiler, GenerateShaderWithFunctionParameters(kMaxFunctionParameters).c_str(),560compileOptions, nullptr));561// Test parameters over the limit fails.562EXPECT_TRUE(CheckShaderCompilation(563compiler, GenerateShaderWithFunctionParameters(kMaxFunctionParameters + 1).c_str(),564compileOptions, kTooManyParameters));565// Test parameters over the limit without limit does not fail.566EXPECT_TRUE(CheckShaderCompilation(567compiler, GenerateShaderWithFunctionParameters(kMaxFunctionParameters + 1).c_str(),568compileOptions & ~SH_LIMIT_EXPRESSION_COMPLEXITY, nullptr));569sh::Destruct(compiler);570}571572TEST_F(ExpressionLimitTest, NestingInsideSwitch)573{574ShShaderSpec spec = SH_WEBGL2_SPEC;575ShShaderOutput output = SH_ESSL_OUTPUT;576ShHandle compiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &resources);577ShCompileOptions compileOptions = SH_LIMIT_EXPRESSION_COMPLEXITY;578579// Test nesting over the limit fails.580EXPECT_TRUE(CheckShaderCompilation(581compiler, GenerateShaderWithNestingInsideSwitch(kMaxExpressionComplexity + 1).c_str(),582compileOptions, kExpressionTooComplex));583// Test nesting over the limit without limit does not fail.584EXPECT_TRUE(CheckShaderCompilation(585compiler, GenerateShaderWithNestingInsideSwitch(kMaxExpressionComplexity + 1).c_str(),586compileOptions & ~SH_LIMIT_EXPRESSION_COMPLEXITY, nullptr));587// Test that nesting way over the limit doesn't cause stack overflow but is handled588// gracefully.589EXPECT_TRUE(CheckShaderCompilation(compiler,590GenerateShaderWithNestingInsideSwitch(5000).c_str(),591compileOptions, kTooComplexSwitch));592sh::Destruct(compiler);593}594595TEST_F(ExpressionLimitTest, NestingInsideGlobalInitializer)596{597ShShaderSpec spec = SH_WEBGL_SPEC;598ShShaderOutput output = SH_ESSL_OUTPUT;599ShHandle compiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &resources);600ShCompileOptions compileOptions = SH_LIMIT_EXPRESSION_COMPLEXITY;601602// Test nesting over the limit fails.603EXPECT_TRUE(CheckShaderCompilation(604compiler,605GenerateShaderWithNestingInsideGlobalInitializer(kMaxExpressionComplexity + 1).c_str(),606compileOptions, kExpressionTooComplex));607// Test nesting over the limit without limit does not fail.608EXPECT_TRUE(CheckShaderCompilation(609compiler,610GenerateShaderWithNestingInsideGlobalInitializer(kMaxExpressionComplexity + 1).c_str(),611compileOptions & ~SH_LIMIT_EXPRESSION_COMPLEXITY, nullptr));612// Test that nesting way over the limit doesn't cause stack overflow but is handled613// gracefully.614EXPECT_TRUE(CheckShaderCompilation(615compiler, GenerateShaderWithNestingInsideGlobalInitializer(5000).c_str(), compileOptions,616kGlobalVariableInit));617sh::Destruct(compiler);618}619620621