Bug 1264613 - Allow object-to-nonobject serialization. r=baku
authorPip <pipcet@gmail.com>
Tue, 19 Apr 2016 10:26:00 +0200
changeset 296820 0504bc4398f643b6b7c4a6f3cbf9e435b732b384
parent 296819 8723a2bd8ecf33230cdfc8259c5501cb60bae8a1
child 296821 c830ab6c217eec0ad735a6d71f249e1bb17b2c0a
push id76480
push usercbook@mozilla.com
push dateTue, 10 May 2016 10:44:42 +0000
treeherdermozilla-inbound@0504bc4398f6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1264613
milestone49.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 1264613 - Allow object-to-nonobject serialization. r=baku Fix the Structured Clone API to avoid assigning a numeric back-reference id to objects that are serialized as non-objects; in particular, this fixes incorrect serialization and crashes upon deserialization when a DedicatedWorkerGlobalScope is serialized twice in the same serialization packet.
dom/base/Console.cpp
js/public/StructuredClone.h
js/src/vm/StructuredClone.cpp
--- a/dom/base/Console.cpp
+++ b/dom/base/Console.cpp
@@ -541,16 +541,20 @@ protected:
                                          mClonedData.mBlobs.Length()))) {
         return false;
       }
 
       mClonedData.mBlobs.AppendElement(blob->Impl());
       return true;
     }
 
+    if (!JS_ObjectNotWritten(aWriter, aObj)) {
+      return false;
+    }
+
     JS::Rooted<JS::Value> value(aCx, JS::ObjectOrNullValue(aObj));
     JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, value));
     if (NS_WARN_IF(!jsString)) {
       return false;
     }
 
     if (NS_WARN_IF(!JS_WriteString(aWriter, jsString))) {
       return false;
--- a/js/public/StructuredClone.h
+++ b/js/public/StructuredClone.h
@@ -276,9 +276,12 @@ JS_PUBLIC_API(bool)
 JS_WriteBytes(JSStructuredCloneWriter* w, const void* p, size_t len);
 
 JS_PUBLIC_API(bool)
 JS_WriteString(JSStructuredCloneWriter* w, JS::HandleString str);
 
 JS_PUBLIC_API(bool)
 JS_WriteTypedArray(JSStructuredCloneWriter* w, JS::HandleValue v);
 
+JS_PUBLIC_API(bool)
+JS_ObjectNotWritten(JSStructuredCloneWriter* w, JS::HandleObject obj);
+
 #endif  /* js_StructuredClone_h */
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -351,16 +351,17 @@ struct JSStructuredCloneWriter {
     void* closure;
 
     // Set of transferable objects
     RootedValue transferable;
     Rooted<GCHashSet<JSObject*>> transferableObjects;
 
     friend bool JS_WriteString(JSStructuredCloneWriter* w, HandleString str);
     friend bool JS_WriteTypedArray(JSStructuredCloneWriter* w, HandleValue v);
+    friend bool JS_ObjectNotWritten(JSStructuredCloneWriter* w, HandleObject obj);
 };
 
 JS_FRIEND_API(uint64_t)
 js::GetSCOffset(JSStructuredCloneWriter* writer)
 {
     MOZ_ASSERT(writer);
     return writer->output().count() * sizeof(uint64_t);
 }
@@ -1758,17 +1759,17 @@ JSStructuredCloneReader::startRead(Mutab
                         : (JSObject*) NewBuiltinClassInstance<PlainObject>(context());
         if (!obj || !objs.append(ObjectValue(*obj)))
             return false;
         vp.setObject(*obj);
         break;
       }
 
       case SCTAG_BACK_REFERENCE_OBJECT: {
-        if (data >= allObjs.length()) {
+        if (data >= allObjs.length() || !allObjs[data].isObject()) {
             JS_ReportErrorNumber(context(), GetErrorMessage, nullptr,
                                  JSMSG_SC_BAD_SERIALIZED_DATA,
                                  "invalid back reference in input");
             return false;
         }
         vp.set(allObjs[data]);
         return true;
       }
@@ -2417,8 +2418,16 @@ JS_WriteString(JSStructuredCloneWriter* 
 JS_PUBLIC_API(bool)
 JS_WriteTypedArray(JSStructuredCloneWriter* w, HandleValue v)
 {
     MOZ_ASSERT(v.isObject());
     assertSameCompartment(w->context(), v);
     RootedObject obj(w->context(), &v.toObject());
     return w->writeTypedArray(obj);
 }
+
+JS_PUBLIC_API(bool)
+JS_ObjectNotWritten(JSStructuredCloneWriter* w, HandleObject obj)
+{
+    w->memory.remove(w->memory.lookup(obj));
+
+    return true;
+}