Bug 1422335 - Using a sandbox on main-thread when deserializing data for IDB - part 1 - Deserialize on main-thread using a sandbox, r=asuth

This commit is contained in:
Andrea Marchesini 2018-01-18 13:19:06 +01:00
Родитель c05fed43cf
Коммит f3cbbe9985
5 изменённых файлов: 285 добавлений и 281 удалений

Просмотреть файл

@ -8028,14 +8028,8 @@ class CreateIndexOp final
{
friend class VersionChangeTransaction;
class ThreadLocalJSContext;
class UpdateIndexDataValuesFunction;
static const unsigned int kBadThreadLocalIndex =
static_cast<unsigned int>(-1);
static unsigned int sThreadLocalIndex;
const IndexMetadata mMetadata;
Maybe<UniqueIndexTable> mMaybeUniqueIndexTable;
RefPtr<FileManager> mFileManager;
@ -8110,47 +8104,21 @@ protected:
Init();
};
class CreateIndexOp::ThreadLocalJSContext final
: public NormalJSContext
{
friend class CreateIndexOp;
friend class nsAutoPtr<ThreadLocalJSContext>;
public:
static ThreadLocalJSContext*
GetOrCreate();
private:
ThreadLocalJSContext()
{
MOZ_COUNT_CTOR(CreateIndexOp::ThreadLocalJSContext);
}
~ThreadLocalJSContext()
{
MOZ_COUNT_DTOR(CreateIndexOp::ThreadLocalJSContext);
}
};
class CreateIndexOp::UpdateIndexDataValuesFunction final
: public mozIStorageFunction
{
RefPtr<CreateIndexOp> mOp;
RefPtr<DatabaseConnection> mConnection;
JSContext* mCx;
public:
UpdateIndexDataValuesFunction(CreateIndexOp* aOp,
DatabaseConnection* aConnection,
JSContext* aCx)
DatabaseConnection* aConnection)
: mOp(aOp)
, mConnection(aConnection)
, mCx(aCx)
{
MOZ_ASSERT(aOp);
MOZ_ASSERT(aConnection);
aConnection->AssertIsOnConnectionThread();
MOZ_ASSERT(aCx);
}
NS_DECL_ISUPPORTS
@ -10154,24 +10122,6 @@ SerializeStructuredCloneFiles(
return NS_OK;
}
already_AddRefed<nsIFile>
GetFileForFileInfo(FileInfo* aFileInfo)
{
FileManager* fileManager = aFileInfo->Manager();
nsCOMPtr<nsIFile> directory = fileManager->GetDirectory();
if (NS_WARN_IF(!directory)) {
return nullptr;
}
nsCOMPtr<nsIFile> file = fileManager->GetFileForId(directory,
aFileInfo->Id());
if (NS_WARN_IF(!file)) {
return nullptr;
}
return file.forget();
}
/*******************************************************************************
* Globals
******************************************************************************/
@ -19880,7 +19830,7 @@ DatabaseOperationBase::GetStructuredCloneReadInfoFromExternalBlob(
MOZ_ASSERT(file.mFileInfo);
MOZ_ASSERT(file.mType == StructuredCloneFile::eStructuredClone);
nsCOMPtr<nsIFile> nativeFile = GetFileForFileInfo(file.mFileInfo);
nsCOMPtr<nsIFile> nativeFile = FileInfo::GetFileForFileInfo(file.mFileInfo);
if (NS_WARN_IF(!nativeFile)) {
return NS_ERROR_FAILURE;
}
@ -24243,7 +24193,7 @@ CreateFileOp::CreateFileOp(Database* aDatabase,
nsresult
CreateFileOp::CreateMutableFile(MutableFile** aMutableFile)
{
nsCOMPtr<nsIFile> file = GetFileForFileInfo(mFileInfo);
nsCOMPtr<nsIFile> file = FileInfo::GetFileForFileInfo(mFileInfo);
if (NS_WARN_IF(!file)) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
@ -24830,8 +24780,6 @@ CreateIndexOp::CreateIndexOp(VersionChangeTransaction* aTransaction,
MOZ_ASSERT(!mDatabaseId.IsEmpty());
}
unsigned int CreateIndexOp::sThreadLocalIndex = kBadThreadLocalIndex;
nsresult
CreateIndexOp::InsertDataFromObjectStore(DatabaseConnection* aConnection)
{
@ -24846,18 +24794,8 @@ CreateIndexOp::InsertDataFromObjectStore(DatabaseConnection* aConnection)
aConnection->GetStorageConnection();
MOZ_ASSERT(storageConnection);
ThreadLocalJSContext* context = ThreadLocalJSContext::GetOrCreate();
if (NS_WARN_IF(!context)) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
JSContext* cx = context->Context();
JSAutoRequest ar(cx);
JSAutoCompartment ac(cx, context->Global());
RefPtr<UpdateIndexDataValuesFunction> updateFunction =
new UpdateIndexDataValuesFunction(this, aConnection, cx);
new UpdateIndexDataValuesFunction(this, aConnection);
NS_NAMED_LITERAL_CSTRING(updateFunctionName, "update_index_data_values");
@ -24923,25 +24861,6 @@ CreateIndexOp::Init(TransactionBase* aTransaction)
AssertIsOnBackgroundThread();
MOZ_ASSERT(aTransaction);
struct MOZ_STACK_CLASS Helper final
{
static void
Destroy(void* aThreadLocal)
{
delete static_cast<ThreadLocalJSContext*>(aThreadLocal);
}
};
if (sThreadLocalIndex == kBadThreadLocalIndex) {
if (NS_WARN_IF(PR_SUCCESS !=
PR_NewThreadPrivateIndex(&sThreadLocalIndex,
&Helper::Destroy))) {
return false;
}
}
MOZ_ASSERT(sThreadLocalIndex != kBadThreadLocalIndex);
nsresult rv =
GetUniqueIndexTableForObjectStore(aTransaction,
mObjectStoreId,
@ -25154,34 +25073,6 @@ NormalJSContext::Create()
return newContext.forget();
}
// static
auto
CreateIndexOp::
ThreadLocalJSContext::GetOrCreate() -> ThreadLocalJSContext*
{
MOZ_ASSERT(!IsOnBackgroundThread());
MOZ_ASSERT(CreateIndexOp::kBadThreadLocalIndex !=
CreateIndexOp::sThreadLocalIndex);
auto* context = static_cast<ThreadLocalJSContext*>(
PR_GetThreadPrivate(CreateIndexOp::sThreadLocalIndex));
if (context) {
return context;
}
nsAutoPtr<ThreadLocalJSContext> newContext(new ThreadLocalJSContext());
if (NS_WARN_IF(!newContext->Init())) {
return nullptr;
}
DebugOnly<PRStatus> status =
PR_SetThreadPrivate(CreateIndexOp::sThreadLocalIndex, newContext);
MOZ_ASSERT(status == PR_SUCCESS);
return newContext.forget();
}
NS_IMPL_ISUPPORTS(CreateIndexOp::UpdateIndexDataValuesFunction,
mozIStorageFunction);
@ -25195,7 +25086,6 @@ UpdateIndexDataValuesFunction::OnFunctionCall(mozIStorageValueArray* aValues,
MOZ_ASSERT(mConnection);
mConnection->AssertIsOnConnectionThread();
MOZ_ASSERT(mOp);
MOZ_ASSERT(mCx);
AUTO_PROFILER_LABEL(
"CreateIndexOp::UpdateIndexDataValuesFunction::OnFunctionCall", STORAGE);
@ -25235,25 +25125,18 @@ UpdateIndexDataValuesFunction::OnFunctionCall(mozIStorageValueArray* aValues,
return rv;
}
JS::Rooted<JS::Value> clone(mCx);
if (NS_WARN_IF(!IDBObjectStore::DeserializeIndexValue(mCx,
cloneInfo,
&clone))) {
return NS_ERROR_DOM_DATA_CLONE_ERR;
}
const IndexMetadata& metadata = mOp->mMetadata;
const int64_t& objectStoreId = mOp->mObjectStoreId;
AutoTArray<IndexUpdateInfo, 32> updateInfos;
rv = IDBObjectStore::AppendIndexUpdateInfo(metadata.id(),
metadata.keyPath(),
metadata.unique(),
metadata.multiEntry(),
metadata.locale(),
mCx,
clone,
updateInfos);
rv = IDBObjectStore::DeserializeIndexValueToUpdateInfos(
metadata.id(),
metadata.keyPath(),
metadata.unique(),
metadata.multiEntry(),
metadata.locale(),
cloneInfo,
updateInfos);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}

Просмотреть файл

@ -256,6 +256,24 @@ CleanupFileRunnable::Run()
return NS_OK;
}
/* static */ already_AddRefed<nsIFile>
FileInfo::GetFileForFileInfo(FileInfo* aFileInfo)
{
FileManager* fileManager = aFileInfo->Manager();
nsCOMPtr<nsIFile> directory = fileManager->GetDirectory();
if (NS_WARN_IF(!directory)) {
return nullptr;
}
nsCOMPtr<nsIFile> file = fileManager->GetFileForId(directory,
aFileInfo->Id());
if (NS_WARN_IF(!file)) {
return nullptr;
}
return file.forget();
}
} // namespace indexedDB
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -69,6 +69,9 @@ public:
virtual int64_t
Id() const = 0;
static already_AddRefed<nsIFile>
GetFileForFileInfo(FileInfo* aFileInfo);
protected:
virtual ~FileInfo();

Просмотреть файл

@ -23,14 +23,18 @@
#include "js/Date.h"
#include "js/StructuredClone.h"
#include "KeyPath.h"
#include "NullPrincipal.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/EndianUtils.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/JSObjectHolder.h"
#include "mozilla/Move.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/DOMStringList.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/FileBlobImpl.h"
#include "mozilla/dom/IDBMutableFileBinding.h"
#include "mozilla/dom/BlobBinding.h"
#include "mozilla/dom/IDBObjectStoreBinding.h"
@ -41,6 +45,7 @@
#include "mozilla/dom/indexedDB/PBackgroundIDBSharedTypes.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/ipc/PBackgroundSharedTypes.h"
#include "mozilla/SystemGroup.h"
#include "nsCOMPtr.h"
#include "nsQueryObject.h"
#include "nsStreamUtils.h"
@ -900,7 +905,26 @@ public:
aData.tag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE ||
aData.tag == SCTAG_DOM_BLOB);
MOZ_ASSERT(aFile.mType == StructuredCloneFile::eBlob);
MOZ_ASSERT(aFile.mBlob);
RefPtr<Blob> blob = aFile.mBlob;
/* If we are creating an index, we do not have an mBlob but do have an
* mInfo. Unlike other index or upgrade cases, we do need a real-looking
* Blob/File instance because the index's key path can reference their
* properties. Rather than create a fake-looking object, create a real
* Blob. */
if (!blob) {
MOZ_ASSERT(aFile.mFileInfo);
nsCOMPtr<nsIFile> file = FileInfo::GetFileForFileInfo(aFile.mFileInfo);
if (!file) {
return false;
}
RefPtr<FileBlobImpl> impl = new FileBlobImpl(file);
impl->SetFileId(aFile.mFileInfo->Id());
blob = File::Create(nullptr, impl);
}
// It can happen that this IDB is chrome code, so there is no parent, but
// still we want to set a correct parent for the new File object.
@ -924,22 +948,22 @@ public:
MOZ_ASSERT(parent);
if (aData.tag == SCTAG_DOM_BLOB) {
aFile.mBlob->Impl()->SetLazyData(
blob->Impl()->SetLazyData(
VoidString(), aData.type, aData.size, INT64_MAX);
MOZ_ASSERT(!aFile.mBlob->IsFile());
MOZ_ASSERT(!blob->IsFile());
// ActorsParent sends here a kind of half blob and half file wrapped into
// a DOM File object. DOM File and DOM Blob are a WebIDL wrapper around a
// BlobImpl object. SetLazyData() has just changed the BlobImpl to be a
// Blob (see the previous assert), but 'aFile.mBlob' still has the WebIDL
// DOM File wrapping.
// Blob (see the previous assert), but 'blob' still has the WebIDL DOM
// File wrapping.
// Before exposing it to content, we must recreate a DOM Blob object.
RefPtr<Blob> blob =
Blob::Create(aFile.mBlob->GetParentObject(), aFile.mBlob->Impl());
MOZ_ASSERT(blob);
RefPtr<Blob> exposedBlob =
Blob::Create(blob->GetParentObject(), blob->Impl());
MOZ_ASSERT(exposedBlob);
JS::Rooted<JS::Value> wrappedBlob(aCx);
if (!ToJSValue(aCx, blob, &wrappedBlob)) {
if (!ToJSValue(aCx, exposedBlob, &wrappedBlob)) {
return false;
}
@ -947,12 +971,12 @@ public:
return true;
}
aFile.mBlob->Impl()->SetLazyData(
blob->Impl()->SetLazyData(
aData.name, aData.type, aData.size,
aData.lastModifiedDate * PR_USEC_PER_MSEC);
MOZ_ASSERT(aFile.mBlob->IsFile());
RefPtr<File> file = aFile.mBlob->ToFile();
MOZ_ASSERT(blob->IsFile());
RefPtr<File> file = blob->ToFile();
MOZ_ASSERT(file);
JS::Rooted<JS::Value> wrappedFile(aCx);
@ -985,114 +1009,6 @@ public:
}
};
class IndexDeserializationHelper
{
public:
static bool
CreateAndWrapMutableFile(JSContext* aCx,
StructuredCloneFile& aFile,
const MutableFileData& aData,
JS::MutableHandle<JSObject*> aResult)
{
// MutableFile can't be used in index creation, so just make a dummy object.
JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
if (NS_WARN_IF(!obj)) {
return false;
}
aResult.set(obj);
return true;
}
static bool
CreateAndWrapBlobOrFile(JSContext* aCx,
IDBDatabase* aDatabase,
StructuredCloneFile& aFile,
const BlobOrFileData& aData,
JS::MutableHandle<JSObject*> aResult)
{
MOZ_ASSERT(aData.tag == SCTAG_DOM_FILE ||
aData.tag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE ||
aData.tag == SCTAG_DOM_BLOB);
// The following properties are available for use in index creation
// Blob.size
// Blob.type
// File.name
// File.lastModifiedDate
JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
if (NS_WARN_IF(!obj)) {
return false;
}
// Technically these props go on the proto, but this detail won't change
// the results of index creation.
JS::Rooted<JSString*> type(aCx,
JS_NewUCStringCopyN(aCx, aData.type.get(), aData.type.Length()));
if (NS_WARN_IF(!type)) {
return false;
}
if (NS_WARN_IF(!JS_DefineProperty(aCx,
obj,
"size",
double(aData.size),
0))) {
return false;
}
if (NS_WARN_IF(!JS_DefineProperty(aCx, obj, "type", type, 0))) {
return false;
}
if (aData.tag == SCTAG_DOM_BLOB) {
aResult.set(obj);
return true;
}
JS::Rooted<JSString*> name(aCx,
JS_NewUCStringCopyN(aCx, aData.name.get(), aData.name.Length()));
if (NS_WARN_IF(!name)) {
return false;
}
JS::ClippedTime time = JS::TimeClip(aData.lastModifiedDate);
JS::Rooted<JSObject*> date(aCx, JS::NewDateObject(aCx, time));
if (NS_WARN_IF(!date)) {
return false;
}
if (NS_WARN_IF(!JS_DefineProperty(aCx, obj, "name", name, 0))) {
return false;
}
if (NS_WARN_IF(!JS_DefineProperty(aCx, obj, "lastModifiedDate", date, 0))) {
return false;
}
aResult.set(obj);
return true;
}
static bool
CreateAndWrapWasmModule(JSContext* aCx,
StructuredCloneFile& aFile,
const WasmModuleData& aData,
JS::MutableHandle<JSObject*> aResult)
{
// Wasm module can't be used in index creation, so just make a dummy object.
JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
if (NS_WARN_IF(!obj)) {
return false;
}
aResult.set(obj);
return true;
}
};
// We don't need to upgrade database on B2G. See the comment in ActorsParent.cpp,
// UpgradeSchemaFrom18_0To19_0()
class UpgradeDeserializationHelper
@ -1460,37 +1376,217 @@ IDBObjectStore::DeserializeValue(JSContext* aCx,
return true;
}
namespace {
// This class helps to create only 1 sandbox.
class SandboxHolder final
{
public:
NS_INLINE_DECL_REFCOUNTING(SandboxHolder)
static JSObject*
GetSandbox(JSContext* aCx)
{
SandboxHolder* holder = GetOrCreate();
return holder->GetSandboxInternal(aCx);
}
private:
~SandboxHolder() = default;
static SandboxHolder*
GetOrCreate()
{
MOZ_ASSERT(XRE_IsParentProcess());
MOZ_ASSERT(NS_IsMainThread());
static StaticRefPtr<SandboxHolder> sHolder;
if (!sHolder) {
sHolder = new SandboxHolder();
ClearOnShutdown(&sHolder);
}
return sHolder;
}
JSObject*
GetSandboxInternal(JSContext* aCx)
{
if (!mSandbox) {
nsIXPConnect* xpc = nsContentUtils::XPConnect();
MOZ_ASSERT(xpc, "This should never be null!");
// Let's use a null principal.
nsCOMPtr<nsIPrincipal> principal = NullPrincipal::Create();
JS::Rooted<JSObject*> sandbox(aCx);
nsresult rv = xpc->CreateSandbox(aCx, principal, sandbox.address());
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
mSandbox = new JSObjectHolder(aCx, sandbox);
}
return mSandbox->GetJSObject();
}
RefPtr<JSObjectHolder> mSandbox;
};
class DeserializeIndexValueHelper final : public Runnable
{
public:
DeserializeIndexValueHelper(int64_t aIndexID,
const KeyPath& aKeyPath,
bool aUnique,
bool aMultiEntry,
const nsCString& aLocale,
StructuredCloneReadInfo& aCloneReadInfo,
nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
: Runnable("DeserializeIndexValueHelper")
, mMonitor("DeserializeIndexValueHelper::mMonitor")
, mIndexID(aIndexID)
, mKeyPath(aKeyPath)
, mUnique(aUnique)
, mMultiEntry(aMultiEntry)
, mLocale(aLocale)
, mCloneReadInfo(aCloneReadInfo)
, mUpdateInfoArray(aUpdateInfoArray)
, mStatus(NS_ERROR_FAILURE)
{}
nsresult
DispatchAndWait()
{
// We don't need to go to the main-thread and use the sandbox. Let's create
// the updateInfo data here.
if (!mCloneReadInfo.mData.Size()) {
AutoJSAPI jsapi;
jsapi.Init();
JS::Rooted<JS::Value> value(jsapi.cx());
value.setUndefined();
return IDBObjectStore::AppendIndexUpdateInfo(mIndexID, mKeyPath, mUnique,
mMultiEntry, mLocale,
jsapi.cx(), value,
mUpdateInfoArray);
}
// The operation will continue on the main-thread.
MOZ_ASSERT(!(mCloneReadInfo.mData.Size() % sizeof(uint64_t)));
MonitorAutoLock lock(mMonitor);
RefPtr<Runnable> self = this;
nsresult rv = SystemGroup::Dispatch(TaskCategory::Other, self.forget());
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
lock.Wait();
return mStatus;
}
NS_IMETHOD
Run() override
{
MOZ_ASSERT(NS_IsMainThread());
AutoJSAPI jsapi;
jsapi.Init();
JSContext* cx = jsapi.cx();
JS::Rooted<JSObject*> global(cx, SandboxHolder::GetSandbox(cx));
if (NS_WARN_IF(!global)) {
OperationCompleted(NS_ERROR_FAILURE);
return NS_OK;
}
JSAutoCompartment ac(cx, global);
JS::Rooted<JS::Value> value(cx);
nsresult rv = DeserializeIndexValue(cx, &value);
if (NS_WARN_IF(NS_FAILED(rv))) {
OperationCompleted(rv);
return NS_OK;
}
rv = IDBObjectStore::AppendIndexUpdateInfo(mIndexID, mKeyPath, mUnique,
mMultiEntry, mLocale, cx,
value, mUpdateInfoArray);
if (NS_WARN_IF(NS_FAILED(rv))) {
OperationCompleted(rv);
return NS_OK;
}
OperationCompleted(NS_OK);
return NS_OK;
}
private:
nsresult
DeserializeIndexValue(JSContext* aCx, JS::MutableHandle<JS::Value> aValue)
{
static const JSStructuredCloneCallbacks callbacks = {
CommonStructuredCloneReadCallback<ValueDeserializationHelper>,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr
};
if (!JS_ReadStructuredClone(aCx, mCloneReadInfo.mData,
JS_STRUCTURED_CLONE_VERSION,
JS::StructuredCloneScope::SameProcessSameThread,
aValue, &callbacks, &mCloneReadInfo)) {
return NS_ERROR_DOM_DATA_CLONE_ERR;
}
return NS_OK;
}
void
OperationCompleted(nsresult aStatus)
{
mStatus = aStatus;
MonitorAutoLock lock(mMonitor);
lock.Notify();
}
Monitor mMonitor;
int64_t mIndexID;
const KeyPath& mKeyPath;
bool mUnique;
bool mMultiEntry;
const nsCString mLocale;
StructuredCloneReadInfo& mCloneReadInfo;
nsTArray<IndexUpdateInfo>& mUpdateInfoArray;
nsresult mStatus;
};
} // anonymous
// static
bool
IDBObjectStore::DeserializeIndexValue(JSContext* aCx,
StructuredCloneReadInfo& aCloneReadInfo,
JS::MutableHandle<JS::Value> aValue)
nsresult
IDBObjectStore::DeserializeIndexValueToUpdateInfos(int64_t aIndexID,
const KeyPath& aKeyPath,
bool aUnique,
bool aMultiEntry,
const nsCString& aLocale,
StructuredCloneReadInfo& aCloneReadInfo,
nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(aCx);
if (!aCloneReadInfo.mData.Size()) {
aValue.setUndefined();
return true;
}
MOZ_ASSERT(!(aCloneReadInfo.mData.Size() % sizeof(uint64_t)));
JSAutoRequest ar(aCx);
static const JSStructuredCloneCallbacks callbacks = {
CommonStructuredCloneReadCallback<IndexDeserializationHelper>,
nullptr,
nullptr
};
if (!JS_ReadStructuredClone(aCx, aCloneReadInfo.mData, JS_STRUCTURED_CLONE_VERSION,
JS::StructuredCloneScope::SameProcessSameThread,
aValue, &callbacks, &aCloneReadInfo)) {
return false;
}
return true;
RefPtr<DeserializeIndexValueHelper> helper =
new DeserializeIndexValueHelper(aIndexID, aKeyPath, aUnique, aMultiEntry,
aLocale, aCloneReadInfo, aUpdateInfoArray);
return helper->DispatchAndWait();
}
// static

Просмотреть файл

@ -88,6 +88,15 @@ public:
JS::Handle<JS::Value> aObject,
nsTArray<IndexUpdateInfo>& aUpdateInfoArray);
static nsresult
DeserializeIndexValueToUpdateInfos(int64_t aIndexID,
const KeyPath& aKeyPath,
bool aUnique,
bool aMultiEntry,
const nsCString& aLocale,
StructuredCloneReadInfo& aCloneInfo,
nsTArray<IndexUpdateInfo>& aUpdateInfoArray);
static void
ClearCloneReadInfo(StructuredCloneReadInfo& aReadInfo);
@ -96,11 +105,6 @@ public:
StructuredCloneReadInfo& aCloneReadInfo,
JS::MutableHandle<JS::Value> aValue);
static bool
DeserializeIndexValue(JSContext* aCx,
StructuredCloneReadInfo& aCloneReadInfo,
JS::MutableHandle<JS::Value> aValue);
static bool
DeserializeUpgradeValue(JSContext* aCx,
StructuredCloneReadInfo& aCloneReadInfo,