Program: clamp the number of uniforms to be copied

BUG=661413

Change-Id: I1a146dae0d01edeb272a58610355261b0e23dec1
Reviewed-on: https://chromium-review.googlesource.com/406745
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Corentin Wallez 2016-11-03 17:06:39 -04:00 коммит произвёл Commit Bot
Родитель 8a9e4bcfe9
Коммит 9863a3ef18
4 изменённых файлов: 70 добавлений и 4 удалений

Просмотреть файл

@ -2855,12 +2855,18 @@ void Program::setUniformInternal(GLint location, GLsizei count, const T *v)
LinkedUniform *linkedUniform = &mState.mUniforms[locationInfo.index];
uint8_t *destPointer = linkedUniform->getDataPtrToElement(locationInfo.element);
// OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
// element index used, as reported by GetActiveUniform, will be ignored by the GL."
unsigned int remainingElements = linkedUniform->elementCount() - locationInfo.element;
GLsizei clampedCount = std::min(
count, static_cast<GLsizei>(remainingElements * linkedUniform->getElementComponents()));
if (VariableComponentType(linkedUniform->type) == GL_BOOL)
{
// Do a cast conversion for boolean types. From the spec:
// "The uniform is set to FALSE if the input value is 0 or 0.0f, and set to TRUE otherwise."
GLint *destAsInt = reinterpret_cast<GLint *>(destPointer);
for (GLsizei component = 0; component < count; ++component)
for (GLsizei component = 0; component < clampedCount; ++component)
{
destAsInt[component] = (v[component] != static_cast<T>(0) ? GL_TRUE : GL_FALSE);
}
@ -2868,12 +2874,12 @@ void Program::setUniformInternal(GLint location, GLsizei count, const T *v)
else
{
// Invalide the validation cache if we modify the sampler data.
if (linkedUniform->isSampler() && memcmp(destPointer, v, sizeof(T) * count) != 0)
if (linkedUniform->isSampler() && memcmp(destPointer, v, sizeof(T) * clampedCount) != 0)
{
mCachedValidateSamplersResult.reset();
}
memcpy(destPointer, v, sizeof(T) * count);
memcpy(destPointer, v, sizeof(T) * clampedCount);
}
}
@ -2893,7 +2899,13 @@ void Program::setMatrixUniformInternal(GLint location,
const VariableLocation &locationInfo = mState.mUniformLocations[location];
LinkedUniform *linkedUniform = &mState.mUniforms[locationInfo.index];
T *destPtr = reinterpret_cast<T *>(linkedUniform->getDataPtrToElement(locationInfo.element));
for (GLsizei element = 0; element < count; ++element)
// OpenGL ES 3.0.4 spec pg 67: "Values for any array element that exceeds the highest array
// element index used, as reported by GetActiveUniform, will be ignored by the GL."
unsigned int remainingElements = linkedUniform->elementCount() - locationInfo.element;
GLsizei clampedCount = std::min(count, static_cast<GLsizei>(remainingElements));
for (GLsizei element = 0; element < clampedCount; ++element)
{
size_t elementOffset = element * rows * cols;

Просмотреть файл

@ -109,6 +109,11 @@ size_t LinkedUniform::getElementSize() const
return VariableExternalSize(type);
}
size_t LinkedUniform::getElementComponents() const
{
return VariableComponentCount(type);
}
uint8_t *LinkedUniform::getDataPtrToElement(size_t elementIndex)
{
ASSERT((!isArray() && elementIndex == 0) || (isArray() && elementIndex < arraySize));

Просмотреть файл

@ -36,6 +36,7 @@ struct LinkedUniform : public sh::Uniform
bool isInDefaultBlock() const;
bool isField() const;
size_t getElementSize() const;
size_t getElementComponents() const;
uint8_t *getDataPtrToElement(size_t elementIndex);
const uint8_t *getDataPtrToElement(size_t elementIndex) const;

Просмотреть файл

@ -459,6 +459,54 @@ TEST_P(UniformTestES3, TranposedMatrixArrayUniformStateQuery)
}
}
// Check that trying setting too many elements of an array doesn't overflow
TEST_P(UniformTestES3, OverflowArray)
{
const std::string &vertexShader =
"#version 300 es\n"
"void main() { gl_Position = vec4(1); }";
const std::string &fragShader =
"#version 300 es\n"
"precision mediump float;\n"
"uniform float uniF[5];\n"
"uniform mat3x2 uniMat3x2[5];\n"
"out vec4 color;\n"
"void main() {\n"
" color = vec4(uniMat3x2[0][0][0] + uniF[0]);\n"
"}";
mProgram = CompileProgram(vertexShader, fragShader);
ASSERT_NE(mProgram, 0u);
glUseProgram(mProgram);
const size_t kOverflowSize = 10000;
std::vector<GLfloat> values(10000 * 6);
// Setting as a clump
GLint floatLocation = glGetUniformLocation(mProgram, "uniF");
ASSERT_NE(-1, floatLocation);
GLint matLocation = glGetUniformLocation(mProgram, "uniMat3x2");
ASSERT_NE(-1, matLocation);
// Set too many float uniforms
glUniform1fv(floatLocation, kOverflowSize, &values[0]);
// Set too many matrix uniforms, transposed or not
glUniformMatrix3x2fv(matLocation, kOverflowSize, GL_FALSE, &values[0]);
glUniformMatrix3x2fv(matLocation, kOverflowSize, GL_TRUE, &values[0]);
// Same checks but with offsets
GLint floatLocationOffset = glGetUniformLocation(mProgram, "uniF[3]");
ASSERT_NE(-1, floatLocationOffset);
GLint matLocationOffset = glGetUniformLocation(mProgram, "uniMat3x2[3]");
ASSERT_NE(-1, matLocationOffset);
glUniform1fv(floatLocationOffset, kOverflowSize, &values[0]);
glUniformMatrix3x2fv(matLocationOffset, kOverflowSize, GL_FALSE, &values[0]);
glUniformMatrix3x2fv(matLocationOffset, kOverflowSize, GL_TRUE, &values[0]);
}
// Check that sampler uniforms only show up one time in the list
TEST_P(UniformTest, SamplerUniformsAppearOnce)
{