Commit 75841d73 by Sean Risser

Reject large arrays in GLSL

The compiler tries to allocate arrays of uniforms before it checks their size. So large arrays will cause the compiler to allocate all of its memory. This change makes the compiler reject oversized arrays and returns a compilation error. Bug chromium:872321 Change-Id: I3441232cca129bd2abd181990bec457ad7f43d05 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/29333Tested-by: 's avatarSean Risser <srisser@google.com> Presubmit-Ready: Sean Risser <srisser@google.com> Kokoro-Presubmit: kokoro <noreply+kokoro@google.com> Reviewed-by: 's avatarAlexis Hétu <sugoi@google.com> Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com>
parent 93ad3b8b
......@@ -3124,6 +3124,10 @@ namespace glsl
if(var == -1)
{
var = allocate(varyings, varying);
if (var == -1)
{
return 0;
}
int registerCount = varying->totalRegisterCount();
if(pixelShader)
......@@ -3300,6 +3304,10 @@ namespace glsl
if(index == -1)
{
index = allocate(uniforms, uniform);
if (index == -1)
{
return 0;
}
}
// Verify if the current uniform is a member of an already declared block
......@@ -3335,6 +3343,10 @@ namespace glsl
if(symbol)
{
index = allocate(attributes, attribute);
if (index == -1)
{
return -1;
}
const TType &type = attribute->getType();
int registerCount = attribute->totalRegisterCount();
sw::VertexShader::AttribType attribType = sw::VertexShader::ATTRIBTYPE_FLOAT;
......@@ -3453,6 +3465,10 @@ namespace glsl
if(index == -1)
{
index = allocate(samplers, sampler, true);
if (index == -1)
{
return 0;
}
if(sampler->getQualifier() == EvqUniform)
{
......@@ -3469,6 +3485,33 @@ namespace glsl
return operand && IsSampler(operand->getBasicType()) && samplerRegister(operand) >= 0;
}
bool OutputASM::arrayExceedsLimits(TIntermTyped *operand)
{
const TVariable *maxUniformVectors = nullptr;
TString builtinName = "";
if (vertexShader)
{
builtinName = "gl_MaxVertexUniformVectors";
}
else if (pixelShader)
{
builtinName = "gl_MaxFragmentUniformVectors";
}
maxUniformVectors = static_cast<const TVariable *>(mContext.symbolTable.findBuiltIn(builtinName.c_str(), mContext.getShaderVersion()));
if (operand->getArraySize() > maxUniformVectors->getConstPointer()->getIConst())
{
std::stringstream extraInfoStream;
extraInfoStream << "Array size (" << operand->getArraySize() << ") "
<< "exceeds limit of " << builtinName
<< " (" << maxUniformVectors->getConstPointer()->getIConst() << ")";
std::string errorStr = extraInfoStream.str();
mContext.error(operand->getLine(), errorStr.c_str(),
operand->getBasicString());
return true;
}
return false;
}
int OutputASM::lookup(VariableArray &list, TIntermTyped *variable)
{
for(unsigned int i = 0; i < list.size(); i++)
......@@ -3549,6 +3592,10 @@ namespace glsl
if(index == -1)
{
if (arrayExceedsLimits(variable))
{
return -1;
}
unsigned int registerCount = variable->blockRegisterCount(samplersOnly);
for(unsigned int i = 0; i < list.size(); i++)
......
......@@ -303,12 +303,14 @@ namespace glsl
int samplerRegister(TIntermTyped *sampler);
int samplerRegister(TIntermSymbol *sampler);
bool isSamplerRegister(TIntermTyped *operand);
bool arrayExceedsLimits(TIntermTyped *operand);
typedef std::vector<TIntermTyped*> VariableArray;
int lookup(VariableArray &list, TIntermTyped *variable);
int lookup(VariableArray &list, TInterfaceBlock *block);
int blockMemberLookup(const TType &type, const TString &name, int registerIndex);
// Returns -1 if it fails to allocate variable.
int allocate(VariableArray &list, TIntermTyped *variable, bool samplersOnly = false);
void free(VariableArray &list, TIntermTyped *variable);
......
......@@ -381,6 +381,58 @@ protected:
checkCompiles("", s);
}
void checkCompileFails(GLuint glShader, std::string source)
{
GLchar buf[1024];
GLint compileStatus = 0;
const char *c_source[1] = { source.c_str() };
glShaderSource(glShader, 1, c_source, nullptr);
glCompileShader(glShader);
EXPECT_GLENUM_EQ(GL_NONE, glGetError());
glGetShaderiv(glShader, GL_COMPILE_STATUS, &compileStatus);
glGetShaderInfoLog(glShader, sizeof(buf), nullptr, buf);
EXPECT_EQ(compileStatus, GL_FALSE) << "Compile status: " << std::endl << buf;
glDeleteShader(glShader);
}
void checkCompileFails(std::string s)
{
std::string vs =
"#version 300 es\n"
"in vec4 position;\n"
"out float unfoldable;\n"
"$INSERT\n"
"void main()\n"
"{\n"
" unfoldable = position.x;\n"
" gl_Position = vec4(position.xy, 0.0, 1.0);\n"
" gl_Position.x += F(unfoldable);\n"
"}\n";
std::string fs =
"#version 300 es\n"
"precision mediump float;\n"
"in float unfoldable;\n"
"out vec4 fragColor;\n"
"$INSERT\n"
"void main()\n"
"{\n"
" fragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
" fragColor.x += F(unfoldable);\n"
"}\n";
vs = replace(vs, "$INSERT", s);
fs = replace(fs, "$INSERT", s);
checkCompileFails(glCreateShader(GL_VERTEX_SHADER), vs);
checkCompileFails(glCreateShader(GL_FRAGMENT_SHADER), fs);
}
EGLDisplay getDisplay() const { return display; }
EGLConfig getConfig() const { return config; }
EGLSurface getSurface() const { return surface; }
......@@ -1767,6 +1819,23 @@ TEST_F(SwiftShaderTest, CompilerLimits_SparseLabels)
);
}
// Test that the compiler doesn't compile arrays larger than
// GL_MAX_{VERTEX/FRAGMENT}_UNIFORM_VECTOR.
TEST_F(SwiftShaderTest, CompilerLimits_ArraySize)
{
Initialize(3, false);
checkCompileFails(
"uniform float u_var[100000000];\n"
"float F(float f) { return u_var[2]; }\n");
checkCompileFails(
"struct structType { mediump sampler2D m0; mediump samplerCube m1; }; \n"
"uniform structType u_var[100000000];\n"
"float F(float f) { return texture(u_var[2].m1, vec3(0.0)), vec4(0.26, 1.72, 0.60, 0.12).x; }\n");
Uninitialize();
}
#ifndef EGL_ANGLE_iosurface_client_buffer
#define EGL_ANGLE_iosurface_client_buffer 1
#define EGL_IOSURFACE_ANGLE 0x3454
......
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