Bug 747619 - Fix WebGL uniform setter validation - r=jgilbert
authorBenoit Jacob <bjacob@mozilla.com>
Sun, 06 May 2012 23:09:36 -0400
changeset 93334 dc76558cbd418dbe93214f525d5d00e5cd28579e
parent 93333 241b44d55176dd28e2fdcce816452613fb7388de
child 93335 6eb9af883b3b7b202029ae61c23aede67e1b21d3
push id22628
push usereakhgari@mozilla.com
push dateMon, 07 May 2012 23:03:04 +0000
treeherdermozilla-central@333626f688a4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert
bugs747619, 732233
milestone15.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 747619 - Fix WebGL uniform setter validation - r=jgilbert This bug, introduced by the patch from bug 732233, caused us to wrongly reject legitimate WebGL uniform setters, especially when doing a partial update of a uniform array.
content/canvas/src/WebGLContextGL.cpp
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -4612,17 +4612,17 @@ GetFloat32Array(JSContext* aCx, const JS
     if (!mCurrentProgram) \
         return ErrorInvalidOperation("%s: no program is currently bound", info); \
     if (mCurrentProgram != location_object->Program()) \
         return ErrorInvalidOperation("%s: this uniform location doesn't correspond to the current program", info); \
     if (mCurrentProgram->Generation() != location_object->ProgramGeneration())            \
         return ErrorInvalidOperation("%s: This uniform location is obsolete since the program has been relinked", info); \
     GLint location = location_object->Location();
 
-#define SIMPLE_ARRAY_METHOD_UNIFORM(name, cnt, arrayType, ptrType)              \
+#define SIMPLE_ARRAY_METHOD_UNIFORM(name, expectedElemSize, arrayType, ptrType) \
 NS_IMETHODIMP                                                                   \
 WebGLContext::name(nsIWebGLUniformLocation *aLocation, const JS::Value& aValue, \
                    JSContext* aCx)                                              \
 {                                                                               \
     JSObject* wa = GetTypedArray<JS_Is ## arrayType ## Array, JS_New ## arrayType ## ArrayFromArray>(aCx, aValue); \
     if (!wa) {                                                                  \
         return NS_ERROR_FAILURE;                                                \
     }                                                                           \
@@ -4633,48 +4633,46 @@ WebGLContext::name(nsIWebGLUniformLocati
 void                                                                            \
 WebGLContext::name##_base(WebGLUniformLocation *location_object,                \
                         uint32_t arrayLength, ptrType* data) {                  \
     if (!IsContextStable()) {                                                   \
         return;                                                                 \
     }                                                                           \
                                                                                 \
     OBTAIN_UNIFORM_LOCATION(#name ": location")                                 \
-    int elementSize = location_object->ElementSize();                           \
-    if (cnt != elementSize) {                                                   \
+    int uniformElemSize = location_object->ElementSize();                           \
+    if (expectedElemSize != uniformElemSize) {                                                   \
         return ErrorInvalidOperation(                                           \
             #name ": this function expected a uniform of element size %d,"      \
             " got a uniform of element size %d",                                \
-            cnt,                                                                \
-            elementSize);                                                       \
+            expectedElemSize,                                                                \
+            uniformElemSize);                                                       \
     }                                                                           \
     const WebGLUniformInfo& info = location_object->Info();                     \
-    PRUint32 expectedArrayLength = cnt * info.arraySize;                        \
-    if (arrayLength < expectedArrayLength ||                                    \
-        (arrayLength % cnt))                                                    \
+    if (arrayLength == 0 ||                                                     \
+        arrayLength % expectedElemSize)                                                      \
     {                                                                           \
         return ErrorInvalidValue("%s: expected an array of length a multiple of" \
-                                 " %d and at least %d, got an array of length %d", \
+                                 " %d, got an array of length %d",              \
                                  #name,                                         \
-                                 cnt,                                           \
-                                 expectedArrayLength,                           \
+                                 expectedElemSize,                                           \
                                  arrayLength);                                  \
     }                                                                           \
     if (!info.isArray &&                                                        \
-        arrayLength > expectedArrayLength) {                                    \
+        arrayLength != expectedElemSize) {                                                   \
         return ErrorInvalidOperation("%s: expected an array of length exactly %d" \
                                      " (since this uniform is not an array uniform)," \
-                                     " got an array of length %d", \
+                                     " got an array of length %d",              \
                                  #name,                                         \
-                                 expectedArrayLength,                           \
+                                 expectedElemSize,                           \
                                  arrayLength);                                  \
     }                                                                           \
                                                                                 \
-    MakeContextCurrent();                                                       \
-    gl->f##name(location, info.arraySize, data);                                \
+    PRUint32 numElementsToUpload = NS_MIN(info.arraySize, arrayLength/expectedElemSize);     \
+    gl->f##name(location, numElementsToUpload, data);    \
 }
 
 #define SIMPLE_MATRIX_METHOD_UNIFORM(name, dim)                                 \
 NS_IMETHODIMP                                                                   \
 WebGLContext::name(nsIWebGLUniformLocation* aLocation, bool aTranspose,         \
                    const JS::Value& aValue, JSContext* aCx)                     \
 {                                                                               \
     JSObject* wa = GetFloat32Array(aCx, aValue);                                \
@@ -4685,57 +4683,57 @@ WebGLContext::name(nsIWebGLUniformLocati
     name(static_cast<WebGLUniformLocation*>(aLocation), aTranspose, arr);       \
     return NS_OK;                                                               \
 }                                                                               \
 void                                                                            \
 WebGLContext::name##_base(WebGLUniformLocation* location_object,                \
                           WebGLboolean aTranspose, uint32_t arrayLength,        \
                           float* data)                                          \
 {                                                                               \
+    PRUint32 expectedElemSize = (dim)*(dim);                                                     \
     if (!IsContextStable()) {                                                   \
         return;                                                                 \
     }                                                                           \
                                                                                 \
     OBTAIN_UNIFORM_LOCATION(#name ": location")                                 \
-    int elementSize = location_object->ElementSize();                           \
-    if (dim*dim != elementSize) {                                               \
+    PRUint32 uniformElemSize = location_object->ElementSize();                           \
+    if (expectedElemSize != uniformElemSize) {                                               \
         return ErrorInvalidOperation(                                           \
             #name ": this function expected a uniform of element size %d,"      \
             " got a uniform of element size %d",                                \
-            dim*dim,                                                            \
-            elementSize);                                                       \
+            expectedElemSize,                                                            \
+            uniformElemSize);                                                       \
     }                                                                           \
     const WebGLUniformInfo& info = location_object->Info();                     \
-    PRUint32 expectedArrayLength = dim * dim * info.arraySize;                  \
-    if (arrayLength < expectedArrayLength ||                                    \
-        (arrayLength % (dim*dim)))                                              \
+    if (arrayLength == 0 ||                                                     \
+        arrayLength % expectedElemSize)                                                \
     {                                                                           \
         return ErrorInvalidValue("%s: expected an array of length a multiple of" \
-                                 " %d and at least %d, got an array of length %d", \
+                                 " %d, got an array of length %d",              \
                                  #name,                                         \
-                                 dim*dim,                                       \
-                                 expectedArrayLength,                           \
+                                 expectedElemSize,                                       \
                                  arrayLength);                                  \
     }                                                                           \
-    if (!info.isArray &&                                          \
-        arrayLength > expectedArrayLength) {                                    \
+    if (!info.isArray &&                                                        \
+        arrayLength != expectedElemSize) {                                               \
         return ErrorInvalidOperation("%s: expected an array of length exactly %d" \
                                      " (since this uniform is not an array uniform)," \
                                      " got an array of length %d", \
                                  #name,                                         \
-                                 expectedArrayLength,                           \
+                                 expectedElemSize,                           \
                                  arrayLength);                                  \
     }                                                                           \
     if (aTranspose) {                                                           \
         return ErrorInvalidValue(#name ": transpose must be FALSE as per the "  \
                                  "OpenGL ES 2.0 spec");                         \
     }                                                                           \
                                                                                 \
     MakeContextCurrent();                                                       \
-    gl->f##name(location, info.arraySize, false,  data);                        \
+    PRUint32 numElementsToUpload = NS_MIN(info.arraySize, arrayLength/(expectedElemSize));  \
+    gl->f##name(location, numElementsToUpload, false, data); \
 }
 
 #define SIMPLE_METHOD_UNIFORM_1(glname, name, t1)        \
 NS_IMETHODIMP WebGLContext::name(nsIWebGLUniformLocation *ploc, t1 a1) {      \
     name(static_cast<WebGLUniformLocation*>(ploc), a1);                 \
     return NS_OK;                                                       \
 }                                                                       \
 void WebGLContext::name(WebGLUniformLocation *location_object, t1 a1) { \