Tighten the validation for staying in array buffer bounds
BUG=angleproject:1523
Change-Id: I685a9b884e5de73b94900c5b6016ce914b9bfe7f
Reviewed-on: https://chromium-review.googlesource.com/418458
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
index c00c0aa..7c24fb2 100644
--- a/src/libANGLE/validationES.cpp
+++ b/src/libANGLE/validationES.cpp
@@ -34,7 +34,10 @@
namespace
{
-bool ValidateDrawAttribs(ValidationContext *context, GLint primcount, GLint maxVertex)
+bool ValidateDrawAttribs(ValidationContext *context,
+ GLint primcount,
+ GLint maxVertex,
+ GLint vertexCount)
{
const gl::State &state = context->getGLState();
const gl::Program *program = state.getProgram();
@@ -51,32 +54,40 @@
if (buffer)
{
- GLint64 attribStride = static_cast<GLint64>(ComputeVertexAttributeStride(attrib));
- GLint64 maxVertexElement = 0;
-
- if (attrib.divisor > 0)
+ CheckedNumeric<GLint64> maxVertexElement = 0;
+ bool readsData = false;
+ if (attrib.divisor == 0)
{
- maxVertexElement =
- static_cast<GLint64>(primcount) / static_cast<GLint64>(attrib.divisor);
- }
- else
- {
+ readsData = vertexCount > 0;
maxVertexElement = static_cast<GLint64>(maxVertex);
}
+ else if (primcount > 0)
+ {
+ readsData = true;
+ maxVertexElement =
+ static_cast<GLint64>(primcount - 1) / static_cast<GLint64>(attrib.divisor);
+ }
// If we're drawing zero vertices, we have enough data.
- if (maxVertexElement > 0)
+ if (readsData)
{
// Note: Last vertex element does not take the full stride!
- GLint64 attribSize =
- static_cast<GLint64>(ComputeVertexAttributeTypeSize(attrib));
- GLint64 attribDataSize = (maxVertexElement - 1) * attribStride + attribSize;
- GLint64 attribOffset = static_cast<GLint64>(attrib.offset);
+ CheckedNumeric<GLint64> attribStride = ComputeVertexAttributeStride(attrib);
+ CheckedNumeric<GLint64> attribSize = ComputeVertexAttributeTypeSize(attrib);
+ CheckedNumeric<GLint64> attribDataSize =
+ maxVertexElement * attribStride + attribSize;
+ CheckedNumeric<GLint64> maxOffset = attribDataSize + attrib.offset;
+
+ if (!maxOffset.IsValid())
+ {
+ context->handleError(Error(GL_INVALID_OPERATION, "Integer overflow."));
+ return false;
+ }
// [OpenGL ES 3.0.2] section 2.9.4 page 40:
// We can return INVALID_OPERATION if our vertex attribute does not have
// enough backing data.
- if (attribDataSize + attribOffset > buffer->getSize())
+ if (maxOffset.ValueOrDie() > buffer->getSize())
{
context->handleError(
Error(GL_INVALID_OPERATION,
@@ -3172,7 +3183,17 @@
return false;
}
- if (!ValidateDrawAttribs(context, primcount, count))
+ CheckedNumeric<GLint> maxVertex = first;
+ maxVertex += count;
+ maxVertex -= 1;
+
+ if (!maxVertex.IsValid())
+ {
+ context->handleError(Error(GL_INVALID_OPERATION, "Integer overflow."));
+ return false;
+ }
+
+ if (!ValidateDrawAttribs(context, primcount, maxVertex.ValueOrDie(), count))
{
return false;
}
@@ -3355,7 +3376,8 @@
return false;
}
- if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOut->vertexCount())))
+ if (!ValidateDrawAttribs(context, primcount, static_cast<GLint>(indexRangeOut->end),
+ static_cast<GLint>(indexRangeOut->vertexCount())))
{
return false;
}