Bug 1448522 - Handle errors in transferOwnership correctly, r=jorendorff
authorSteve Fink <sfink@mozilla.com>
Fri, 23 Mar 2018 20:03:55 -0700
changeset 469212 ee36b000e3adae7acc7976372eeed1f1ca8db6ef
parent 469211 6cd19d2e0138d698749d329088659ab4d4a9810c
child 469213 db04d03e84185756c423bd40141fa45e7004d05a
push id9165
push userasasaki@mozilla.com
push dateThu, 26 Apr 2018 21:04:54 +0000
treeherdermozilla-beta@064c3804de2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs1448522
milestone61.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 1448522 - Handle errors in transferOwnership correctly, r=jorendorff
js/src/tests/non262/extensions/clone-transferables.js
js/src/vm/StructuredClone.cpp
--- a/js/src/tests/non262/extensions/clone-transferables.js
+++ b/js/src/tests/non262/extensions/clone-transferables.js
@@ -88,22 +88,39 @@ function test() {
             var viewCopy = new Int32Array(copy[0]);
             assertEq(view.length, 0); // Underlying buffer now detached.
             assertEq(viewCopy[0], 2);
         }
 
         // Detach the buffer during the clone operation. Should throw an
         // exception.
         if (size >= 4) {
-            old = new ArrayBuffer(size);
-            var mutator = {
+            const b1 = new ArrayBuffer(size);
+            let mutator = {
                 get foo() {
-                    deserialize(serialize(old, [old], { scope }), { scope });
+                    serialize(b1, [b1], { scope });
                 }
             };
-            // The throw is not yet implemented, bug 919259.
-            //var copy = deserialize(serialize([ old, mutator ], [old]));
+
+            assertThrowsInstanceOf(
+                () => serialize([ b1, mutator ], [b1]),
+                TypeError,
+                "detaching (due to Transferring) while serializing should throw"
+            );
+
+            const b2 = new ArrayBuffer(size);
+            mutator = {
+                get foo() {
+                    detachArrayBuffer(b2);
+                }
+            };
+
+            assertThrowsInstanceOf(
+                () => serialize([ b2, mutator ], [b2]),
+                TypeError,
+                "detaching (due to detachArrayBuffer) while serializing should throw"
+            );
         }
     }
 }
 
 test();
 reportCompare(0, 0, 'ok');
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -1696,44 +1696,51 @@ JSStructuredCloneWriter::transferOwnersh
 
             size_t nbytes = arrayBuffer->byteLength();
 
             if (arrayBuffer->isWasm() || arrayBuffer->isPreparedForAsmJS()) {
                 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_NO_TRANSFER);
                 return false;
             }
 
+            if (arrayBuffer->isDetached()) {
+                JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
+                return false;
+            }
+
             if (scope == JS::StructuredCloneScope::DifferentProcess) {
                 // Write Transferred ArrayBuffers in DifferentProcess scope at
                 // the end of the clone buffer, and store the offset within the
                 // buffer to where the ArrayBuffer was written. Note that this
                 // will invalidate the current position iterator.
 
                 size_t pointOffset = out.offset(point);
                 tag = SCTAG_TRANSFER_MAP_STORED_ARRAY_BUFFER;
                 ownership = JS::SCTAG_TMO_UNOWNED;
                 content = nullptr;
                 extraData = out.tell() - pointOffset; // Offset from tag to current end of buffer
-                if (!writeArrayBuffer(arrayBuffer))
+                if (!writeArrayBuffer(arrayBuffer)) {
+                    ReportOutOfMemory(cx);
                     return false;
+                }
 
                 // Must refresh the point iterator after its collection has
                 // been modified.
                 point = out.iter();
                 point += pointOffset;
 
                 if (!JS_DetachArrayBuffer(cx, arrayBuffer))
                     return false;
             } else {
                 bool hasStealableContents = arrayBuffer->hasStealableContents();
 
                 ArrayBufferObject::BufferContents bufContents =
                     ArrayBufferObject::stealContents(cx, arrayBuffer, hasStealableContents);
                 if (!bufContents)
-                    return false; // already transferred data
+                    return false; // out of memory
 
                 content = bufContents.data();
                 if (bufContents.kind() == ArrayBufferObject::MAPPED)
                     ownership = JS::SCTAG_TMO_MAPPED_DATA;
                 else
                     ownership = JS::SCTAG_TMO_ALLOC_DATA;
                 extraData = nbytes;
             }