Bug 976697 - Detect neutered buffers in typed array / typed object constructors r=sfink
authorNicholas D. Matsakis <nmatsakis@mozilla.com>
Wed, 26 Feb 2014 11:55:34 -0500
changeset 173841 719629050761
parent 173840 a83ecf923dec
child 173842 bb5bd88acaeb
push id26425
push userphilringnalda@gmail.com
push date2014-03-17 04:06 +0000
treeherdermozilla-central@5870a4beef4d [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/atopneuteredbuffer.js
js/src/jit-test/tests/TypedObject/bug976697.js
js/src/vm/ArrayBufferObject.h
js/src/vm/TypedArrayObject.cpp
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -2296,16 +2296,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;
             }
 
@@ -2402,16 +2408,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/atopneuteredbuffer.js
@@ -0,0 +1,23 @@
+// Bug 976697. Check for various quirks when instantiating a typed
+// object atop an already neutered buffer.
+
+if (typeof TypedObject === "undefined")
+  quit();
+
+load(libdir + "asserts.js")
+
+var {StructType, uint32, Object, Any, storage, objectType} = TypedObject;
+
+function main() { // once a C programmer, always a C programmer.
+  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");
+}
+
+main();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/TypedObject/bug976697.js
@@ -0,0 +1,13 @@
+// Test that instantiating a typed array on top of a neutered buffer
+// doesn't trip any asserts.
+//
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+if (!this.hasOwnProperty("TypedObject"))
+  quit();
+
+x = ArrayBuffer();
+neuter(x);
+Uint32Array(x);
+gc();
--- a/js/src/vm/ArrayBufferObject.h
+++ b/js/src/vm/ArrayBufferObject.h
@@ -297,17 +297,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);