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;
// Version number for shader translation API.
// It is incremented every time the API changes.
#define ANGLE_SH_VERSION 143
#define ANGLE_SH_VERSION 144
typedef enum {
SH_GLES2_SPEC = 0x8B40,
......@@ -299,11 +299,15 @@ typedef struct
// Default is SH_CLAMP_WITH_CLAMP_INTRINSIC.
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;
// The maximum depth a call stack can be.
int MaxCallStackDepth;
// The maximum number of parameters a function can have when SH_LIMIT_EXPRESSION_COMPLEXITY is
// turned on.
int MaxFunctionParameters;
} ShBuiltInResources;
//
......
......@@ -98,6 +98,8 @@
'compiler/translator/ValidateGlobalInitializer.h',
'compiler/translator/ValidateLimitations.cpp',
'compiler/translator/ValidateLimitations.h',
'compiler/translator/ValidateMaxParameters.h',
'compiler/translator/ValidateMaxParameters.cpp',
'compiler/translator/ValidateOutputs.cpp',
'compiler/translator/ValidateOutputs.h',
'compiler/translator/ValidateSwitch.cpp',
......
......@@ -20,6 +20,7 @@
#include "compiler/translator/ScalarizeVecAndMatConstructorArgs.h"
#include "compiler/translator/UnfoldShortCircuitAST.h"
#include "compiler/translator/ValidateLimitations.h"
#include "compiler/translator/ValidateMaxParameters.h"
#include "compiler/translator/ValidateOutputs.h"
#include "compiler/translator/VariablePacker.h"
#include "compiler/translator/depgraph/DependencyGraph.h"
......@@ -141,6 +142,7 @@ TCompiler::TCompiler(sh::GLenum type, ShShaderSpec spec, ShShaderOutput output)
maxUniformVectors(0),
maxExpressionComplexity(0),
maxCallStackDepth(0),
maxFunctionParameters(0),
fragmentPrecisionHigh(false),
clampingStrategy(SH_CLAMP_WITH_CLAMP_INTRINSIC),
builtInFunctionEmulator(),
......@@ -169,7 +171,8 @@ bool TCompiler::Init(const ShBuiltInResources& resources)
resources.MaxVertexUniformVectors :
resources.MaxFragmentUniformVectors;
maxExpressionComplexity = resources.MaxExpressionComplexity;
maxCallStackDepth = resources.MaxCallStackDepth;
maxCallStackDepth = resources.MaxCallStackDepth;
maxFunctionParameters = resources.MaxFunctionParameters;
SetGlobalPoolAllocator(&allocator);
......@@ -486,6 +489,7 @@ void TCompiler::setResourceString()
<< ":FragmentPrecisionHigh:" << compileResources.FragmentPrecisionHigh
<< ":MaxExpressionComplexity:" << compileResources.MaxExpressionComplexity
<< ":MaxCallStackDepth:" << compileResources.MaxCallStackDepth
<< ":MaxFunctionParameters:" << compileResources.MaxFunctionParameters
<< ":EXT_blend_func_extended:" << compileResources.EXT_blend_func_extended
<< ":EXT_frag_depth:" << compileResources.EXT_frag_depth
<< ":EXT_shader_texture_lod:" << compileResources.EXT_shader_texture_lod
......@@ -747,6 +751,12 @@ bool TCompiler::limitExpressionComplexity(TIntermNode* root)
return false;
}
if (!ValidateMaxParameters::validate(root, maxFunctionParameters))
{
infoSink.info << "Function has too many parameters.";
return false;
}
return true;
}
......
......@@ -208,6 +208,7 @@ class TCompiler : public TShHandleBase
int maxUniformVectors;
int maxExpressionComplexity;
int maxCallStackDepth;
int maxFunctionParameters;
ShBuiltInResources compileResources;
std::string builtInResourcesString;
......
......@@ -178,7 +178,8 @@ void ShInitBuiltInResources(ShBuiltInResources* resources)
resources->ArrayIndexClampingStrategy = SH_CLAMP_WITH_CLAMP_INTRINSIC;
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 @@
class ExpressionLimitTest : public testing::Test {
protected:
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* kCallStackTooDeep;
static const char* kHasRecursion;
static const char *kTooManyParameters;
virtual void SetUp()
{
......@@ -46,6 +48,7 @@ protected:
res->MaxExpressionComplexity = kMaxExpressionComplexity;
res->MaxCallStackDepth = kMaxCallStackDepth;
res->MaxFunctionParameters = kMaxFunctionParameters;
}
void GenerateLongExpression(int length, std::stringstream* ss)
......@@ -140,6 +143,34 @@ protected:
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
// substring in the error log. This way we know the error is specific
// to the issue we are testing.
......@@ -173,6 +204,8 @@ const char* ExpressionLimitTest::kCallStackTooDeep =
"Call stack too deep";
const char* ExpressionLimitTest::kHasRecursion =
"Function recursion detected";
const char* ExpressionLimitTest::kTooManyParameters =
"Function has too many parameters";
TEST_F(ExpressionLimitTest, ExpressionComplexity)
{
......@@ -506,3 +539,24 @@ TEST_F(ExpressionLimitTest, Recursion)
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