1 // 2 // Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 #include <sstream> 7 #include <string> 8 #include <vector> 9 #include "angle_gl.h" 10 #include "gtest/gtest.h" 11 #include "GLSLANG/ShaderLang.h" 12 13 #define SHADER(Src) #Src 14 15 class ExpressionLimitTest : public testing::Test { 16 protected: 17 static const int kMaxExpressionComplexity = 16; 18 static const int kMaxCallStackDepth = 16; 19 static const int kMaxFunctionParameters = 16; 20 static const char* kExpressionTooComplex; 21 static const char* kCallStackTooDeep; 22 static const char* kHasRecursion; 23 static const char *kTooManyParameters; 24 SetUp()25 virtual void SetUp() 26 { 27 memset(&resources, 0, sizeof(resources)); 28 29 GenerateResources(&resources); 30 } 31 32 // Set up the per compile resources GenerateResources(ShBuiltInResources * res)33 static void GenerateResources(ShBuiltInResources *res) 34 { 35 sh::InitBuiltInResources(res); 36 37 res->MaxVertexAttribs = 8; 38 res->MaxVertexUniformVectors = 128; 39 res->MaxVaryingVectors = 8; 40 res->MaxVertexTextureImageUnits = 0; 41 res->MaxCombinedTextureImageUnits = 8; 42 res->MaxTextureImageUnits = 8; 43 res->MaxFragmentUniformVectors = 16; 44 res->MaxDrawBuffers = 1; 45 46 res->OES_standard_derivatives = 0; 47 res->OES_EGL_image_external = 0; 48 49 res->MaxExpressionComplexity = kMaxExpressionComplexity; 50 res->MaxCallStackDepth = kMaxCallStackDepth; 51 res->MaxFunctionParameters = kMaxFunctionParameters; 52 } 53 GenerateLongExpression(int length,std::stringstream * ss)54 void GenerateLongExpression(int length, std::stringstream* ss) 55 { 56 for (int ii = 0; ii < length; ++ii) { 57 *ss << "+ vec4(" << ii << ")"; 58 } 59 } 60 GenerateShaderWithLongExpression(int length)61 std::string GenerateShaderWithLongExpression(int length) 62 { 63 static const char* shaderStart = SHADER( 64 precision mediump float; 65 uniform vec4 u_color; 66 void main() 67 { 68 gl_FragColor = u_color 69 ); 70 71 std::stringstream ss; 72 ss << shaderStart; 73 GenerateLongExpression(length, &ss); 74 ss << "; }"; 75 76 return ss.str(); 77 } 78 79 std::string GenerateShaderWithUnusedLongExpression(int length) 80 { 81 static const char* shaderStart = SHADER( 82 precision mediump float; 83 uniform vec4 u_color; 84 void main() 85 { 86 gl_FragColor = u_color; 87 } 88 vec4 someFunction() { 89 return u_color 90 ); 91 92 std::stringstream ss; 93 94 ss << shaderStart; 95 GenerateLongExpression(length, &ss); 96 ss << "; }"; 97 98 return ss.str(); 99 } 100 101 void GenerateDeepFunctionStack(int length, std::stringstream* ss) 102 { 103 static const char* shaderStart = SHADER( 104 precision mediump float; 105 uniform vec4 u_color; 106 vec4 function0() { 107 return u_color; 108 } 109 ); 110 111 *ss << shaderStart; 112 for (int ii = 0; ii < length; ++ii) { 113 *ss << "vec4 function" << (ii + 1) << "() {\n" 114 << " return function" << ii << "();\n" 115 << "}\n"; 116 } 117 } 118 119 std::string GenerateShaderWithDeepFunctionStack(int length) 120 { 121 std::stringstream ss; 122 123 GenerateDeepFunctionStack(length, &ss); 124 125 ss << "void main() {\n" 126 << " gl_FragColor = function" << length << "();\n" 127 << "}"; 128 129 return ss.str(); 130 } 131 132 std::string GenerateShaderWithUnusedDeepFunctionStack(int length) 133 { 134 std::stringstream ss; 135 136 GenerateDeepFunctionStack(length, &ss); 137 138 ss << "void main() {\n" 139 << " gl_FragColor = vec4(0,0,0,0);\n" 140 << "}"; 141 142 143 return ss.str(); 144 } 145 146 std::string GenerateShaderWithFunctionParameters(int parameters) 147 { 148 std::stringstream ss; 149 150 ss << "precision mediump float;\n" 151 << "\n" 152 << "float foo("; 153 for (int i = 0; i < parameters; ++i) 154 { 155 ss << "float f" << i; 156 if (i + 1 < parameters) 157 { 158 ss << ", "; 159 } 160 } 161 ss << ")\n" 162 << "{\n" 163 << " return f0;\n" 164 << "}\n" 165 << "\n" 166 << "void main()\n" 167 << "{\n" 168 << " gl_FragColor = vec4(0,0,0,0);\n" 169 << "}"; 170 171 return ss.str(); 172 } 173 174 // Compiles a shader and if there's an error checks for a specific 175 // substring in the error log. This way we know the error is specific 176 // to the issue we are testing. 177 bool CheckShaderCompilation(ShHandle compiler, 178 const char *source, 179 ShCompileOptions compileOptions, 180 const char *expected_error) 181 { 182 bool success = sh::Compile(compiler, &source, 1, compileOptions) != 0; 183 if (success) 184 { 185 success = !expected_error; 186 } 187 else 188 { 189 std::string log = sh::GetInfoLog(compiler); 190 if (expected_error) 191 success = log.find(expected_error) != std::string::npos; 192 193 EXPECT_TRUE(success) << log << "\n----shader----\n" << source; 194 } 195 return success; 196 } 197 198 ShBuiltInResources resources; 199 }; 200 201 const char* ExpressionLimitTest::kExpressionTooComplex = 202 "Expression too complex"; 203 const char* ExpressionLimitTest::kCallStackTooDeep = 204 "Call stack too deep"; 205 const char* ExpressionLimitTest::kHasRecursion = 206 "Function recursion detected"; 207 const char* ExpressionLimitTest::kTooManyParameters = 208 "Function has too many parameters"; 209 210 TEST_F(ExpressionLimitTest, ExpressionComplexity) 211 { 212 ShShaderSpec spec = SH_WEBGL_SPEC; 213 ShShaderOutput output = SH_ESSL_OUTPUT; 214 ShHandle vertexCompiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &resources); 215 ShCompileOptions compileOptions = SH_LIMIT_EXPRESSION_COMPLEXITY; 216 217 // Test expression under the limit passes. 218 EXPECT_TRUE(CheckShaderCompilation( 219 vertexCompiler, 220 GenerateShaderWithLongExpression( 221 kMaxExpressionComplexity - 10).c_str(), 222 compileOptions, NULL)); 223 // Test expression over the limit fails. 224 EXPECT_TRUE(CheckShaderCompilation( 225 vertexCompiler, 226 GenerateShaderWithLongExpression( 227 kMaxExpressionComplexity + 10).c_str(), 228 compileOptions, kExpressionTooComplex)); 229 // Test expression over the limit without a limit does not fail. 230 EXPECT_TRUE(CheckShaderCompilation( 231 vertexCompiler, 232 GenerateShaderWithLongExpression( 233 kMaxExpressionComplexity + 10).c_str(), 234 compileOptions & ~SH_LIMIT_EXPRESSION_COMPLEXITY, NULL)); 235 sh::Destruct(vertexCompiler); 236 } 237 238 TEST_F(ExpressionLimitTest, UnusedExpressionComplexity) 239 { 240 ShShaderSpec spec = SH_WEBGL_SPEC; 241 ShShaderOutput output = SH_ESSL_OUTPUT; 242 ShHandle vertexCompiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &resources); 243 ShCompileOptions compileOptions = SH_LIMIT_EXPRESSION_COMPLEXITY; 244 245 // Test expression under the limit passes. 246 EXPECT_TRUE(CheckShaderCompilation( 247 vertexCompiler, 248 GenerateShaderWithUnusedLongExpression( 249 kMaxExpressionComplexity - 10).c_str(), 250 compileOptions, NULL)); 251 // Test expression over the limit fails. 252 EXPECT_TRUE(CheckShaderCompilation( 253 vertexCompiler, 254 GenerateShaderWithUnusedLongExpression( 255 kMaxExpressionComplexity + 10).c_str(), 256 compileOptions, kExpressionTooComplex)); 257 // Test expression over the limit without a limit does not fail. 258 EXPECT_TRUE(CheckShaderCompilation( 259 vertexCompiler, 260 GenerateShaderWithUnusedLongExpression( 261 kMaxExpressionComplexity + 10).c_str(), 262 compileOptions & ~SH_LIMIT_EXPRESSION_COMPLEXITY, NULL)); 263 sh::Destruct(vertexCompiler); 264 } 265 266 TEST_F(ExpressionLimitTest, CallStackDepth) 267 { 268 ShShaderSpec spec = SH_WEBGL_SPEC; 269 ShShaderOutput output = SH_ESSL_OUTPUT; 270 ShHandle vertexCompiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &resources); 271 ShCompileOptions compileOptions = SH_LIMIT_CALL_STACK_DEPTH; 272 273 // Test call stack under the limit passes. 274 EXPECT_TRUE(CheckShaderCompilation( 275 vertexCompiler, 276 GenerateShaderWithDeepFunctionStack( 277 kMaxCallStackDepth - 10).c_str(), 278 compileOptions, NULL)); 279 // Test call stack over the limit fails. 280 EXPECT_TRUE(CheckShaderCompilation( 281 vertexCompiler, 282 GenerateShaderWithDeepFunctionStack( 283 kMaxCallStackDepth + 10).c_str(), 284 compileOptions, kCallStackTooDeep)); 285 // Test call stack over the limit without limit does not fail. 286 EXPECT_TRUE(CheckShaderCompilation( 287 vertexCompiler, 288 GenerateShaderWithDeepFunctionStack( 289 kMaxCallStackDepth + 10).c_str(), 290 compileOptions & ~SH_LIMIT_CALL_STACK_DEPTH, NULL)); 291 sh::Destruct(vertexCompiler); 292 } 293 294 TEST_F(ExpressionLimitTest, UnusedCallStackDepth) 295 { 296 ShShaderSpec spec = SH_WEBGL_SPEC; 297 ShShaderOutput output = SH_ESSL_OUTPUT; 298 ShHandle vertexCompiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &resources); 299 ShCompileOptions compileOptions = SH_LIMIT_CALL_STACK_DEPTH; 300 301 // Test call stack under the limit passes. 302 EXPECT_TRUE(CheckShaderCompilation( 303 vertexCompiler, 304 GenerateShaderWithUnusedDeepFunctionStack( 305 kMaxCallStackDepth - 10).c_str(), 306 compileOptions, NULL)); 307 // Test call stack over the limit fails. 308 EXPECT_TRUE(CheckShaderCompilation( 309 vertexCompiler, 310 GenerateShaderWithUnusedDeepFunctionStack( 311 kMaxCallStackDepth + 10).c_str(), 312 compileOptions, kCallStackTooDeep)); 313 // Test call stack over the limit without limit does not fail. 314 EXPECT_TRUE(CheckShaderCompilation( 315 vertexCompiler, 316 GenerateShaderWithUnusedDeepFunctionStack( 317 kMaxCallStackDepth + 10).c_str(), 318 compileOptions & ~SH_LIMIT_CALL_STACK_DEPTH, NULL)); 319 sh::Destruct(vertexCompiler); 320 } 321 322 TEST_F(ExpressionLimitTest, Recursion) 323 { 324 ShShaderSpec spec = SH_WEBGL_SPEC; 325 ShShaderOutput output = SH_ESSL_OUTPUT; 326 ShHandle vertexCompiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &resources); 327 ShCompileOptions compileOptions = 0; 328 329 static const char* shaderWithRecursion0 = SHADER( 330 precision mediump float; 331 uniform vec4 u_color; 332 vec4 someFunc() { 333 return someFunc(); 334 } 335 336 void main() { 337 gl_FragColor = u_color * someFunc(); 338 } 339 ); 340 341 static const char* shaderWithRecursion1 = SHADER( 342 precision mediump float; 343 uniform vec4 u_color; 344 345 vec4 someFunc(); 346 347 vec4 someFunc1() { 348 return someFunc(); 349 } 350 351 vec4 someFunc() { 352 return someFunc1(); 353 } 354 355 void main() { 356 gl_FragColor = u_color * someFunc(); 357 } 358 ); 359 360 static const char* shaderWithRecursion2 = SHADER( 361 precision mediump float; 362 uniform vec4 u_color; 363 vec4 someFunc() { 364 if (u_color.x > 0.5) { 365 return someFunc(); 366 } else { 367 return vec4(1); 368 } 369 } 370 371 void main() { 372 gl_FragColor = someFunc(); 373 } 374 ); 375 376 static const char* shaderWithRecursion3 = SHADER( 377 precision mediump float; 378 uniform vec4 u_color; 379 vec4 someFunc() { 380 if (u_color.x > 0.5) { 381 return vec4(1); 382 } else { 383 return someFunc(); 384 } 385 } 386 387 void main() { 388 gl_FragColor = someFunc(); 389 } 390 ); 391 392 static const char* shaderWithRecursion4 = SHADER( 393 precision mediump float; 394 uniform vec4 u_color; 395 vec4 someFunc() { 396 return (u_color.x > 0.5) ? vec4(1) : someFunc(); 397 } 398 399 void main() { 400 gl_FragColor = someFunc(); 401 } 402 ); 403 404 static const char* shaderWithRecursion5 = SHADER( 405 precision mediump float; 406 uniform vec4 u_color; 407 vec4 someFunc() { 408 return (u_color.x > 0.5) ? someFunc() : vec4(1); 409 } 410 411 void main() { 412 gl_FragColor = someFunc(); 413 } 414 ); 415 416 static const char* shaderWithRecursion6 = SHADER( 417 precision mediump float; 418 uniform vec4 u_color; 419 vec4 someFunc() { 420 return someFunc(); 421 } 422 423 void main() { 424 gl_FragColor = u_color; 425 } 426 ); 427 428 static const char* shaderWithNoRecursion = SHADER( 429 precision mediump float; 430 uniform vec4 u_color; 431 432 vec3 rgb(int r, int g, int b) { 433 return vec3(float(r) / 255.0, float(g) / 255.0, float(b) / 255.0); 434 } 435 436 void main() { 437 vec3 hairColor0 = rgb(151, 200, 234); 438 vec3 faceColor2 = rgb(183, 148, 133); 439 gl_FragColor = u_color + vec4(hairColor0 + faceColor2, 0); 440 } 441 ); 442 443 static const char* shaderWithRecursion7 = SHADER( 444 precision mediump float; 445 uniform vec4 u_color; 446 447 vec4 function2() { 448 return u_color; 449 } 450 451 vec4 function1() { 452 vec4 a = function2(); 453 vec4 b = function1(); 454 return a + b; 455 } 456 457 void main() { 458 gl_FragColor = function1(); 459 } 460 ); 461 462 static const char* shaderWithRecursion8 = SHADER( 463 precision mediump float; 464 uniform vec4 u_color; 465 466 vec4 function1(); 467 468 vec4 function3() { 469 return function1(); 470 } 471 472 vec4 function2() { 473 return function3(); 474 } 475 476 vec4 function1() { 477 return function2(); 478 } 479 480 void main() { 481 gl_FragColor = function1(); 482 } 483 ); 484 485 // Check simple recursions fails. 486 EXPECT_TRUE(CheckShaderCompilation( 487 vertexCompiler, shaderWithRecursion0, 488 compileOptions, kHasRecursion)); 489 // Check simple recursions fails. 490 EXPECT_TRUE(CheckShaderCompilation( 491 vertexCompiler, shaderWithRecursion1, 492 compileOptions, kHasRecursion)); 493 // Check if recursions fails. 494 EXPECT_TRUE(CheckShaderCompilation( 495 vertexCompiler, shaderWithRecursion2, 496 compileOptions, kHasRecursion)); 497 // Check if recursions fails. 498 EXPECT_TRUE(CheckShaderCompilation( 499 vertexCompiler, shaderWithRecursion3, 500 compileOptions, kHasRecursion)); 501 // Check ternary recursions fails. 502 EXPECT_TRUE(CheckShaderCompilation( 503 vertexCompiler, shaderWithRecursion4, 504 compileOptions, kHasRecursion)); 505 // Check ternary recursions fails. 506 EXPECT_TRUE(CheckShaderCompilation( 507 vertexCompiler, shaderWithRecursion5, 508 compileOptions, kHasRecursion)); 509 510 // Check some more forms of recursion 511 EXPECT_TRUE(CheckShaderCompilation( 512 vertexCompiler, shaderWithRecursion6, 513 compileOptions, kHasRecursion)); 514 EXPECT_TRUE(CheckShaderCompilation( 515 vertexCompiler, shaderWithRecursion7, 516 compileOptions, kHasRecursion)); 517 EXPECT_TRUE(CheckShaderCompilation( 518 vertexCompiler, shaderWithRecursion8, 519 compileOptions, kHasRecursion)); 520 // Check unused recursions fails if limiting call stack 521 // since we check all paths. 522 EXPECT_TRUE(CheckShaderCompilation( 523 vertexCompiler, shaderWithRecursion6, 524 compileOptions | SH_LIMIT_CALL_STACK_DEPTH, kHasRecursion)); 525 526 // Check unused recursions passes. 527 EXPECT_TRUE(CheckShaderCompilation( 528 vertexCompiler, shaderWithNoRecursion, 529 compileOptions, NULL)); 530 // Check unused recursions passes if limiting call stack. 531 EXPECT_TRUE(CheckShaderCompilation( 532 vertexCompiler, shaderWithNoRecursion, 533 compileOptions | SH_LIMIT_CALL_STACK_DEPTH, NULL)); 534 sh::Destruct(vertexCompiler); 535 } 536 537 TEST_F(ExpressionLimitTest, FunctionParameterCount) 538 { 539 ShShaderSpec spec = SH_WEBGL_SPEC; 540 ShShaderOutput output = SH_ESSL_OUTPUT; 541 ShHandle compiler = sh::ConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &resources); 542 ShCompileOptions compileOptions = SH_LIMIT_EXPRESSION_COMPLEXITY; 543 544 // Test parameters under the limit succeeds. 545 EXPECT_TRUE(CheckShaderCompilation( 546 compiler, GenerateShaderWithFunctionParameters(kMaxFunctionParameters).c_str(), 547 compileOptions, nullptr)); 548 // Test parameters over the limit fails. 549 EXPECT_TRUE(CheckShaderCompilation( 550 compiler, GenerateShaderWithFunctionParameters(kMaxFunctionParameters + 1).c_str(), 551 compileOptions, kTooManyParameters)); 552 // Test parameters over the limit without limit does not fail. 553 EXPECT_TRUE(CheckShaderCompilation( 554 compiler, GenerateShaderWithFunctionParameters(kMaxFunctionParameters + 1).c_str(), 555 compileOptions & ~SH_LIMIT_EXPRESSION_COMPLEXITY, nullptr)); 556 sh::Destruct(compiler); 557 } 558