Bug 1329187 - Call GetPrototypeFromConstructor before checking the ArrayBuffer length. r=evilpie
authorAndré Bargull <andre.bargull@gmail.com>
Wed, 11 Jan 2017 14:08:00 -0800
changeset 374736 ec0bd468598df93bdd0d4395412e829636d7ea2f
parent 374735 51c9e4c7bd08f04b294caf45cb5eaa390cb0d516
child 374737 e9850399c17efdbabadf9b4f4dc08023f88d90fb
push id6996
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 20:48:21 +0000
treeherdermozilla-beta@d89512dab048 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersevilpie
bugs1329187
milestone53.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 1329187 - Call GetPrototypeFromConstructor before checking the ArrayBuffer length. r=evilpie
js/src/tests/test262/built-ins/ArrayBuffer/data-allocation-after-object-creation.js
js/src/vm/ArrayBufferObject.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/tests/test262/built-ins/ArrayBuffer/data-allocation-after-object-creation.js
@@ -0,0 +1,38 @@
+// Copyright (C) 2015 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+es6id: 24.1.2.1
+description: >
+  The new ArrayBuffer instance is created prior to allocating the Data Block.
+info: >
+  ArrayBuffer( length )
+
+  ...
+  6. Return AllocateArrayBuffer(NewTarget, byteLength).
+
+  AllocateArrayBuffer( constructor, byteLength )
+    1. Let obj be OrdinaryCreateFromConstructor(constructor, "%ArrayBufferPrototype%",
+       «[[ArrayBufferData]], [[ArrayBufferByteLength]]» ).
+    2. ReturnIfAbrupt(obj).
+    ...
+    4. Let block be CreateByteDataBlock(byteLength).
+    5. ReturnIfAbrupt(block).
+    ...
+features: [Reflect.construct]
+---*/
+
+function DummyError() { }
+
+var newTarget = function(){}.bind(null);
+Object.defineProperty(newTarget, "prototype", {
+  get: function() {
+    throw new DummyError();
+  }
+});
+
+assert.throws(DummyError, function() {
+  // Allocating 7 PiB should fail with a RangeError.
+  // Math.pow(1024, 5) = 1125899906842624
+  Reflect.construct(ArrayBuffer, [7 * 1125899906842624], newTarget);
+});
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -275,28 +275,31 @@ ArrayBufferObject::class_constructor(JSC
     if (!ThrowIfNotConstructing(cx, args, "ArrayBuffer"))
         return false;
 
     // Step 2.
     uint64_t byteLength;
     if (!ToIndex(cx, args.get(0), &byteLength))
         return false;
 
-    // Non-standard: Refuse to allocate buffers larger than ~2 GiB.
+    // Step 3 (Inlined 24.1.1.1 AllocateArrayBuffer).
+    // 24.1.1.1, step 1 (Inlined 9.1.14 OrdinaryCreateFromConstructor).
+    RootedObject proto(cx);
+    RootedObject newTarget(cx, &args.newTarget().toObject());
+    if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
+        return false;
+
+    // 24.1.1.1, step 3 (Inlined 6.2.6.1 CreateByteDataBlock, step 2).
+    // Refuse to allocate too large buffers, currently limited to ~2 GiB.
     if (byteLength > INT32_MAX) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
         return false;
     }
 
-    // Step 3.
-    RootedObject proto(cx);
-    RootedObject newTarget(cx, &args.newTarget().toObject());
-    if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
-        return false;
-
+    // 24.1.1.1, steps 1 and 4-6.
     JSObject* bufobj = create(cx, uint32_t(byteLength), proto);
     if (!bufobj)
         return false;
     args.rval().setObject(*bufobj);
     return true;
 }
 
 static ArrayBufferObject::BufferContents