Implement robust GetUniform entry points.

BUG=angleproject:1354

Change-Id: I07dccc470c57aadd41cae8fce327e4aca58a0bea
Reviewed-on: https://chromium-review.googlesource.com/395113
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
index 4904124..7310112 100644
--- a/src/libANGLE/validationES.cpp
+++ b/src/libANGLE/validationES.cpp
@@ -2674,13 +2674,28 @@
     return ValidateGetUniformBase(context, program, location);
 }
 
-static bool ValidateSizedGetUniform(Context *context, GLuint program, GLint location, GLsizei bufSize)
+static bool ValidateSizedGetUniform(Context *context,
+                                    GLuint program,
+                                    GLint location,
+                                    GLsizei bufSize,
+                                    GLsizei *length)
 {
+    if (length)
+    {
+        *length = 0;
+    }
+
     if (!ValidateGetUniformBase(context, program, location))
     {
         return false;
     }
 
+    if (bufSize < 0)
+    {
+        context->handleError(Error(GL_INVALID_VALUE, "bufSize cannot be negative."));
+        return false;
+    }
+
     gl::Program *programObject = context->getProgram(program);
     ASSERT(programObject);
 
@@ -2689,21 +2704,83 @@
     size_t requiredBytes = VariableExternalSize(uniform.type);
     if (static_cast<size_t>(bufSize) < requiredBytes)
     {
-        context->handleError(Error(GL_INVALID_OPERATION));
+        context->handleError(
+            Error(GL_INVALID_OPERATION, "bufSize of at least %u is required.", requiredBytes));
         return false;
     }
 
+    if (length)
+    {
+        // Cast is safe because of comparison to bufSize.
+        *length = static_cast<GLsizei>(requiredBytes);
+    }
+
     return true;
 }
 
 bool ValidateGetnUniformfvEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
 {
-    return ValidateSizedGetUniform(context, program, location, bufSize);
+    return ValidateSizedGetUniform(context, program, location, bufSize, nullptr);
 }
 
 bool ValidateGetnUniformivEXT(Context *context, GLuint program, GLint location, GLsizei bufSize, GLint* params)
 {
-    return ValidateSizedGetUniform(context, program, location, bufSize);
+    return ValidateSizedGetUniform(context, program, location, bufSize, nullptr);
+}
+
+bool ValidateGetUniformfvRobustANGLE(Context *context,
+                                     GLuint program,
+                                     GLint location,
+                                     GLsizei bufSize,
+                                     GLsizei *length,
+                                     GLfloat *params)
+{
+    if (!ValidateRobustEntryPoint(context, bufSize))
+    {
+        return false;
+    }
+
+    // bufSize is validated in ValidateSizedGetUniform
+    return ValidateSizedGetUniform(context, program, location, bufSize, length);
+}
+
+bool ValidateGetUniformivRobustANGLE(Context *context,
+                                     GLuint program,
+                                     GLint location,
+                                     GLsizei bufSize,
+                                     GLsizei *length,
+                                     GLint *params)
+{
+    if (!ValidateRobustEntryPoint(context, bufSize))
+    {
+        return false;
+    }
+
+    // bufSize is validated in ValidateSizedGetUniform
+    return ValidateSizedGetUniform(context, program, location, bufSize, length);
+}
+
+bool ValidateGetUniformuivRobustANGLE(Context *context,
+                                      GLuint program,
+                                      GLint location,
+                                      GLsizei bufSize,
+                                      GLsizei *length,
+                                      GLuint *params)
+{
+    if (!ValidateRobustEntryPoint(context, bufSize))
+    {
+        return false;
+    }
+
+    if (context->getClientMajorVersion() < 3)
+    {
+        context->handleError(
+            Error(GL_INVALID_OPERATION, "Entry point requires at least OpenGL ES 3.0."));
+        return false;
+    }
+
+    // bufSize is validated in ValidateSizedGetUniform
+    return ValidateSizedGetUniform(context, program, location, bufSize, length);
 }
 
 bool ValidateDiscardFramebufferBase(Context *context, GLenum target, GLsizei numAttachments,