Bug 976697 - Detect neutered buffers in typed array / typed object constructors r=sfink
☠☠ backed out by 4647aa53d286 ☠ ☠
authorNicholas D. Matsakis <nmatsakis@mozilla.com>
Wed, 26 Feb 2014 11:55:34 -0500
changeset 190414 bef8a33f2d8f84777bb3056c45b61147f75864b4
parent 190413 bbc1eb14098a03afc2496c0c23d80e6153c73e02
child 190415 6dc60397b3a1211895344c131aeb9a69f189f043
push id3503
push userraliiev@mozilla.com
push dateMon, 28 Apr 2014 18:51:11 +0000
treeherdermozilla-beta@c95ac01e332e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs976697
milestone30.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 976697 - Detect neutered buffers in typed array / typed object constructors r=sfink
js/src/builtin/TypedObject.cpp
js/src/jit-test/tests/TypedObject/bug976697.js
js/src/tests/ecma_6/TypedObject/atopneuteredbuffer.js
js/src/vm/ArrayBufferObject.h
js/src/vm/TypedArrayObject.cpp
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -2287,16 +2287,22 @@ TypedObject::constructSized(JSContext *c
         return true;
     }
 
     // Buffer constructor.
     if (args[0].isObject() && args[0].toObject().is<ArrayBufferObject>()) {
         Rooted<ArrayBufferObject*> buffer(cx);
         buffer = &args[0].toObject().as<ArrayBufferObject>();
 
+        if (buffer->isNeutered()) {
+            JS_ReportErrorNumber(cx, js_GetErrorMessage,
+                                 nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
+            return false;
+        }
+
         int32_t offset;
         if (args.length() >= 2 && !args[1].isUndefined()) {
             if (!args[1].isInt32()) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage,
                                      nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
                 return false;
             }
 
@@ -2393,16 +2399,22 @@ TypedObject::constructUnsized(JSContext 
         return true;
     }
 
     // Buffer constructor.
     if (args[0].isObject() && args[0].toObject().is<ArrayBufferObject>()) {
         Rooted<ArrayBufferObject*> buffer(cx);
         buffer = &args[0].toObject().as<ArrayBufferObject>();
 
+        if (buffer->isNeutered()) {
+            JS_ReportErrorNumber(cx, js_GetErrorMessage,
+                                 nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
+            return false;
+        }
+
         int32_t offset;
         if (args.length() >= 2 && !args[1].isUndefined()) {
             if (!args[1].isInt32()) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage,
                                      nullptr, JSMSG_TYPEDOBJECT_BAD_ARGS);
                 return false;
             }
 
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/TypedObject/bug976697.js
@@ -0,0 +1,10 @@
+// Test that instantiating a typed array on top of a neutered buffer
+// doesn't trip any asserts. Public domain.
+
+if (!this.hasOwnProperty("TypedObject"))
+  quit();
+
+x = ArrayBuffer();
+neuter(x);
+Uint32Array(x);
+gc();
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/TypedObject/atopneuteredbuffer.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty("TypedObject"))
+var BUGNUMBER = 976697;
+
+var {StructType, uint32, Object, Any, storage, objectType} = TypedObject;
+
+function main() { // once a C programmer, always a C programmer.
+  print(BUGNUMBER + ": " + summary);
+
+  var Uints = uint32.array();
+  var Unit = new StructType({});   // Empty struct type
+  var buffer = new ArrayBuffer(0); // Empty buffer
+  var p = new Unit(buffer);        // OK
+  neuter(buffer);
+  assertThrowsInstanceOf(() => new Unit(buffer), TypeError,
+                         "Able to instantiate atop neutered buffer");
+  assertThrowsInstanceOf(() => new Uints(buffer, 0), TypeError,
+                         "Able to instantiate atop neutered buffer");
+
+  reportCompare(true, true);
+  print("Tests complete");
+}
+
+main();
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -273,17 +273,24 @@ PostBarrierTypedArrayObject(JSObject *ob
 inline void
 InitArrayBufferViewDataPointer(ArrayBufferViewObject *obj, ArrayBufferObject *buffer, size_t byteOffset)
 {
     /*
      * N.B. The base of the array's data is stored in the object's
      * private data rather than a slot to avoid alignment restrictions
      * on private Values.
      */
-    obj->initPrivate(buffer->dataPointer() + byteOffset);
+
+    if (buffer->isNeutered()) {
+        JS_ASSERT(byteOffset == 0);
+        obj->initPrivate(nullptr);
+    } else {
+        obj->initPrivate(buffer->dataPointer() + byteOffset);
+    }
+
     PostBarrierTypedArrayObject(obj);
 }
 
 /*
  * Tests for either ArrayBufferObject or SharedArrayBufferObject.
  * For specific class testing, use e.g., obj->is<ArrayBufferObject>().
  */
 bool IsArrayBuffer(HandleValue v);
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -357,17 +357,17 @@ class TypedArrayObjectTemplate : public 
         if (!empty)
             return nullptr;
         obj->setLastPropertyInfallible(empty);
 
 #ifdef DEBUG
         uint32_t bufferByteLength = buffer->byteLength();
         uint32_t arrayByteLength = obj->byteLength();
         uint32_t arrayByteOffset = obj->byteOffset();
-        JS_ASSERT(buffer->dataPointer() <= obj->viewData());
+        JS_ASSERT_IF(!buffer->isNeutered(), buffer->dataPointer() <= obj->viewData());
         JS_ASSERT(bufferByteLength - arrayByteOffset >= arrayByteLength);
         JS_ASSERT(arrayByteOffset <= bufferByteLength);
 
         // Verify that the private slot is at the expected place
         JS_ASSERT(obj->numFixedSlots() == DATA_SLOT);
 #endif
 
         buffer->addView(obj);