Commit d0c82d5e by Jamie Madill

Fix stack overflow when parsing huge expressions.

The expression limit validation check needs to be in front of other tree traversal to prevent stack overflows. Also, call depths of sufficient size (80k+) could overflow the depth check itself, necessitating an upper bound on initial tree traversal. This fixes crashes in the WebGL long-expressions bug test. BUG=angle:584 Change-Id: Ib48294bf77a5923d230f237fbd63a36a5662e317 Reviewed-on: https://chromium-review.googlesource.com/190051Reviewed-by: 's avatarZhenyao Mo <zmo@chromium.org> Reviewed-by: 's avatarNicolas Capens <nicolascapens@chromium.org> Tested-by: 's avatarJamie Madill <jmadill@chromium.org>
parent b16827b0
...@@ -160,6 +160,10 @@ bool TCompiler::compile(const char* const shaderStrings[], ...@@ -160,6 +160,10 @@ bool TCompiler::compile(const char* const shaderStrings[],
TIntermNode* root = parseContext.treeRoot; TIntermNode* root = parseContext.treeRoot;
success = intermediate.postProcess(root); success = intermediate.postProcess(root);
// Disallow expressions deemed too complex.
if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY))
success = limitExpressionComplexity(root);
if (success) if (success)
success = detectCallDepth(root, infoSink, (compileOptions & SH_LIMIT_CALL_STACK_DEPTH) != 0); success = detectCallDepth(root, infoSink, (compileOptions & SH_LIMIT_CALL_STACK_DEPTH) != 0);
...@@ -198,10 +202,6 @@ bool TCompiler::compile(const char* const shaderStrings[], ...@@ -198,10 +202,6 @@ bool TCompiler::compile(const char* const shaderStrings[],
if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS)) if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS))
arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root); arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root);
// Disallow expressions deemed too complex.
if (success && (compileOptions & SH_LIMIT_EXPRESSION_COMPLEXITY))
success = limitExpressionComplexity(root);
if (success && shaderType == SH_VERTEX_SHADER && (compileOptions & SH_INIT_GL_POSITION)) if (success && shaderType == SH_VERTEX_SHADER && (compileOptions & SH_INIT_GL_POSITION))
initializeGLPosition(root); initializeGLPosition(root);
...@@ -381,8 +381,15 @@ bool TCompiler::enforceTimingRestrictions(TIntermNode* root, bool outputGraph) ...@@ -381,8 +381,15 @@ bool TCompiler::enforceTimingRestrictions(TIntermNode* root, bool outputGraph)
bool TCompiler::limitExpressionComplexity(TIntermNode* root) bool TCompiler::limitExpressionComplexity(TIntermNode* root)
{ {
TIntermTraverser traverser; TMaxDepthTraverser traverser(maxExpressionComplexity+1);
root->traverse(&traverser); root->traverse(&traverser);
if (traverser.getMaxDepth() > maxExpressionComplexity)
{
infoSink.info << "Expression too complex.";
return false;
}
TDependencyGraph graph(root); TDependencyGraph graph(root);
for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls(); for (TFunctionCallVector::const_iterator iter = graph.beginUserDefinedFunctionCalls();
...@@ -394,11 +401,6 @@ bool TCompiler::limitExpressionComplexity(TIntermNode* root) ...@@ -394,11 +401,6 @@ bool TCompiler::limitExpressionComplexity(TIntermNode* root)
samplerSymbol->traverse(&graphTraverser); samplerSymbol->traverse(&graphTraverser);
} }
if (traverser.getMaxDepth() > maxExpressionComplexity)
{
infoSink.info << "Expression too complex.";
return false;
}
return true; return true;
} }
......
...@@ -653,4 +653,30 @@ protected: ...@@ -653,4 +653,30 @@ protected:
TVector<TIntermNode *> path; TVector<TIntermNode *> path;
}; };
//
// For traversing the tree, and computing max depth.
// Takes a maximum depth limit to prevent stack overflow.
//
class TMaxDepthTraverser : public TIntermTraverser
{
public:
POOL_ALLOCATOR_NEW_DELETE();
TMaxDepthTraverser(int depthLimit)
: TIntermTraverser(true, true, false, false),
depthLimit(depthLimit)
{}
virtual bool visitBinary(Visit visit, TIntermBinary*) { return depthCheck(); }
virtual bool visitUnary(Visit visit, TIntermUnary*) { return depthCheck(); }
virtual bool visitSelection(Visit visit, TIntermSelection*) { return depthCheck(); }
virtual bool visitAggregate(Visit visit, TIntermAggregate*) { return depthCheck(); }
virtual bool visitLoop(Visit visit, TIntermLoop*) { return depthCheck(); }
virtual bool visitBranch(Visit visit, TIntermBranch*) { return depthCheck(); }
protected:
int depthLimit;
bool depthCheck() const { return maxDepth < depthLimit; }
};
#endif // __INTERMEDIATE_H #endif // __INTERMEDIATE_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment