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;
     }