Bug 1495573 - avoid double refcount decrement along failure path. r=luke
authorLars T Hansen <lhansen@mozilla.com>
Tue, 02 Oct 2018 14:12:41 +0200
changeset 495113 9d0ccdab956d9037b083d2576cc54e587fb70f71
parent 495112 cfbdabe4e05df6426e7d49164d77a4767a41b0c4
child 495114 a1855d696e1ca886a4ed8f3668bc6830a8d1ccd6
push id9984
push userffxbld-merge
push dateMon, 15 Oct 2018 21:07:35 +0000
treeherdermozilla-beta@183d27ea8570 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs1495573
milestone64.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 1495573 - avoid double refcount decrement along failure path. r=luke
js/src/shell/js.cpp
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -6681,44 +6681,54 @@ GetSharedObject(JSContext* cx, unsigned 
           case MailboxTag::Empty: {
             break;
           }
           case MailboxTag::SharedArrayBuffer:
           case MailboxTag::WasmMemory: {
             // Flag was set in the sender; ensure it is set in the receiver.
             MOZ_ASSERT(cx->realm()->creationOptions().getSharedMemoryAndAtomicsEnabled());
 
+            // The protocol for creating a SAB requires the refcount to be
+            // incremented prior to the SAB creation.
+
             SharedArrayRawBuffer* buf = mbx->val.sarb.buffer;
             uint32_t length = mbx->val.sarb.length;
             if (!buf->addReference()) {
                 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SC_SAB_REFCNT_OFLO);
                 return false;
             }
-            auto dropBuf = MakeScopeExit([buf] { buf->dropReference(); });
+
+            // If the allocation fails we must decrement the refcount before
+            // returning.
 
             Rooted<ArrayBufferObjectMaybeShared*> maybesab(cx, SharedArrayBufferObject::New(cx, buf, length));
             if (!maybesab) {
-                return false;
-            }
+                buf->dropReference();
+                return false;
+            }
+
+            // At this point the SAB was created successfully and it owns the
+            // refcount-increase on the buffer that we performed above.  So even
+            // if we fail to allocate along any path below we must not decrement
+            // the refcount; the garbage collector must be allowed to handle
+            // that via finalization of the orphaned SAB object.
+
             if (mbx->tag == MailboxTag::SharedArrayBuffer) {
                 newObj = maybesab;
             } else {
                 if (!GlobalObject::ensureConstructor(cx, cx->global(), JSProto_WebAssembly)) {
                     return false;
                 }
-
                 RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmMemory).toObject());
                 newObj = WasmMemoryObject::create(cx, maybesab, proto);
                 MOZ_ASSERT_IF(newObj, newObj->as<WasmMemoryObject>().isShared());
-            }
-            if (!newObj) {
-                return false;
-            }
-
-            dropBuf.release();
+                if (!newObj) {
+                    return false;
+                }
+            }
 
             break;
           }
           case MailboxTag::WasmModule: {
             // Flag was set in the sender; ensure it is set in the receiver.
             MOZ_ASSERT(cx->realm()->creationOptions().getSharedMemoryAndAtomicsEnabled());
 
             if (!GlobalObject::ensureConstructor(cx, cx->global(), JSProto_WebAssembly)) {