Commit 19d1dc99 by Olli Etuaho Committed by Commit Bot

Add option to limit the number of function parameters

Trying to compile user-defined functions that have thousands of parameters introduces some instability in native compilers, so it is better to reject shaders with large numbers of function parameters in ANGLE. The check is only enabled if the SH_LIMIT_EXPRESSION_COMPLEXITY flag is turned on. The default limit for the number of parameters is 1024, but it can also be configured. BUG=angleproject:1338 TEST=angle_unittests Change-Id: I5c9b7a4e97e67f36e77f969368336fa8fffba1c3 Reviewed-on: https://chromium-review.googlesource.com/331970Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Reviewed-by: 's avatarKenneth Russell <kbr@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent bd382711
...@@ -48,7 +48,7 @@ typedef unsigned int GLenum; ...@@ -48,7 +48,7 @@ typedef unsigned int GLenum;
// Version number for shader translation API. // Version number for shader translation API.
// It is incremented every time the API changes. // It is incremented every time the API changes.
#define ANGLE_SH_VERSION 143 #define ANGLE_SH_VERSION 144
typedef enum { typedef enum {
SH_GLES2_SPEC = 0x8B40, SH_GLES2_SPEC = 0x8B40,
...@@ -299,11 +299,15 @@ typedef struct ...@@ -299,11 +299,15 @@ typedef struct
// Default is SH_CLAMP_WITH_CLAMP_INTRINSIC. // Default is SH_CLAMP_WITH_CLAMP_INTRINSIC.
ShArrayIndexClampingStrategy ArrayIndexClampingStrategy; ShArrayIndexClampingStrategy ArrayIndexClampingStrategy;
// The maximum complexity an expression can be. // The maximum complexity an expression can be when SH_LIMIT_EXPRESSION_COMPLEXITY is turned on.
int MaxExpressionComplexity; int MaxExpressionComplexity;
// The maximum depth a call stack can be. // The maximum depth a call stack can be.
int MaxCallStackDepth; int MaxCallStackDepth;
// The maximum number of parameters a function can have when SH_LIMIT_EXPRESSION_COMPLEXITY is
// turned on.
int MaxFunctionParameters;
} ShBuiltInResources; } ShBuiltInResources;
// //
......
...@@ -98,6 +98,8 @@ ...@@ -98,6 +98,8 @@
'compiler/translator/ValidateGlobalInitializer.h', 'compiler/translator/ValidateGlobalInitializer.h',
'compiler/translator/ValidateLimitations.cpp', 'compiler/translator/ValidateLimitations.cpp',
'compiler/translator/ValidateLimitations.h', 'compiler/translator/ValidateLimitations.h',
'compiler/translator/ValidateMaxParameters.h',
'compiler/translator/ValidateMaxParameters.cpp',
'compiler/translator/ValidateOutputs.cpp', 'compiler/translator/ValidateOutputs.cpp',
'compiler/translator/ValidateOutputs.h', 'compiler/translator/ValidateOutputs.h',
'compiler/translator/ValidateSwitch.cpp', 'compiler/translator/ValidateSwitch.cpp',
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "compiler/translator/ScalarizeVecAndMatConstructorArgs.h" #include "compiler/translator/ScalarizeVecAndMatConstructorArgs.h"
#include "compiler/translator/UnfoldShortCircuitAST.h" #include "compiler/translator/UnfoldShortCircuitAST.h"
#include "compiler/translator/ValidateLimitations.h" #include "compiler/translator/ValidateLimitations.h"
#include "compiler/translator/ValidateMaxParameters.h"
#include "compiler/translator/ValidateOutputs.h" #include "compiler/translator/ValidateOutputs.h"
#include "compiler/translator/VariablePacker.h" #include "compiler/translator/VariablePacker.h"
#include "compiler/translator/depgraph/DependencyGraph.h" #include "compiler/translator/depgraph/DependencyGraph.h"
...@@ -141,6 +142,7 @@ TCompiler::TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output) ...@@ -141,6 +142,7 @@ TCompiler::TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
maxUniformVectors(0), maxUniformVectors(0),
maxExpressionComplexity(0), maxExpressionComplexity(0),
maxCallStackDepth(0), maxCallStackDepth(0),
maxFunctionParameters(0),
fragmentPrecisionHigh(false), fragmentPrecisionHigh(false),
clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC), clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC),
builtInFunctionEmulator(), builtInFunctionEmulator(),
...@@ -169,7 +171,8 @@ bool TCompiler::Init(const ShBuiltInResources& resources) ...@@ -169,7 +171,8 @@ bool TCompiler::Init(const ShBuiltInResources& resources)
resources.MaxVertexUniformVectors : resources.MaxVertexUniformVectors :
resources.MaxFragmentUniformVectors; resources.MaxFragmentUniformVectors;
maxExpressionComplexity = resources.MaxExpressionComplexity; maxExpressionComplexity = resources.MaxExpressionComplexity;
maxCallStackDepth = resources.MaxCallStackDepth; maxCallStackDepth = resources.MaxCallStackDepth;
maxFunctionParameters = resources.MaxFunctionParameters;
SetGlobalPoolAllocator(&allocator); SetGlobalPoolAllocator(&allocator);
...@@ -486,6 +489,7 @@ void TCompiler::setResourceString() ...@@ -486,6 +489,7 @@ void TCompiler::setResourceString()
<< ":FragmentPrecisionHigh:" << compileResources.FragmentPrecisionHigh << ":FragmentPrecisionHigh:" << compileResources.FragmentPrecisionHigh
<< ":MaxExpressionComplexity:" << compileResources.MaxExpressionComplexity << ":MaxExpressionComplexity:" << compileResources.MaxExpressionComplexity
<< ":MaxCallStackDepth:" << compileResources.MaxCallStackDepth << ":MaxCallStackDepth:" << compileResources.MaxCallStackDepth
<< ":MaxFunctionParameters:" << compileResources.MaxFunctionParameters
<< ":EXT_blend_func_extended:" << compileResources.EXT_blend_func_extended << ":EXT_blend_func_extended:" << compileResources.EXT_blend_func_extended
<< ":EXT_frag_depth:" << compileResources.EXT_frag_depth << ":EXT_frag_depth:" << compileResources.EXT_frag_depth
<< ":EXT_shader_texture_lod:" << compileResources.EXT_shader_texture_lod << ":EXT_shader_texture_lod:" << compileResources.EXT_shader_texture_lod
...@@ -747,6 +751,12 @@ bool TCompiler::limitExpressionComplexity(TIntermNode* root) ...@@ -747,6 +751,12 @@ bool TCompiler::limitExpressionComplexity(TIntermNode* root)
return false; return false;
} }
if (!ValidateMaxParameters::validate(root, maxFunctionParameters))
{
infoSink.info << "Function has too many parameters.";
return false;
}
return true; return true;
} }
......
...@@ -208,6 +208,7 @@ class TCompiler : public TShHandleBase ...@@ -208,6 +208,7 @@ class TCompiler : public TShHandleBase
int maxUniformVectors; int maxUniformVectors;
int maxExpressionComplexity; int maxExpressionComplexity;
int maxCallStackDepth; int maxCallStackDepth;
int maxFunctionParameters;
ShBuiltInResources compileResources; ShBuiltInResources compileResources;
std::string builtInResourcesString; std::string builtInResourcesString;
......
...@@ -178,7 +178,8 @@ void ShInitBuiltInResources(ShBuiltInResources* resources) ...@@ -178,7 +178,8 @@ void ShInitBuiltInResources(ShBuiltInResources* resources)
resources->ArrayIndexClampingStrategy = SH_CLAMP_WITH_CLAMP_INTRINSIC; resources->ArrayIndexClampingStrategy = SH_CLAMP_WITH_CLAMP_INTRINSIC;
resources->MaxExpressionComplexity = 256; resources->MaxExpressionComplexity = 256;
resources->MaxCallStackDepth = 256; resources->MaxCallStackDepth = 256;
resources->MaxFunctionParameters = 1024;
} }
// //
......
//
// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// ValidateMaxParameters checks if function definitions have more than a set number of parameters.
#include "compiler/translator/ValidateMaxParameters.h"
ValidateMaxParameters::ValidateMaxParameters(unsigned int maxParameters)
: TIntermTraverser(true, false, false), mMaxParameters(maxParameters), mValid(true)
{
}
bool ValidateMaxParameters::visitAggregate(Visit visit, TIntermAggregate *node)
{
if (!mValid)
{
return false;
}
if (node->getOp() == EOpParameters && node->getSequence()->size() > mMaxParameters)
{
mValid = false;
}
return mValid;
}
bool ValidateMaxParameters::validate(TIntermNode *root, unsigned int maxParameters)
{
ValidateMaxParameters argsTraverser(maxParameters);
root->traverse(&argsTraverser);
return argsTraverser.mValid;
}
//
// Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// ValidateMaxParameters checks if function definitions have more than a set number of parameters.
#ifndef COMPILER_TRANSLATOR_VALIDATEMAXPARAMETERS_H_
#define COMPILER_TRANSLATOR_VALIDATEMAXPARAMETERS_H_
#include "compiler/translator/IntermNode.h"
class ValidateMaxParameters : public TIntermTraverser
{
public:
// Returns false if maxParameters is exceeded.
static bool validate(TIntermNode *root, unsigned int maxParameters);
protected:
bool visitAggregate(Visit visit, TIntermAggregate *node) override;
private:
ValidateMaxParameters(unsigned int maxParameters);
unsigned int mMaxParameters;
bool mValid;
};
#endif // COMPILER_TRANSLATOR_VALIDATEMAXPARAMETERS_H_
...@@ -15,10 +15,12 @@ ...@@ -15,10 +15,12 @@
class ExpressionLimitTest : public testing::Test { class ExpressionLimitTest : public testing::Test {
protected: protected:
static const int kMaxExpressionComplexity = 16; static const int kMaxExpressionComplexity = 16;
static const int kMaxCallStackDepth = 16; static const int kMaxCallStackDepth = 16;
static const int kMaxFunctionParameters = 16;
static const char* kExpressionTooComplex; static const char* kExpressionTooComplex;
static const char* kCallStackTooDeep; static const char* kCallStackTooDeep;
static const char* kHasRecursion; static const char* kHasRecursion;
static const char *kTooManyParameters;
virtual void SetUp() virtual void SetUp()
{ {
...@@ -46,6 +48,7 @@ protected: ...@@ -46,6 +48,7 @@ protected:
res->MaxExpressionComplexity = kMaxExpressionComplexity; res->MaxExpressionComplexity = kMaxExpressionComplexity;
res->MaxCallStackDepth = kMaxCallStackDepth; res->MaxCallStackDepth = kMaxCallStackDepth;
res->MaxFunctionParameters = kMaxFunctionParameters;
} }
void GenerateLongExpression(int length, std::stringstream* ss) void GenerateLongExpression(int length, std::stringstream* ss)
...@@ -140,6 +143,34 @@ protected: ...@@ -140,6 +143,34 @@ protected:
return ss.str(); return ss.str();
} }
std::string GenerateShaderWithFunctionParameters(int parameters)
{
std::stringstream ss;
ss << "precision mediump float;\n"
<< "\n"
<< "float foo(";
for (int i = 0; i < parameters; ++i)
{
ss << "float f" << i;
if (i + 1 < parameters)
{
ss << ", ";
}
}
ss << ")\n"
<< "{\n"
<< " return f0;\n"
<< "}\n"
<< "\n"
<< "void main()\n"
<< "{\n"
<< " gl_FragColor = vec4(0,0,0,0);\n"
<< "}";
return ss.str();
}
// Compiles a shader and if there's an error checks for a specific // Compiles a shader and if there's an error checks for a specific
// substring in the error log. This way we know the error is specific // substring in the error log. This way we know the error is specific
// to the issue we are testing. // to the issue we are testing.
...@@ -173,6 +204,8 @@ const char* ExpressionLimitTest::kCallStackTooDeep = ...@@ -173,6 +204,8 @@ const char* ExpressionLimitTest::kCallStackTooDeep =
"Call stack too deep"; "Call stack too deep";
const char* ExpressionLimitTest::kHasRecursion = const char* ExpressionLimitTest::kHasRecursion =
"Function recursion detected"; "Function recursion detected";
const char* ExpressionLimitTest::kTooManyParameters =
"Function has too many parameters";
TEST_F(ExpressionLimitTest, ExpressionComplexity) TEST_F(ExpressionLimitTest, ExpressionComplexity)
{ {
...@@ -506,3 +539,24 @@ TEST_F(ExpressionLimitTest, Recursion) ...@@ -506,3 +539,24 @@ TEST_F(ExpressionLimitTest, Recursion)
ShDestruct(vertexCompiler); ShDestruct(vertexCompiler);
} }
TEST_F(ExpressionLimitTest, FunctionParameterCount)
{
ShShaderSpec spec = SH_WEBGL_SPEC;
ShShaderOutput output = SH_ESSL_OUTPUT;
ShHandle compiler = ShConstructCompiler(GL_FRAGMENT_SHADER, spec, output, &resources);
int compileOptions = SH_LIMIT_EXPRESSION_COMPLEXITY;
// Test parameters under the limit succeeds.
EXPECT_TRUE(CheckShaderCompilation(
compiler, GenerateShaderWithFunctionParameters(kMaxFunctionParameters).c_str(),
compileOptions, nullptr));
// Test parameters over the limit fails.
EXPECT_TRUE(CheckShaderCompilation(
compiler, GenerateShaderWithFunctionParameters(kMaxFunctionParameters + 1).c_str(),
compileOptions, kTooManyParameters));
// Test parameters over the limit without limit does not fail.
EXPECT_TRUE(CheckShaderCompilation(
compiler, GenerateShaderWithFunctionParameters(kMaxFunctionParameters + 1).c_str(),
compileOptions & ~SH_LIMIT_EXPRESSION_COMPLEXITY, nullptr));
ShDestruct(compiler);
}
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