Commit 0844f2db by Corentin Wallez Committed by Commit Bot

WebGLCompatibility: add tests for OOB in DrawElements' index buffer

Also add a small fix for a WebGL test where DrawElements with a count of 0 should skip OOB checks. BUG=angleproject:1523 BUG=chromium:668223 Change-Id: I67fbe939f6c8b925551b658b6178dbbae982df89 Reviewed-on: https://chromium-review.googlesource.com/435279Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Commit-Queue: Corentin Wallez <cwallez@chromium.org>
parent 1aa728e3
...@@ -3456,7 +3456,7 @@ bool ValidateDrawElements(ValidationContext *context, ...@@ -3456,7 +3456,7 @@ bool ValidateDrawElements(ValidationContext *context,
// Check for mapped buffers // Check for mapped buffers
if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER)) if (state.hasMappedBuffer(GL_ELEMENT_ARRAY_BUFFER))
{ {
context->handleError(Error(GL_INVALID_OPERATION)); context->handleError(Error(GL_INVALID_OPERATION, "Index buffer is mapped."));
return false; return false;
} }
...@@ -3488,34 +3488,39 @@ bool ValidateDrawElements(ValidationContext *context, ...@@ -3488,34 +3488,39 @@ bool ValidateDrawElements(ValidationContext *context,
} }
} }
if (elementArrayBuffer) if (count > 0)
{ {
GLint64 offset = reinterpret_cast<GLint64>(indices); if (elementArrayBuffer)
GLint64 byteCount = static_cast<GLint64>(typeBytes) * static_cast<GLint64>(count) + offset;
// check for integer overflows
if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeBytes) ||
byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
{ {
context->handleError(Error(GL_OUT_OF_MEMORY)); GLint64 offset = reinterpret_cast<GLint64>(indices);
return false; GLint64 byteCount =
} static_cast<GLint64>(typeBytes) * static_cast<GLint64>(count) + offset;
// Check for reading past the end of the bound buffer object // check for integer overflows
if (byteCount > elementArrayBuffer->getSize()) if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeBytes) ||
byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
{
context->handleError(Error(GL_OUT_OF_MEMORY, "Integer overflow."));
return false;
}
// Check for reading past the end of the bound buffer object
if (byteCount > elementArrayBuffer->getSize())
{
context->handleError(
Error(GL_INVALID_OPERATION, "Index buffer is not big enough for the draw."));
return false;
}
}
else if (!indices)
{ {
context->handleError(Error(GL_INVALID_OPERATION)); // This is an application error that would normally result in a crash,
// but we catch it and return an error
context->handleError(
Error(GL_INVALID_OPERATION, "No element array buffer and no pointer."));
return false; return false;
} }
} }
else if (!indices && count > 0)
{
// This is an application error that would normally result in a crash,
// but we catch it and return an error
context->handleError(
Error(GL_INVALID_OPERATION, "No element array buffer and no pointer."));
return false;
}
if (!ValidateDrawBase(context, mode, count)) if (!ValidateDrawBase(context, mode, count))
{ {
......
...@@ -361,37 +361,56 @@ TEST_P(WebGLCompatibilityTest, DrawArraysBufferOutOfBoundsNonInstanced) ...@@ -361,37 +361,56 @@ TEST_P(WebGLCompatibilityTest, DrawArraysBufferOutOfBoundsNonInstanced)
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
} }
// Tests that NPOT is not enabled by default in WebGL 1 and that it can be enabled // Test the checks for OOB reads in the index buffer
TEST_P(WebGLCompatibilityTest, NPOT) TEST_P(WebGLCompatibilityTest, DrawElementsBufferOutOfBoundsInIndexBuffer)
{ {
EXPECT_FALSE(extensionEnabled("GL_OES_texture_npot")); const std::string &vert =
"attribute float a_pos;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(a_pos, a_pos, a_pos, 1.0);\n"
"}\n";
// Create a texture and set an NPOT mip 0, should always be acceptable. const std::string &frag =
GLTexture texture; "precision highp float;\n"
glBindTexture(GL_TEXTURE_2D, texture.get()); "void main()\n"
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 10, 10, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); "{\n"
" gl_FragColor = vec4(1.0);\n"
"}\n";
ANGLE_GL_PROGRAM(program, vert, frag);
GLint posLocation = glGetAttribLocation(program.get(), "a_pos");
ASSERT_NE(-1, posLocation);
glUseProgram(program.get());
GLBuffer vertexBuffer;
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer.get());
glBufferData(GL_ARRAY_BUFFER, 16, nullptr, GL_STATIC_DRAW);
glEnableVertexAttribArray(posLocation);
const uint8_t *zeroOffset = nullptr;
const uint8_t zeroIndices[] = {0, 0, 0, 0, 0, 0, 0, 0};
glVertexAttribPointer(0, 1, GL_UNSIGNED_BYTE, GL_FALSE, 0, zeroOffset);
GLBuffer indexBuffer;
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.get());
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(zeroIndices), zeroIndices, GL_STATIC_DRAW);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
// Try setting an NPOT mip 1 and verify the error if WebGL 1 // Test touching the last index is valid
glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 5, 5, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glDrawElements(GL_POINTS, 4, GL_UNSIGNED_BYTE, zeroOffset + 4);
if (getClientMajorVersion() < 3) ASSERT_GL_NO_ERROR();
{
ASSERT_GL_ERROR(GL_INVALID_VALUE);
}
else
{
ASSERT_GL_NO_ERROR();
}
if (extensionRequestable("GL_OES_texture_npot")) // Test touching the last + 1 element is invalid
{ glDrawElements(GL_POINTS, 4, GL_UNSIGNED_BYTE, zeroOffset + 5);
glRequestExtensionANGLE("GL_OES_texture_npot"); EXPECT_GL_ERROR(GL_INVALID_OPERATION);
ASSERT_GL_NO_ERROR();
// Try again to set NPOT mip 1 // Test any offset if valid if count is zero
glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 5, 5, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glDrawElements(GL_POINTS, 0, GL_UNSIGNED_BYTE, zeroOffset + 42);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
}
} }
// Test the checks for OOB reads in the vertex buffers, instanced version // Test the checks for OOB reads in the vertex buffers, instanced version
...@@ -452,6 +471,39 @@ TEST_P(WebGL2CompatibilityTest, DrawArraysBufferOutOfBoundsInstanced) ...@@ -452,6 +471,39 @@ TEST_P(WebGL2CompatibilityTest, DrawArraysBufferOutOfBoundsInstanced)
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
} }
// Tests that NPOT is not enabled by default in WebGL 1 and that it can be enabled
TEST_P(WebGLCompatibilityTest, NPOT)
{
EXPECT_FALSE(extensionEnabled("GL_OES_texture_npot"));
// Create a texture and set an NPOT mip 0, should always be acceptable.
GLTexture texture;
glBindTexture(GL_TEXTURE_2D, texture.get());
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 10, 10, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
ASSERT_GL_NO_ERROR();
// Try setting an NPOT mip 1 and verify the error if WebGL 1
glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 5, 5, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
if (getClientMajorVersion() < 3)
{
ASSERT_GL_ERROR(GL_INVALID_VALUE);
}
else
{
ASSERT_GL_NO_ERROR();
}
if (extensionRequestable("GL_OES_texture_npot"))
{
glRequestExtensionANGLE("GL_OES_texture_npot");
ASSERT_GL_NO_ERROR();
// Try again to set NPOT mip 1
glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 5, 5, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
ASSERT_GL_NO_ERROR();
}
}
// Tests that a rendering feedback loop triggers a GL error under WebGL. // Tests that a rendering feedback loop triggers a GL error under WebGL.
// Based on WebGL test conformance/renderbuffers/feedback-loop.html. // Based on WebGL test conformance/renderbuffers/feedback-loop.html.
TEST_P(WebGLCompatibilityTest, RenderingFeedbackLoop) TEST_P(WebGLCompatibilityTest, RenderingFeedbackLoop)
......
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