Add expression complexity and call stack depth limits.

git-svn-id: https://angleproject.googlecode.com/svn/trunk@2242 736b8ea6-26fd-11df-bfd4-992fa37f6226

TRAC #23333
Authored-by: gman@chromium.org
Signed-off-by: Shannon Woods
Signed-off-by Nicolas Capens
Merged-by: Jamie Madill
Conflicts:

	src/common/version.h
diff --git a/src/compiler/Compiler.cpp b/src/compiler/Compiler.cpp
index d39d921..c7c792c 100644
--- a/src/compiler/Compiler.cpp
+++ b/src/compiler/Compiler.cpp
@@ -5,7 +5,7 @@
 //
 
 #include "compiler/BuiltInFunctionEmulator.h"
-#include "compiler/DetectRecursion.h"
+#include "compiler/DetectCallDepth.h"
 #include "compiler/ForLoopUnroll.h"
 #include "compiler/Initialize.h"
 #include "compiler/InitializeParseContext.h"
@@ -59,6 +59,9 @@
 TCompiler::TCompiler(ShShaderType type, ShShaderSpec spec)
     : shaderType(type),
       shaderSpec(spec),
+      maxUniformVectors(0),
+      maxExpressionComplexity(0),
+      maxCallStackDepth(0),
       fragmentPrecisionHigh(false),
       clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC),
       builtInFunctionEmulator(type)
@@ -78,6 +81,8 @@
     maxUniformVectors = (shaderType == SH_VERTEX_SHADER) ?
         resources.MaxVertexUniformVectors :
         resources.MaxFragmentUniformVectors;
+    maxExpressionComplexity = resources.MaxExpressionComplexity;
+    maxCallStackDepth = resources.MaxCallStackDepth;
     TScopedPoolAllocator scopedAlloc(&allocator, false);
 
     // Generate built-in symbol table.
@@ -144,7 +149,7 @@
         success = intermediate.postProcess(root);
 
         if (success)
-            success = detectRecursion(root);
+            success = detectCallDepth(root, infoSink, (compileOptions & SH_LIMIT_CALL_STACK_DEPTH) != 0);
 
         if (success && shaderVersion == 300 && shaderType == SH_FRAGMENT_SHADER)
             success = validateOutputs(root);
@@ -170,6 +175,10 @@
         if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS))
             arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root);
 
+        // Disallow expressions deemed too complex.
+        if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY))
+            success = limitExpressionComplexity(root);
+
         // Call mapLongVariableNames() before collectAttribsUniforms() so in
         // collectAttribsUniforms() we already have the mapped symbol names and
         // we could composite mapped and original variable names.
@@ -260,21 +269,25 @@
     nameMap.clear();
 }
 
-bool TCompiler::detectRecursion(TIntermNode* root)
+bool TCompiler::detectCallDepth(TIntermNode* root, TInfoSink& infoSink, bool limitCallStackDepth)
 {
-    DetectRecursion detect;
+    DetectCallDepth detect(infoSink, limitCallStackDepth, maxCallStackDepth);
     root->traverse(&detect);
-    switch (detect.detectRecursion()) {
-        case DetectRecursion::kErrorNone:
+    switch (detect.detectCallDepth()) {
+        case DetectCallDepth::kErrorNone:
             return true;
-        case DetectRecursion::kErrorMissingMain:
+        case DetectCallDepth::kErrorMissingMain:
             infoSink.info.prefix(EPrefixError);
             infoSink.info << "Missing main()";
             return false;
-        case DetectRecursion::kErrorRecursion:
+        case DetectCallDepth::kErrorRecursion:
             infoSink.info.prefix(EPrefixError);
             infoSink.info << "Function recursion detected";
             return false;
+        case DetectCallDepth::kErrorMaxDepthExceeded:
+            infoSink.info.prefix(EPrefixError);
+            infoSink.info << "Function call stack too deep";
+            return false;
         default:
             UNREACHABLE();
             return false;
@@ -326,6 +339,28 @@
     }
 }
 
+bool TCompiler::limitExpressionComplexity(TIntermNode* root)
+{
+    TIntermTraverser traverser;
+    root->traverse(&traverser);
+    TDependencyGraph graph(root);
+
+    for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls();
+         iter != graph.endUserDefinedFunctionCalls();
+         ++iter)
+    {
+        TGraphFunctionCall* samplerSymbol = *iter;
+        TDependencyGraphTraverser graphTraverser;
+        samplerSymbol->traverse(&graphTraverser);
+    }
+
+    if (traverser.getMaxDepth() > maxExpressionComplexity) {
+        infoSink.info << "Expression too complex.";
+        return false;
+    }
+    return true;
+}
+
 bool TCompiler::enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph)
 {
     RestrictFragmentShaderTiming restrictor(infoSink.info);