Commit fe9306a8 by Corentin Wallez Committed by Commit Bot

WebGLCompatibility: Add test for "negative" offset in DrawElements

BUG=angleproject:1523 BUG=chromium:668223 Change-Id: I2d21c15b53fa204b3cb2b0be849cfe91ca63046b Reviewed-on: https://chromium-review.googlesource.com/435884Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Corentin Wallez <cwallez@chromium.org>
parent e16a4519
...@@ -3503,6 +3503,15 @@ bool ValidateDrawElements(ValidationContext *context, ...@@ -3503,6 +3503,15 @@ bool ValidateDrawElements(ValidationContext *context,
"indices must be a multiple of the element type size.")); "indices must be a multiple of the element type size."));
return false; 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 || if (context->getExtensions().webglCompatibility ||
...@@ -3523,20 +3532,31 @@ bool ValidateDrawElements(ValidationContext *context, ...@@ -3523,20 +3532,31 @@ bool ValidateDrawElements(ValidationContext *context,
{ {
if (elementArrayBuffer) if (elementArrayBuffer)
{ {
GLint64 offset = reinterpret_cast<GLint64>(indices); // The max possible type size is 8 and count is on 32 bits so doing the multiplication
GLint64 byteCount = // in a 64 bit integer is safe. Also we are guaranteed that here count > 0.
static_cast<GLint64>(typeBytes) * static_cast<GLint64>(count) + offset; static_assert(std::is_same<int, GLsizei>::value, "GLsizei isn't the expected type");
constexpr uint64_t kMaxTypeSize = 8;
// check for integer overflows constexpr uint64_t kIntMax = std::numeric_limits<int>::max();
if (static_cast<GLuint>(count) > (std::numeric_limits<GLuint>::max() / typeBytes) || constexpr uint64_t kUint64Max = std::numeric_limits<uint64_t>::max();
byteCount > static_cast<GLint64>(std::numeric_limits<GLuint>::max())) static_assert(kIntMax < kUint64Max / kMaxTypeSize, "");
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; return false;
} }
// Check for reading past the end of the bound buffer object uint64_t elementDataSizeWithOffset = elementDataSizeNoOffset + offset;
if (byteCount > elementArrayBuffer->getSize()) if (elementDataSizeWithOffset > static_cast<uint64_t>(elementArrayBuffer->getSize()))
{ {
context->handleError( context->handleError(
Error(GL_INVALID_OPERATION, "Index buffer is not big enough for the draw.")); Error(GL_INVALID_OPERATION, "Index buffer is not big enough for the draw."));
......
...@@ -445,6 +445,16 @@ TEST_P(WebGLCompatibilityTest, DrawElementsBufferOutOfBoundsInIndexBuffer) ...@@ -445,6 +445,16 @@ TEST_P(WebGLCompatibilityTest, DrawElementsBufferOutOfBoundsInIndexBuffer)
// Test any offset if valid if count is zero // Test any offset if valid if count is zero
glDrawElements(GL_POINTS, 0, GL_UNSIGNED_BYTE, zeroOffset + 42); glDrawElements(GL_POINTS, 0, GL_UNSIGNED_BYTE, zeroOffset + 42);
ASSERT_GL_NO_ERROR(); ASSERT_GL_NO_ERROR();
// Test touching the first index is valid
glDrawElements(GL_POINTS, 4, GL_UNSIGNED_BYTE, zeroOffset + 4);
ASSERT_GL_NO_ERROR();
// Test touching the first - 1 index is invalid
// The error ha been specified to be INVALID_VALUE instead of INVALID_OPERATION because it was
// the historic behavior of WebGL implementations
glDrawElements(GL_POINTS, 4, GL_UNSIGNED_BYTE, zeroOffset - 1);
EXPECT_GL_ERROR(GL_INVALID_VALUE);
} }
// Test depth range with 'near' more or less than 'far.' // Test depth range with 'near' more or less than 'far.'
......
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