WebGLCompatibility: Add test for "negative" offset in DrawElements
BUG=angleproject:1523
BUG=chromium:668223
Change-Id: I2d21c15b53fa204b3cb2b0be849cfe91ca63046b
Reviewed-on: https://chromium-review.googlesource.com/435884
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
index 6901b54..74037b2 100644
--- a/src/libANGLE/validationES.cpp
+++ b/src/libANGLE/validationES.cpp
@@ -3503,6 +3503,15 @@
"indices must be a multiple of the element type size."));
return false;
}
+
+ // [WebGL 1.0] Section 6.4 Buffer Offset and Stride Requirements
+ // In addition the offset argument to drawElements must be non-negative or an INVALID_VALUE
+ // error is generated.
+ if (reinterpret_cast<intptr_t>(indices) < 0)
+ {
+ context->handleError(Error(GL_INVALID_VALUE, "Offset < 0."));
+ return false;
+ }
}
if (context->getExtensions().webglCompatibility ||
@@ -3523,20 +3532,31 @@
{
if (elementArrayBuffer)
{
- GLint64 offset = reinterpret_cast<GLint64>(indices);
- GLint64 byteCount =
- static_cast<GLint64>(typeBytes) * static_cast<GLint64>(count) + offset;
+ // The max possible type size is 8 and count is on 32 bits so doing the multiplication
+ // in a 64 bit integer is safe. Also we are guaranteed that here count > 0.
+ static_assert(std::is_same<int, GLsizei>::value, "GLsizei isn't the expected type");
+ constexpr uint64_t kMaxTypeSize = 8;
+ constexpr uint64_t kIntMax = std::numeric_limits<int>::max();
+ constexpr uint64_t kUint64Max = std::numeric_limits<uint64_t>::max();
+ static_assert(kIntMax < kUint64Max / kMaxTypeSize, "");
- // check for integer overflows
- if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeBytes) ||
- byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max()))
+ uint64_t typeSize = typeBytes;
+ uint64_t elementCount = static_cast<uint64_t>(count);
+ ASSERT(elementCount > 0 && typeSize <= kMaxTypeSize);
+
+ // Doing the multiplication here is overflow-safe
+ uint64_t elementDataSizeNoOffset = typeSize * elementCount;
+
+ // The offset can be any value, check for overflows
+ uint64_t offset = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(indices));
+ if (elementDataSizeNoOffset > kUint64Max - offset)
{
- context->handleError(Error(GL_OUT_OF_MEMORY, "Integer overflow."));
+ context->handleError(Error(GL_INVALID_OPERATION, "Integer overflow."));
return false;
}
- // Check for reading past the end of the bound buffer object
- if (byteCount > elementArrayBuffer->getSize())
+ uint64_t elementDataSizeWithOffset = elementDataSizeNoOffset + offset;
+ if (elementDataSizeWithOffset > static_cast<uint64_t>(elementArrayBuffer->getSize()))
{
context->handleError(
Error(GL_INVALID_OPERATION, "Index buffer is not big enough for the draw."));