diff --git a/dom/base/StructuredCloneHolder.cpp b/dom/base/StructuredCloneHolder.cpp index 5a07697ac222a..d04a99a717bc9 100644 --- a/dom/base/StructuredCloneHolder.cpp +++ b/dom/base/StructuredCloneHolder.cpp @@ -57,11 +57,14 @@ JSObject* StructuredCloneCallbacksRead(JSContext* aCx, bool StructuredCloneCallbacksWrite(JSContext* aCx, JSStructuredCloneWriter* aWriter, - JS::Handle aObj, void* aClosure) { + JS::Handle aObj, + bool* aSameProcessScopeRequired, + void* aClosure) { StructuredCloneHolderBase* holder = static_cast(aClosure); MOZ_ASSERT(holder); - return holder->CustomWriteHandler(aCx, aWriter, aObj); + return holder->CustomWriteHandler(aCx, aWriter, aObj, + aSameProcessScopeRequired); } bool StructuredCloneCallbacksReadTransfer( @@ -100,11 +103,13 @@ void StructuredCloneCallbacksFreeTransfer(uint32_t aTag, bool StructuredCloneCallbacksCanTransfer(JSContext* aCx, JS::Handle aObject, + bool* aSameProcessScopeRequired, void* aClosure) { StructuredCloneHolderBase* holder = static_cast(aClosure); MOZ_ASSERT(holder); - return holder->CustomCanTransferHandler(aCx, aObject); + return holder->CustomCanTransferHandler(aCx, aObject, + aSameProcessScopeRequired); } void StructuredCloneCallbacksError(JSContext* aCx, uint32_t aErrorId) { @@ -229,7 +234,8 @@ void StructuredCloneHolderBase::CustomFreeTransferHandler( } bool StructuredCloneHolderBase::CustomCanTransferHandler( - JSContext* aCx, JS::Handle aObj) { + JSContext* aCx, JS::Handle aObj, + bool* aSameProcessScopeRequired) { return false; } @@ -321,9 +327,9 @@ void StructuredCloneHolder::ReadFromBuffer(nsIGlobalObject* aGlobal, mozilla::AutoRestore guard(mGlobal); mGlobal = aGlobal; - if (!JS_ReadStructuredClone(aCx, aBuffer, aAlgorithmVersion, - mStructuredCloneScope, aValue, - JS::CloneDataPolicy(), &sCallbacks, this)) { + if (!JS_ReadStructuredClone(aCx, aBuffer, aAlgorithmVersion, CloneScope(), + aValue, JS::CloneDataPolicy(), &sCallbacks, + this)) { JS_ClearPendingException(aCx); aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); } @@ -884,7 +890,7 @@ JSObject* StructuredCloneHolder::CustomReadHandler( } if (aTag == SCTAG_DOM_IMAGEBITMAP && - mStructuredCloneScope == StructuredCloneScope::SameProcess) { + CloneScope() == StructuredCloneScope::SameProcess) { // Get the current global object. // This can be null. JS::RootedObject result(aCx); @@ -901,7 +907,7 @@ JSObject* StructuredCloneHolder::CustomReadHandler( } if (aTag == SCTAG_DOM_WASM && - mStructuredCloneScope == StructuredCloneScope::SameProcess) { + CloneScope() == StructuredCloneScope::SameProcess) { return ReadWasmModule(aCx, aIndex, this); } @@ -920,9 +926,9 @@ JSObject* StructuredCloneHolder::CustomReadHandler( return ReadFullySerializableObjects(aCx, aReader, aTag); } -bool StructuredCloneHolder::CustomWriteHandler(JSContext* aCx, - JSStructuredCloneWriter* aWriter, - JS::Handle aObj) { +bool StructuredCloneHolder::CustomWriteHandler( + JSContext* aCx, JSStructuredCloneWriter* aWriter, + JS::Handle aObj, bool* aSameProcessScopeRequired) { if (!mSupportsCloning) { return false; } @@ -962,11 +968,16 @@ bool StructuredCloneHolder::CustomWriteHandler(JSContext* aCx, } // See if this is an ImageBitmap object. - if (mStructuredCloneScope == StructuredCloneScope::SameProcess) { + { ImageBitmap* imageBitmap = nullptr; if (NS_SUCCEEDED(UNWRAP_OBJECT(ImageBitmap, &obj, imageBitmap))) { - return ImageBitmap::WriteStructuredClone(aWriter, GetSurfaces(), - imageBitmap); + SameProcessScopeRequired(aSameProcessScopeRequired); + + if (CloneScope() == StructuredCloneScope::SameProcess) { + return ImageBitmap::WriteStructuredClone(aWriter, GetSurfaces(), + imageBitmap); + } + return false; } } @@ -979,8 +990,7 @@ bool StructuredCloneHolder::CustomWriteHandler(JSContext* aCx, } // See if this is a BrowsingContext object. - if (mStructuredCloneScope == StructuredCloneScope::SameProcess || - mStructuredCloneScope == StructuredCloneScope::DifferentProcess) { + { BrowsingContext* holder = nullptr; if (NS_SUCCEEDED(UNWRAP_OBJECT(BrowsingContext, &obj, holder))) { return holder->WriteStructuredClone(aCx, aWriter, this); @@ -996,12 +1006,15 @@ bool StructuredCloneHolder::CustomWriteHandler(JSContext* aCx, } // See if this is a WasmModule. - if (mStructuredCloneScope == StructuredCloneScope::SameProcess && - JS::IsWasmModuleObject(obj)) { - RefPtr module = JS::GetWasmModule(obj); - MOZ_ASSERT(module); + if (JS::IsWasmModuleObject(obj)) { + SameProcessScopeRequired(aSameProcessScopeRequired); + if (CloneScope() == StructuredCloneScope::SameProcess) { + RefPtr module = JS::GetWasmModule(obj); + MOZ_ASSERT(module); - return WriteWasmModule(aWriter, module, this); + return WriteWasmModule(aWriter, module, this); + } + return false; } { @@ -1051,7 +1064,7 @@ bool StructuredCloneHolder::CustomReadTransferHandler( } if (aTag == SCTAG_DOM_CANVAS && - mStructuredCloneScope == StructuredCloneScope::SameProcess) { + CloneScope() == StructuredCloneScope::SameProcess) { MOZ_ASSERT(aContent); OffscreenCanvasCloneData* data = static_cast(aContent); @@ -1070,7 +1083,7 @@ bool StructuredCloneHolder::CustomReadTransferHandler( } if (aTag == SCTAG_DOM_IMAGEBITMAP && - mStructuredCloneScope == StructuredCloneScope::SameProcess) { + CloneScope() == StructuredCloneScope::SameProcess) { MOZ_ASSERT(aContent); ImageBitmapCloneData* data = static_cast(aContent); RefPtr bitmap = @@ -1122,7 +1135,7 @@ bool StructuredCloneHolder::CustomWriteTransferHandler( return true; } - if (mStructuredCloneScope == StructuredCloneScope::SameProcess) { + if (CloneScope() == StructuredCloneScope::SameProcess) { OffscreenCanvas* canvas = nullptr; rv = UNWRAP_OBJECT(OffscreenCanvas, &obj, canvas); if (NS_SUCCEEDED(rv)) { @@ -1186,7 +1199,7 @@ void StructuredCloneHolder::CustomFreeTransferHandler( } if (aTag == SCTAG_DOM_CANVAS && - mStructuredCloneScope == StructuredCloneScope::SameProcess) { + CloneScope() == StructuredCloneScope::SameProcess) { MOZ_ASSERT(aContent); OffscreenCanvasCloneData* data = static_cast(aContent); @@ -1195,7 +1208,7 @@ void StructuredCloneHolder::CustomFreeTransferHandler( } if (aTag == SCTAG_DOM_IMAGEBITMAP && - mStructuredCloneScope == StructuredCloneScope::SameProcess) { + CloneScope() == StructuredCloneScope::SameProcess) { MOZ_ASSERT(aContent); ImageBitmapCloneData* data = static_cast(aContent); delete data; @@ -1204,7 +1217,8 @@ void StructuredCloneHolder::CustomFreeTransferHandler( } bool StructuredCloneHolder::CustomCanTransferHandler( - JSContext* aCx, JS::Handle aObj) { + JSContext* aCx, JS::Handle aObj, + bool* aSameProcessScopeRequired) { if (!mSupportsTransferring) { return false; } @@ -1217,19 +1231,23 @@ bool StructuredCloneHolder::CustomCanTransferHandler( if (NS_SUCCEEDED(rv)) { return true; } + } - if (mStructuredCloneScope == StructuredCloneScope::SameProcess) { - OffscreenCanvas* canvas = nullptr; - rv = UNWRAP_OBJECT(OffscreenCanvas, &obj, canvas); - if (NS_SUCCEEDED(rv)) { - return true; - } + { + OffscreenCanvas* canvas = nullptr; + nsresult rv = UNWRAP_OBJECT(OffscreenCanvas, &obj, canvas); + if (NS_SUCCEEDED(rv)) { + SameProcessScopeRequired(aSameProcessScopeRequired); + return CloneScope() == StructuredCloneScope::SameProcess; + } + } - ImageBitmap* bitmap = nullptr; - rv = UNWRAP_OBJECT(ImageBitmap, &obj, bitmap); - if (NS_SUCCEEDED(rv)) { - return true; - } + { + ImageBitmap* bitmap = nullptr; + nsresult rv = UNWRAP_OBJECT(ImageBitmap, &obj, bitmap); + if (NS_SUCCEEDED(rv)) { + SameProcessScopeRequired(aSameProcessScopeRequired); + return CloneScope() == StructuredCloneScope::SameProcess; } } @@ -1250,5 +1268,14 @@ bool StructuredCloneHolder::TakeTransferredPortsAsSequence( return true; } +void StructuredCloneHolder::SameProcessScopeRequired( + bool* aSameProcessScopeRequired) { + MOZ_ASSERT(aSameProcessScopeRequired); + if (mStructuredCloneScope == StructuredCloneScope::UnknownDestination) { + mStructuredCloneScope = StructuredCloneScope::SameProcess; + *aSameProcessScopeRequired = true; + } +} + } // namespace dom } // namespace mozilla diff --git a/dom/base/StructuredCloneHolder.h b/dom/base/StructuredCloneHolder.h index 01143f54c4ce4..9fbba64ad5789 100644 --- a/dom/base/StructuredCloneHolder.h +++ b/dom/base/StructuredCloneHolder.h @@ -57,7 +57,8 @@ class StructuredCloneHolderBase { virtual bool CustomWriteHandler(JSContext* aCx, JSStructuredCloneWriter* aWriter, - JS::Handle aObj) = 0; + JS::Handle aObj, + bool* aSameProcessScopeRequired) = 0; // This method has to be called when this object is not needed anymore. // It will free memory and the buffer. This has to be called because @@ -87,7 +88,8 @@ class StructuredCloneHolderBase { void* aContent, uint64_t aExtraData); virtual bool CustomCanTransferHandler(JSContext* aCx, - JS::Handle aObj); + JS::Handle aObj, + bool* aSameProcessScopeRequired); // These methods are what you should use to read/write data. @@ -198,7 +200,14 @@ class StructuredCloneHolder : public StructuredCloneHolderBase { return mInputStreamArray; } - StructuredCloneScope CloneScope() const { return mStructuredCloneScope; } + // This method returns the final scope. If the final scope is unknown, + // DifferentProcess is returned because it's the most restrictive one. + StructuredCloneScope CloneScope() const { + if (mStructuredCloneScope == StructuredCloneScope::UnknownDestination) { + return StructuredCloneScope::DifferentProcess; + } + return mStructuredCloneScope; + } // The global object is set internally just during the Read(). This method // can be used by read functions to retrieve it. @@ -235,7 +244,8 @@ class StructuredCloneHolder : public StructuredCloneHolderBase { virtual bool CustomWriteHandler(JSContext* aCx, JSStructuredCloneWriter* aWriter, - JS::Handle aObj) override; + JS::Handle aObj, + bool* aSameProcessScopeRequired) override; virtual bool CustomReadTransferHandler( JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag, @@ -254,8 +264,9 @@ class StructuredCloneHolder : public StructuredCloneHolderBase { void* aContent, uint64_t aExtraData) override; - virtual bool CustomCanTransferHandler(JSContext* aCx, - JS::Handle aObj) override; + virtual bool CustomCanTransferHandler( + JSContext* aCx, JS::Handle aObj, + bool* aSameProcessScopeRequired) override; // These 2 static methods are useful to read/write fully serializable objects. // They can be used by custom StructuredCloneHolderBase classes to @@ -288,6 +299,8 @@ class StructuredCloneHolder : public StructuredCloneHolderBase { uint32_t aAlgorithmVersion, JS::MutableHandle aValue, ErrorResult& aRv); + void SameProcessScopeRequired(bool* aSameProcessScopeRequired); + bool mSupportsCloning; bool mSupportsTransferring; diff --git a/dom/console/Console.cpp b/dom/console/Console.cpp index 1891d59f49b0f..913997eafde2f 100644 --- a/dom/console/Console.cpp +++ b/dom/console/Console.cpp @@ -308,7 +308,8 @@ class ConsoleRunnable : public StructuredCloneHolderBase { } bool CustomWriteHandler(JSContext* aCx, JSStructuredCloneWriter* aWriter, - JS::Handle aObj) override { + JS::Handle aObj, + bool* aSameProcessScopeRequired) override { RefPtr blob; if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) { if (NS_WARN_IF(!JS_WriteUint32Pair(aWriter, CONSOLE_TAG_BLOB, diff --git a/dom/indexedDB/IDBObjectStore.cpp b/dom/indexedDB/IDBObjectStore.cpp index 8e198dc7f0b1a..d93d99ec24905 100644 --- a/dom/indexedDB/IDBObjectStore.cpp +++ b/dom/indexedDB/IDBObjectStore.cpp @@ -193,7 +193,8 @@ RefPtr GenerateRequest(JSContext* aCx, bool StructuredCloneWriteCallback(JSContext* aCx, JSStructuredCloneWriter* aWriter, - JS::Handle aObj, void* aClosure) { + JS::Handle aObj, + bool* aSameProcessRequired, void* aClosure) { MOZ_ASSERT(aCx); MOZ_ASSERT(aWriter); MOZ_ASSERT(aClosure); @@ -352,6 +353,7 @@ bool StructuredCloneWriteCallback(JSContext* aCx, bool CopyingStructuredCloneWriteCallback(JSContext* aCx, JSStructuredCloneWriter* aWriter, JS::Handle aObj, + bool* aSameProcessRequired, void* aClosure) { MOZ_ASSERT(aCx); MOZ_ASSERT(aWriter); diff --git a/dom/promise/Promise.cpp b/dom/promise/Promise.cpp index 2c6b946085605..39e49105c6986 100644 --- a/dom/promise/Promise.cpp +++ b/dom/promise/Promise.cpp @@ -783,7 +783,8 @@ JSObject* PromiseWorkerProxy::CustomReadHandler( bool PromiseWorkerProxy::CustomWriteHandler(JSContext* aCx, JSStructuredCloneWriter* aWriter, - JS::Handle aObj) { + JS::Handle aObj, + bool* aSameProcessScopeRequired) { if (NS_WARN_IF(!mCallbacks)) { return false; } diff --git a/dom/promise/PromiseWorkerProxy.h b/dom/promise/PromiseWorkerProxy.h index a4b20ca39ad0c..0a451ae451a79 100644 --- a/dom/promise/PromiseWorkerProxy.h +++ b/dom/promise/PromiseWorkerProxy.h @@ -160,7 +160,8 @@ class PromiseWorkerProxy : public PromiseNativeHandler, uint32_t aTag, uint32_t aIndex) override; bool CustomWriteHandler(JSContext* aCx, JSStructuredCloneWriter* aWriter, - JS::Handle aObj) override; + JS::Handle aObj, + bool* aSameProcessScopeRequired) override; protected: virtual void ResolvedCallback(JSContext* aCx, diff --git a/js/public/StructuredClone.h b/js/public/StructuredClone.h index 763df9fcbfa77..f0011080e9401 100644 --- a/js/public/StructuredClone.h +++ b/js/public/StructuredClone.h @@ -168,7 +168,14 @@ enum class StructuredCloneScope : uint32_t { * JSStructuredCloneData without knowing the scope, then populate it with * data (at which point the scope *is* known.) */ - Unassigned + Unassigned, + + /** + * This scope is used when the deserialization context is unknown. When + * writing, DifferentProcess or SameProcess scope is chosen based on the + * nature of the object. + */ + UnknownDestination, }; enum TransferableOwnership { @@ -248,7 +255,9 @@ typedef JSObject* (*ReadStructuredCloneOp)(JSContext* cx, */ typedef bool (*WriteStructuredCloneOp)(JSContext* cx, JSStructuredCloneWriter* w, - JS::HandleObject obj, void* closure); + JS::HandleObject obj, + bool* sameProcessScopeRequired, + void* closure); /** * This is called when JS_WriteStructuredClone is given an invalid transferable. @@ -306,6 +315,7 @@ typedef void (*FreeTransferStructuredCloneOp)( */ typedef bool (*CanTransferStructuredCloneOp)(JSContext* cx, JS::Handle obj, + bool* sameProcessScopeRequired, void* closure); struct JSStructuredCloneCallbacks { @@ -433,7 +443,18 @@ class MOZ_NON_MEMMOVABLE JS_PUBLIC_API JSStructuredCloneData { return bufList_.Init(0, initialCapacity); } - JS::StructuredCloneScope scope() const { return scope_; } + JS::StructuredCloneScope scope() const { + if (scope_ == JS::StructuredCloneScope::UnknownDestination) { + return JS::StructuredCloneScope::DifferentProcess; + } + return scope_; + } + + void sameProcessScopeRequired() { + if (scope_ == JS::StructuredCloneScope::UnknownDestination) { + scope_ = JS::StructuredCloneScope::SameProcess; + } + } void initScope(JS::StructuredCloneScope newScope) { MOZ_ASSERT(Size() == 0, "initScope() of nonempty JSStructuredCloneData"); diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp index e3936e21f9f14..18cf7d07614d0 100644 --- a/js/src/vm/StructuredClone.cpp +++ b/js/src/vm/StructuredClone.cpp @@ -309,6 +309,7 @@ struct SCOutput { JSContext* context() const { return cx; } JS::StructuredCloneScope scope() const { return buf.scope(); } + void sameProcessScopeRequired() { buf.sameProcessScopeRequired(); } MOZ_MUST_USE bool write(uint64_t u); MOZ_MUST_USE bool writePair(uint32_t tag, uint32_t data); @@ -1101,10 +1102,15 @@ bool JSStructuredCloneWriter::parseTransferable() { } JSAutoRealm ar(cx, unwrappedObj); - if (!out.buf.callbacks_->canTransfer(cx, unwrappedObj, - out.buf.closure_)) { + bool sameProcessScopeRequired = false; + if (!out.buf.callbacks_->canTransfer( + cx, unwrappedObj, &sameProcessScopeRequired, out.buf.closure_)) { return false; } + + if (sameProcessScopeRequired) { + output().sameProcessScopeRequired(); + } } // No duplicates allowed @@ -1263,6 +1269,8 @@ bool JSStructuredCloneWriter::writeSharedArrayBuffer(HandleObject obj) { return false; } + output().sameProcessScopeRequired(); + // We must not transmit SAB pointers (including for WebAssembly.Memory) // cross-process. The cloneDataPolicy should have guarded against this; // since it did not then throw, with a very explicit message. @@ -1742,7 +1750,18 @@ bool JSStructuredCloneWriter::startWrite(HandleValue v) { } if (out.buf.callbacks_ && out.buf.callbacks_->write) { - return out.buf.callbacks_->write(context(), this, obj, out.buf.closure_); + bool sameProcessScopeRequired = false; + if (!out.buf.callbacks_->write(context(), this, obj, + &sameProcessScopeRequired, + out.buf.closure_)) { + return false; + } + + if (sameProcessScopeRequired) { + output().sameProcessScopeRequired(); + } + + return true; } // else fall through } diff --git a/js/xpconnect/src/ExportHelpers.cpp b/js/xpconnect/src/ExportHelpers.cpp index 094c9030539e9..a5f90997b9616 100644 --- a/js/xpconnect/src/ExportHelpers.cpp +++ b/js/xpconnect/src/ExportHelpers.cpp @@ -133,7 +133,8 @@ class MOZ_STACK_CLASS StackScopedCloneData : public StructuredCloneHolderBase { } bool CustomWriteHandler(JSContext* aCx, JSStructuredCloneWriter* aWriter, - JS::Handle aObj) override { + JS::Handle aObj, + bool* aSameProcessScopeRequired) override { { JS::Rooted obj(aCx, aObj); Blob* blob = nullptr;