summaryrefslogtreecommitdiffstats
path: root/gpu
diff options
context:
space:
mode:
authorzmo@chromium.org <zmo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-24 22:59:31 +0000
committerzmo@chromium.org <zmo@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-24 22:59:31 +0000
commitdb2833886f19cd4a687b5159e066e89d889ad21a (patch)
treed8a19291ec7886d680b452f6a198bc9f5c6973b9 /gpu
parentf4e972d7809c0383fb61593f0376fc13454c031a (diff)
downloadchromium_src-db2833886f19cd4a687b5159e066e89d889ad21a.zip
chromium_src-db2833886f19cd4a687b5159e066e89d889ad21a.tar.gz
chromium_src-db2833886f19cd4a687b5159e066e89d889ad21a.tar.bz2
Disallow sizes and offsets that can't fit into a 32-bit integer in GL.
So we have consistent behaviors on various systems. BUG=363869 TEST=gpu_unittests, http://www.khronos.org/registry/webgl/sdk/tests/conformance/rendering/draw-elements-out-of-bounds.html on 64 bit systems. R=piman@chromium.org, kbr@chromium.org Review URL: https://codereview.chromium.org/246403012 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@266021 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu')
-rw-r--r--gpu/command_buffer/client/gles2_implementation.cc60
-rw-r--r--gpu/command_buffer/client/gles2_implementation.h8
-rw-r--r--gpu/command_buffer/client/gles2_implementation_unittest.cc106
-rw-r--r--gpu/command_buffer/common/gles2_cmd_utils.h8
4 files changed, 172 insertions, 10 deletions
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index 6b64d82..3fe999a 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -865,6 +865,10 @@ void GLES2Implementation::DrawElements(
if (count == 0) {
return;
}
+ if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
+ !ValidateOffset("glDrawElements", reinterpret_cast<GLintptr>(indices))) {
+ return;
+ }
GLuint offset = 0;
bool simulated = false;
if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
@@ -1266,7 +1270,6 @@ void GLES2Implementation::PixelStorei(GLenum pname, GLint param) {
CheckGLError();
}
-
void GLES2Implementation::VertexAttribPointer(
GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
const void* ptr) {
@@ -1288,10 +1291,18 @@ void GLES2Implementation::VertexAttribPointer(
#if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
if (bound_array_buffer_id_ != 0) {
// Only report NON client side buffers to the service.
+ if (!ValidateOffset("glVertexAttribPointer",
+ reinterpret_cast<GLintptr>(ptr))) {
+ return;
+ }
helper_->VertexAttribPointer(index, size, type, normalized, stride,
ToGLuint(ptr));
}
#else // !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
+ if (!ValidateOffset("glVertexAttribPointer",
+ reinterpret_cast<GLintptr>(ptr))) {
+ return;
+ }
helper_->VertexAttribPointer(index, size, type, normalized, stride,
ToGLuint(ptr));
#endif // !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
@@ -1381,10 +1392,8 @@ void GLES2Implementation::ShaderSource(
void GLES2Implementation::BufferDataHelper(
GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
- if (size < 0) {
- SetGLError(GL_INVALID_VALUE, "glBufferData", "size < 0");
+ if (!ValidateSize("glBufferData", size))
return;
- }
GLuint buffer_id;
if (GetBoundPixelTransferBuffer(target, "glBufferData", &buffer_id)) {
@@ -1455,8 +1464,8 @@ void GLES2Implementation::BufferSubDataHelper(
return;
}
- if (size < 0) {
- SetGLError(GL_INVALID_VALUE, "glBufferSubData", "size < 0");
+ if (!ValidateSize("glBufferSubData", size) ||
+ !ValidateOffset("glBufferSubData", offset)) {
return;
}
@@ -1893,9 +1902,9 @@ void GLES2Implementation::TexSubImage2D(
}
static GLint ComputeNumRowsThatFitInBuffer(
- GLsizeiptr padded_row_size, GLsizeiptr unpadded_row_size,
+ uint32 padded_row_size, uint32 unpadded_row_size,
unsigned int size) {
- DCHECK_GE(unpadded_row_size, 0);
+ DCHECK_GE(unpadded_row_size, 0u);
if (padded_row_size == 0) {
return 1;
}
@@ -2916,10 +2925,11 @@ void* GLES2Implementation::MapBufferSubDataCHROMIUM(
"glMapBufferSubDataCHROMIUM", access, "access");
return NULL;
}
- if (offset < 0 || size < 0) {
- SetGLError(GL_INVALID_VALUE, "glMapBufferSubDataCHROMIUM", "bad range");
+ if (!ValidateSize("glMapBufferSubDataCHROMIUM", size) ||
+ !ValidateOffset("glMapBufferSubDataCHROMIUM", offset)) {
return NULL;
}
+
int32 shm_id;
unsigned int shm_offset;
void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
@@ -3129,6 +3139,7 @@ void GLES2Implementation::GetMultipleIntegervCHROMIUM(
" " << i << ": " << GLES2Util::GetStringGLState(pnames[i]));
}
});
+ DCHECK(size >= 0 && FitInt32NonNegative<GLsizeiptr>(size));
GetMultipleIntegervState state(pnames, count, results, size);
if (!GetMultipleIntegervSetup(&state)) {
@@ -3536,6 +3547,11 @@ void GLES2Implementation::DrawElementsInstancedANGLE(
if (primcount == 0) {
return;
}
+ if (vertex_array_object_manager_->bound_element_array_buffer() != 0 &&
+ !ValidateOffset("glDrawElementsInstancedANGLE",
+ reinterpret_cast<GLintptr>(indices))) {
+ return;
+ }
GLuint offset = 0;
bool simulated = false;
if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
@@ -4097,6 +4113,30 @@ void GLES2Implementation::GetImageParameterivCHROMIUM(
CheckGLError();
}
+bool GLES2Implementation::ValidateSize(const char* func, GLsizeiptr size) {
+ if (size < 0) {
+ SetGLError(GL_INVALID_VALUE, func, "size < 0");
+ return false;
+ }
+ if (!FitInt32NonNegative<GLsizeiptr>(size)) {
+ SetGLError(GL_INVALID_OPERATION, func, "size more than 32-bit");
+ return false;
+ }
+ return true;
+}
+
+bool GLES2Implementation::ValidateOffset(const char* func, GLintptr offset) {
+ if (offset < 0) {
+ SetGLError(GL_INVALID_VALUE, func, "offset < 0");
+ return false;
+ }
+ if (!FitInt32NonNegative<GLintptr>(offset)) {
+ SetGLError(GL_INVALID_OPERATION, func, "offset more than 32-bit");
+ return false;
+ }
+ return true;
+}
+
// Include the auto-generated part of this file. We split this because it means
// we can easily edit the non-auto generated parts right here in this file
// instead of having to edit some template or the code generator.
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h
index eaf0d6f..45fb270 100644
--- a/gpu/command_buffer/client/gles2_implementation.h
+++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -597,6 +597,14 @@ class GLES2_IMPL_EXPORT GLES2Implementation
void OnSwapBuffersComplete();
+ // Validate if an offset is valid, i.e., non-negative and fit into 32-bit.
+ // If not, generate an approriate error, and return false.
+ bool ValidateOffset(const char* func, GLintptr offset);
+
+ // Validate if a size is valid, i.e., non-negative and fit into 32-bit.
+ // If not, generate an approriate error, and return false.
+ bool ValidateSize(const char* func, GLsizeiptr offset);
+
// Remove the transfer buffer from the buffer tracker. For buffers used
// asynchronously the memory is free:ed if the upload has completed. For
// other buffers, the memory is either free:ed immediately or free:ed pending
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc
index cb7f6bd..9224424 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest.cc
+++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -598,6 +598,10 @@ class GLES2ImplementationTest : public testing::Test {
return gl_->GetError();
}
+ const std::string& GetLastError() {
+ return gl_->GetLastError();
+ }
+
bool GetBucketContents(uint32 bucket_id, std::vector<int8>* data) {
return gl_->GetBucketContents(bucket_id, data);
}
@@ -3133,6 +3137,108 @@ TEST_F(GLES2ImplementationTest, ProduceTextureCHROMIUM) {
EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
}
+TEST_F(GLES2ImplementationTest, LimitSizeAndOffsetTo32Bit) {
+ GLsizeiptr size;
+ GLintptr offset;
+ if (sizeof(size) <= 4 || sizeof(offset) <= 4)
+ return;
+ // The below two casts should be no-op, as we return early if
+ // it's 32-bit system.
+ int64 value64 = 0x100000000;
+ size = static_cast<GLsizeiptr>(value64);
+ offset = static_cast<GLintptr>(value64);
+
+ const char kSizeOverflowMessage[] = "size more than 32-bit";
+ const char kOffsetOverflowMessage[] = "offset more than 32-bit";
+
+ const GLfloat buf[] = { 1.0, 1.0, 1.0, 1.0 };
+ const GLubyte indices[] = { 0 };
+
+ const GLuint kClientArrayBufferId = 0x789;
+ const GLuint kClientElementArrayBufferId = 0x790;
+ gl_->BindBuffer(GL_ARRAY_BUFFER, kClientArrayBufferId);
+ gl_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, kClientElementArrayBufferId);
+ EXPECT_EQ(GL_NO_ERROR, CheckError());
+
+ // Call BufferData() should succeed with legal paramaters.
+ gl_->BufferData(GL_ARRAY_BUFFER, sizeof(buf), buf, GL_DYNAMIC_DRAW);
+ gl_->BufferData(
+ GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_DYNAMIC_DRAW);
+ EXPECT_EQ(GL_NO_ERROR, CheckError());
+
+ // BufferData: size
+ gl_->BufferData(GL_ARRAY_BUFFER, size, buf, GL_DYNAMIC_DRAW);
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+ EXPECT_STREQ(kSizeOverflowMessage, GetLastError().c_str());
+
+ // Call BufferSubData() should succeed with legal paramaters.
+ gl_->BufferSubData(GL_ARRAY_BUFFER, 0, sizeof(buf[0]), buf);
+ EXPECT_EQ(GL_NO_ERROR, CheckError());
+
+ // BufferSubData: offset
+ gl_->BufferSubData(GL_ARRAY_BUFFER, offset, 1, buf);
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+ EXPECT_STREQ(kOffsetOverflowMessage, GetLastError().c_str());
+
+ // BufferSubData: size
+ EXPECT_EQ(GL_NO_ERROR, CheckError());
+ gl_->BufferSubData(GL_ARRAY_BUFFER, 0, size, buf);
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+ EXPECT_STREQ(kSizeOverflowMessage, GetLastError().c_str());
+
+ // Call MapBufferSubDataCHROMIUM() should succeed with legal paramaters.
+ EXPECT_TRUE(NULL != gl_->MapBufferSubDataCHROMIUM(
+ GL_ARRAY_BUFFER, 0, 1, GL_WRITE_ONLY));
+ EXPECT_EQ(GL_NO_ERROR, CheckError());
+
+ // MapBufferSubDataCHROMIUM: offset
+ EXPECT_TRUE(NULL == gl_->MapBufferSubDataCHROMIUM(
+ GL_ARRAY_BUFFER, offset, 1, GL_WRITE_ONLY));
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+ EXPECT_STREQ(kOffsetOverflowMessage, GetLastError().c_str());
+
+ // MapBufferSubDataCHROMIUM: size
+ EXPECT_EQ(GL_NO_ERROR, CheckError());
+ EXPECT_TRUE(NULL == gl_->MapBufferSubDataCHROMIUM(
+ GL_ARRAY_BUFFER, 0, size, GL_WRITE_ONLY));
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+ EXPECT_STREQ(kSizeOverflowMessage, GetLastError().c_str());
+
+ // Call DrawElements() should succeed with legal paramaters.
+ gl_->DrawElements(GL_POINTS, 1, GL_UNSIGNED_BYTE, NULL);
+ EXPECT_EQ(GL_NO_ERROR, CheckError());
+
+ // DrawElements: offset
+ gl_->DrawElements(
+ GL_POINTS, 1, GL_UNSIGNED_BYTE, reinterpret_cast<void*>(offset));
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+ EXPECT_STREQ(kOffsetOverflowMessage, GetLastError().c_str());
+
+ // Call DrawElementsInstancedANGLE() should succeed with legal paramaters.
+ gl_->DrawElementsInstancedANGLE(GL_POINTS, 1, GL_UNSIGNED_BYTE, NULL, 1);
+ EXPECT_EQ(GL_NO_ERROR, CheckError());
+
+ // DrawElementsInstancedANGLE: offset
+ gl_->DrawElementsInstancedANGLE(
+ GL_POINTS, 1, GL_UNSIGNED_BYTE, reinterpret_cast<void*>(offset), 1);
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+ EXPECT_STREQ(kOffsetOverflowMessage, GetLastError().c_str());
+
+ // Call VertexAttribPointer() should succeed with legal paramaters.
+ const GLuint kAttribIndex = 1;
+ const GLsizei kStride = 4;
+ gl_->VertexAttribPointer(
+ kAttribIndex, 1, GL_FLOAT, GL_FALSE, kStride, NULL);
+ EXPECT_EQ(GL_NO_ERROR, CheckError());
+
+ // VertexAttribPointer: offset
+ gl_->VertexAttribPointer(
+ kAttribIndex, 1, GL_FLOAT, GL_FALSE, kStride,
+ reinterpret_cast<void*>(offset));
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+ EXPECT_STREQ(kOffsetOverflowMessage, GetLastError().c_str());
+}
+
TEST_F(GLES2ImplementationManualInitTest, LoseContextOnOOM) {
ContextInitOptions init_options;
init_options.lose_context_when_out_of_memory = true;
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.h b/gpu/command_buffer/common/gles2_cmd_utils.h
index 0df1f31..52d93a3 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils.h
@@ -56,6 +56,14 @@ inline bool SafeAddInt32(int32 a, int32 b, int32* dst) {
return safe;
}
+// Return false if |value| is more than a 32 bit integer can represent.
+template<typename T>
+inline bool FitInt32NonNegative(T value) {
+ const int32 max = std::numeric_limits<int32>::max();
+ return (std::numeric_limits<T>::max() <= max ||
+ value <= static_cast<T>(max));
+}
+
// Utilties for GLES2 support.
class GLES2_UTILS_EXPORT GLES2Util {
public: