@@ -229,6 +229,69 @@ struct BufferIterator {
229229 typename BufferList::IterImpl mIter ;
230230};
231231
232+ SharedArrayRawBufferRefs&
233+ SharedArrayRawBufferRefs::operator =(SharedArrayRawBufferRefs&& other)
234+ {
235+ takeOwnership (Move (other));
236+ return *this ;
237+ }
238+
239+ SharedArrayRawBufferRefs::~SharedArrayRawBufferRefs ()
240+ {
241+ releaseAll ();
242+ }
243+
244+ bool
245+ SharedArrayRawBufferRefs::acquire (JSContext* cx, SharedArrayRawBuffer* rawbuf)
246+ {
247+ if (!refs_.append (rawbuf)) {
248+ ReportOutOfMemory (cx);
249+ return false ;
250+ }
251+
252+ if (!rawbuf->addReference ()) {
253+ refs_.popBack ();
254+ JS_ReportErrorNumberASCII (cx, GetErrorMessage, nullptr , JSMSG_SC_SAB_REFCNT_OFLO );
255+ return false ;
256+ }
257+
258+ return true ;
259+ }
260+
261+ bool
262+ SharedArrayRawBufferRefs::acquireAll (JSContext* cx, const SharedArrayRawBufferRefs& that)
263+ {
264+ if (!refs_.reserve (refs_.length () + that.refs_ .length ())) {
265+ ReportOutOfMemory (cx);
266+ return false ;
267+ }
268+
269+ for (auto ref : that.refs_ ) {
270+ if (!ref->addReference ()) {
271+ JS_ReportErrorNumberASCII (cx, GetErrorMessage, nullptr , JSMSG_SC_SAB_REFCNT_OFLO );
272+ return false ;
273+ }
274+ MOZ_ALWAYS_TRUE (refs_.append (ref));
275+ }
276+
277+ return true ;
278+ }
279+
280+ void
281+ SharedArrayRawBufferRefs::takeOwnership (SharedArrayRawBufferRefs&& other)
282+ {
283+ MOZ_ASSERT (refs_.empty ());
284+ refs_ = Move (other.refs_ );
285+ }
286+
287+ void
288+ SharedArrayRawBufferRefs::releaseAll ()
289+ {
290+ for (auto ref : refs_)
291+ ref->dropReference ();
292+ refs_.clear ();
293+ }
294+
232295struct SCOutput {
233296 public:
234297 using Iter = BufferIterator<uint64_t , TempAllocPolicy>;
@@ -408,6 +471,9 @@ struct JSStructuredCloneWriter {
408471 bool extractBuffer (JSStructuredCloneData* data) {
409472 bool success = out.extractBuffer (data);
410473 if (success) {
474+ // Move the SharedArrayRawBuf references here, SCOutput::extractBuffer
475+ // moves the serialized data.
476+ data->refsHeld_ .takeOwnership (Move (refsHeld));
411477 data->setOptionalCallbacks (callbacks, closure,
412478 OwnTransferablePolicy::OwnsTransferablesIfAny);
413479 }
@@ -486,6 +552,9 @@ struct JSStructuredCloneWriter {
486552
487553 const JS ::CloneDataPolicy cloneDataPolicy;
488554
555+ // SharedArrayRawBuffers whose reference counts we have incremented.
556+ SharedArrayRawBufferRefs refsHeld;
557+
489558 friend bool JS_WriteString (JSStructuredCloneWriter* w, HandleString str);
490559 friend bool JS_WriteTypedArray (JSStructuredCloneWriter* w, HandleValue v);
491560 friend bool JS_ObjectNotWritten (JSStructuredCloneWriter* w, HandleObject obj);
@@ -1161,12 +1230,8 @@ JSStructuredCloneWriter::writeSharedArrayBuffer(HandleObject obj)
11611230 Rooted<SharedArrayBufferObject*> sharedArrayBuffer (context (), &CheckedUnwrap (obj)->as <SharedArrayBufferObject>());
11621231 SharedArrayRawBuffer* rawbuf = sharedArrayBuffer->rawBufferObject ();
11631232
1164- // Avoids a race condition where the parent thread frees the buffer
1165- // before the child has accepted the transferable.
1166- if (!rawbuf->addReference ()) {
1167- JS_ReportErrorNumberASCII (context (), GetErrorMessage, nullptr , JSMSG_SC_SAB_REFCNT_OFLO );
1233+ if (!refsHeld.acquire (context (), rawbuf))
11681234 return false ;
1169- }
11701235
11711236 intptr_t p = reinterpret_cast <intptr_t >(rawbuf);
11721237 return out.writePair (SCTAG_SHARED_ARRAY_BUFFER_OBJECT , static_cast <uint32_t >(sizeof (p))) &&
@@ -1894,18 +1959,24 @@ JSStructuredCloneReader::readSharedArrayBuffer(uint32_t nbytes, MutableHandleVal
18941959 // in any case. Just fail at the receiving end if we can't handle it.
18951960
18961961 if (!context ()->compartment ()->creationOptions ().getSharedMemoryAndAtomicsEnabled ()) {
1897- // The sending side performed a reference increment before sending.
1898- // Account for that here before leaving.
1899- if (rawbuf)
1900- rawbuf->dropReference ();
1901-
19021962 JS_ReportErrorNumberASCII (context (), GetErrorMessage, nullptr , JSMSG_SC_SAB_DISABLED );
19031963 return false ;
19041964 }
19051965
1906- // The constructor absorbs the reference count increment performed by the sender.
1966+ // The new object will have a new reference to the rawbuf.
1967+
1968+ if (!rawbuf->addReference ()) {
1969+ JS_ReportErrorNumberASCII (context (), GetErrorMessage, nullptr , JSMSG_SC_SAB_REFCNT_OFLO );
1970+ return false ;
1971+ }
1972+
19071973 JSObject* obj = SharedArrayBufferObject::New (context (), rawbuf);
19081974
1975+ if (!obj) {
1976+ rawbuf->dropReference ();
1977+ return false ;
1978+ }
1979+
19091980 vp.setObject (*obj);
19101981 return true ;
19111982}
@@ -2591,13 +2662,14 @@ JSAutoStructuredCloneBuffer::clear(const JSStructuredCloneCallbacks* optionalCal
25912662 if (data_.ownTransferables_ == OwnTransferablePolicy::OwnsTransferablesIfAny)
25922663 DiscardTransferables (data_, callbacks, closure);
25932664 data_.ownTransferables_ = OwnTransferablePolicy::NoTransferables;
2665+ data_.refsHeld_ .releaseAll ();
25942666 data_.Clear ();
25952667 version_ = 0 ;
25962668}
25972669
25982670bool
2599- JSAutoStructuredCloneBuffer::copy (const JSStructuredCloneData& srcData, uint32_t version ,
2600- const JSStructuredCloneCallbacks* callbacks,
2671+ JSAutoStructuredCloneBuffer::copy (JSContext* cx, const JSStructuredCloneData& srcData,
2672+ uint32_t version, const JSStructuredCloneCallbacks* callbacks,
26012673 void * closure)
26022674{
26032675 // transferable objects cannot be copied
@@ -2608,11 +2680,16 @@ JSAutoStructuredCloneBuffer::copy(const JSStructuredCloneData& srcData, uint32_t
26082680
26092681 auto iter = srcData.Iter ();
26102682 while (!iter.Done ()) {
2611- data_.WriteBytes (iter.Data (), iter.RemainingInSegment ());
2612- iter.Advance (srcData, iter.RemainingInSegment ());
2683+ if (!data_.WriteBytes (iter.Data (), iter.RemainingInSegment ()))
2684+ return false ;
2685+ iter.Advance (srcData, iter.RemainingInSegment ());
26132686 }
26142687
26152688 version_ = version;
2689+
2690+ if (!data_.refsHeld_ .acquireAll (cx, srcData.refsHeld_ ))
2691+ return false ;
2692+
26162693 data_.setOptionalCallbacks (callbacks, closure, OwnTransferablePolicy::NoTransferables);
26172694 return true ;
26182695}
0 commit comments