зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1422335 - Using a sandbox on main-thread when deserializing data for IDB - part 2 - Upgrade value, r=asuth
This commit is contained in:
Родитель
f3cbbe9985
Коммит
29ae60f412
|
@ -3648,13 +3648,10 @@ UpgradeSchemaFrom18_0To19_0(mozIStorageConnection* aConnection)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
class NormalJSContext;
|
||||
|
||||
class UpgradeFileIdsFunction final
|
||||
: public mozIStorageFunction
|
||||
{
|
||||
RefPtr<FileManager> mFileManager;
|
||||
nsAutoPtr<NormalJSContext> mContext;
|
||||
|
||||
public:
|
||||
UpgradeFileIdsFunction()
|
||||
|
@ -8057,53 +8054,6 @@ private:
|
|||
DoDatabaseWork(DatabaseConnection* aConnection) override;
|
||||
};
|
||||
|
||||
class NormalJSContext
|
||||
{
|
||||
friend class nsAutoPtr<NormalJSContext>;
|
||||
|
||||
static const JSClass sGlobalClass;
|
||||
static const uint32_t kContextHeapSize = 768 * 1024;
|
||||
|
||||
JSContext* mContext;
|
||||
JSObject* mGlobal;
|
||||
|
||||
public:
|
||||
static NormalJSContext*
|
||||
Create();
|
||||
|
||||
JSContext*
|
||||
Context() const
|
||||
{
|
||||
return mContext;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
Global() const
|
||||
{
|
||||
return mGlobal;
|
||||
}
|
||||
|
||||
protected:
|
||||
NormalJSContext()
|
||||
: mContext(nullptr)
|
||||
, mGlobal(nullptr)
|
||||
{
|
||||
MOZ_COUNT_CTOR(NormalJSContext);
|
||||
}
|
||||
|
||||
~NormalJSContext()
|
||||
{
|
||||
MOZ_COUNT_DTOR(NormalJSContext);
|
||||
|
||||
if (mContext) {
|
||||
JS_DestroyContext(mContext);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Init();
|
||||
};
|
||||
|
||||
class CreateIndexOp::UpdateIndexDataValuesFunction final
|
||||
: public mozIStorageFunction
|
||||
{
|
||||
|
@ -19535,13 +19485,7 @@ UpgradeFileIdsFunction::Init(nsIFile* aFMDirectory,
|
|||
return rv;
|
||||
}
|
||||
|
||||
nsAutoPtr<NormalJSContext> context(NormalJSContext::Create());
|
||||
if (NS_WARN_IF(!context)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mFileManager.swap(fileManager);
|
||||
mContext = context;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -19554,7 +19498,6 @@ UpgradeFileIdsFunction::OnFunctionCall(mozIStorageValueArray* aArguments,
|
|||
MOZ_ASSERT(aArguments);
|
||||
MOZ_ASSERT(aResult);
|
||||
MOZ_ASSERT(mFileManager);
|
||||
MOZ_ASSERT(mContext);
|
||||
|
||||
AUTO_PROFILER_LABEL("UpgradeFileIdsFunction::OnFunctionCall", STORAGE);
|
||||
|
||||
|
@ -19576,30 +19519,10 @@ UpgradeFileIdsFunction::OnFunctionCall(mozIStorageValueArray* aArguments,
|
|||
mFileManager,
|
||||
&cloneInfo);
|
||||
|
||||
JSContext* cx = mContext->Context();
|
||||
JSAutoRequest ar(cx);
|
||||
JSAutoCompartment ac(cx, mContext->Global());
|
||||
|
||||
JS::Rooted<JS::Value> clone(cx);
|
||||
if (NS_WARN_IF(!IDBObjectStore::DeserializeUpgradeValue(cx, cloneInfo,
|
||||
&clone))) {
|
||||
return NS_ERROR_DOM_DATA_CLONE_ERR;
|
||||
}
|
||||
|
||||
nsAutoString fileIds;
|
||||
|
||||
for (uint32_t count = cloneInfo.mFiles.Length(), index = 0;
|
||||
index < count;
|
||||
index++) {
|
||||
StructuredCloneFile& file = cloneInfo.mFiles[index];
|
||||
MOZ_ASSERT(file.mFileInfo);
|
||||
|
||||
const int64_t id = file.mFileInfo->Id();
|
||||
|
||||
if (index) {
|
||||
fileIds.Append(' ');
|
||||
}
|
||||
fileIds.AppendInt(file.mType == StructuredCloneFile::eBlob ? id : -id);
|
||||
rv = IDBObjectStore::DeserializeUpgradeValueToFileIds(cloneInfo, fileIds);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return NS_ERROR_DOM_DATA_CLONE_ERR;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIVariant> result = new mozilla::storage::TextVariant(fileIds);
|
||||
|
@ -25005,74 +24928,6 @@ CreateIndexOp::DoDatabaseWork(DatabaseConnection* aConnection)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
static const JSClassOps sNormalJSContextGlobalClassOps = {
|
||||
/* addProperty */ nullptr,
|
||||
/* delProperty */ nullptr,
|
||||
/* enumerate */ nullptr,
|
||||
/* newEnumerate */ nullptr,
|
||||
/* resolve */ nullptr,
|
||||
/* mayResolve */ nullptr,
|
||||
/* finalize */ nullptr,
|
||||
/* call */ nullptr,
|
||||
/* hasInstance */ nullptr,
|
||||
/* construct */ nullptr,
|
||||
/* trace */ JS_GlobalObjectTraceHook
|
||||
};
|
||||
|
||||
const JSClass NormalJSContext::sGlobalClass = {
|
||||
"IndexedDBTransactionThreadGlobal",
|
||||
JSCLASS_GLOBAL_FLAGS,
|
||||
&sNormalJSContextGlobalClassOps
|
||||
};
|
||||
|
||||
bool
|
||||
NormalJSContext::Init()
|
||||
{
|
||||
MOZ_ASSERT(!IsOnBackgroundThread());
|
||||
|
||||
mContext = JS_NewContext(kContextHeapSize);
|
||||
if (NS_WARN_IF(!mContext)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Let everyone know that we might be able to call JS. This alerts the
|
||||
// profiler about certain possible deadlocks.
|
||||
NS_GetCurrentThread()->SetCanInvokeJS(true);
|
||||
|
||||
// Not setting this will cause JS_CHECK_RECURSION to report false positives.
|
||||
JS_SetNativeStackQuota(mContext, 128 * sizeof(size_t) * 1024);
|
||||
|
||||
if (NS_WARN_IF(!JS::InitSelfHostedCode(mContext))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
JSAutoRequest ar(mContext);
|
||||
|
||||
JS::CompartmentOptions options;
|
||||
mGlobal = JS_NewGlobalObject(mContext, &sGlobalClass, nullptr,
|
||||
JS::FireOnNewGlobalHook, options);
|
||||
if (NS_WARN_IF(!mGlobal)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
NormalJSContext*
|
||||
NormalJSContext::Create()
|
||||
{
|
||||
MOZ_ASSERT(!IsOnBackgroundThread());
|
||||
|
||||
nsAutoPtr<NormalJSContext> newContext(new NormalJSContext());
|
||||
|
||||
if (NS_WARN_IF(!newContext->Init())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return newContext.forget();
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(CreateIndexOp::UpdateIndexDataValuesFunction,
|
||||
mozIStorageFunction);
|
||||
|
||||
|
|
|
@ -872,6 +872,24 @@ public:
|
|||
JS::MutableHandle<JSObject*> aResult)
|
||||
{
|
||||
MOZ_ASSERT(aCx);
|
||||
|
||||
// If we have eBlob, we are in an IDB SQLite schema upgrade where we don't
|
||||
// care about a real 'MutableFile', but we just care of having a propert
|
||||
// |mType| flag.
|
||||
if (aFile.mType == StructuredCloneFile::eBlob) {
|
||||
aFile.mType = StructuredCloneFile::eMutableFile;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aFile.mType == StructuredCloneFile::eMutableFile);
|
||||
|
||||
if (!aFile.mMutableFile || !NS_IsMainThread()) {
|
||||
|
@ -1009,74 +1027,6 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
// We don't need to upgrade database on B2G. See the comment in ActorsParent.cpp,
|
||||
// UpgradeSchemaFrom18_0To19_0()
|
||||
class UpgradeDeserializationHelper
|
||||
{
|
||||
public:
|
||||
static bool
|
||||
CreateAndWrapMutableFile(JSContext* aCx,
|
||||
StructuredCloneFile& aFile,
|
||||
const MutableFileData& aData,
|
||||
JS::MutableHandle<JSObject*> aResult)
|
||||
{
|
||||
MOZ_ASSERT(aCx);
|
||||
MOZ_ASSERT(aFile.mType == StructuredCloneFile::eBlob);
|
||||
|
||||
aFile.mType = StructuredCloneFile::eMutableFile;
|
||||
|
||||
// Just make a dummy object. The file_ids upgrade function is only
|
||||
// interested in the |mType| flag.
|
||||
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(aCx);
|
||||
MOZ_ASSERT(aFile.mType == StructuredCloneFile::eBlob);
|
||||
MOZ_ASSERT(aData.tag == SCTAG_DOM_FILE ||
|
||||
aData.tag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE ||
|
||||
aData.tag == SCTAG_DOM_BLOB);
|
||||
|
||||
// Just make a dummy object. The file_ids upgrade function is only interested
|
||||
// in the |mType| flag.
|
||||
JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
|
||||
|
||||
if (NS_WARN_IF(!obj)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aResult.set(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
CreateAndWrapWasmModule(JSContext* aCx,
|
||||
StructuredCloneFile& aFile,
|
||||
const WasmModuleData& aData,
|
||||
JS::MutableHandle<JSObject*> aResult)
|
||||
{
|
||||
MOZ_ASSERT(aCx);
|
||||
MOZ_ASSERT(aFile.mType == StructuredCloneFile::eBlob);
|
||||
|
||||
MOZ_ASSERT(false, "This should never be possible!");
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <class Traits>
|
||||
JSObject*
|
||||
CommonStructuredCloneReadCallback(JSContext* aCx,
|
||||
|
@ -1569,6 +1519,130 @@ private:
|
|||
nsresult mStatus;
|
||||
};
|
||||
|
||||
class DeserializeUpgradeValueHelper final : public Runnable
|
||||
{
|
||||
public:
|
||||
explicit DeserializeUpgradeValueHelper(StructuredCloneReadInfo& aCloneReadInfo)
|
||||
: Runnable("DeserializeUpgradeValueHelper")
|
||||
, mMonitor("DeserializeUpgradeValueHelper::mMonitor")
|
||||
, mCloneReadInfo(aCloneReadInfo)
|
||||
, mStatus(NS_ERROR_FAILURE)
|
||||
{}
|
||||
|
||||
nsresult
|
||||
DispatchAndWait(nsAString& aFileIds)
|
||||
{
|
||||
// We don't need to go to the main-thread and use the sandbox.
|
||||
if (!mCloneReadInfo.mData.Size()) {
|
||||
PopulateFileIds(aFileIds);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
||||
if (NS_FAILED(mStatus)) {
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
PopulateFileIds(aFileIds);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
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 = DeserializeUpgradeValue(cx, &value);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
OperationCompleted(rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
OperationCompleted(NS_OK);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsresult
|
||||
DeserializeUpgradeValue(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
|
||||
PopulateFileIds(nsAString& aFileIds)
|
||||
{
|
||||
for (uint32_t count = mCloneReadInfo.mFiles.Length(), index = 0;
|
||||
index < count;
|
||||
index++) {
|
||||
StructuredCloneFile& file = mCloneReadInfo.mFiles[index];
|
||||
MOZ_ASSERT(file.mFileInfo);
|
||||
|
||||
const int64_t id = file.mFileInfo->Id();
|
||||
|
||||
if (index) {
|
||||
aFileIds.Append(' ');
|
||||
}
|
||||
aFileIds.AppendInt(file.mType == StructuredCloneFile::eBlob ? id : -id);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
OperationCompleted(nsresult aStatus)
|
||||
{
|
||||
mStatus = aStatus;
|
||||
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
lock.Notify();
|
||||
}
|
||||
|
||||
Monitor mMonitor;
|
||||
StructuredCloneReadInfo& mCloneReadInfo;
|
||||
nsresult mStatus;
|
||||
};
|
||||
|
||||
} // anonymous
|
||||
|
||||
// static
|
||||
|
@ -1590,39 +1664,15 @@ IDBObjectStore::DeserializeIndexValueToUpdateInfos(int64_t aIndexID,
|
|||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
IDBObjectStore::DeserializeUpgradeValue(JSContext* aCx,
|
||||
StructuredCloneReadInfo& aCloneReadInfo,
|
||||
JS::MutableHandle<JS::Value> aValue)
|
||||
nsresult
|
||||
IDBObjectStore::DeserializeUpgradeValueToFileIds(StructuredCloneReadInfo& aCloneReadInfo,
|
||||
nsAString& aFileIds)
|
||||
{
|
||||
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 JSStructuredCloneCallbacks callbacks = {
|
||||
CommonStructuredCloneReadCallback<UpgradeDeserializationHelper>,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr
|
||||
};
|
||||
|
||||
if (!JS_ReadStructuredClone(aCx, aCloneReadInfo.mData, JS_STRUCTURED_CLONE_VERSION,
|
||||
JS::StructuredCloneScope::SameProcessSameThread,
|
||||
aValue, &callbacks, &aCloneReadInfo)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
RefPtr<DeserializeUpgradeValueHelper> helper =
|
||||
new DeserializeUpgradeValueHelper(aCloneReadInfo);
|
||||
return helper->DispatchAndWait(aFileIds);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
|
|
@ -105,10 +105,9 @@ public:
|
|||
StructuredCloneReadInfo& aCloneReadInfo,
|
||||
JS::MutableHandle<JS::Value> aValue);
|
||||
|
||||
static bool
|
||||
DeserializeUpgradeValue(JSContext* aCx,
|
||||
StructuredCloneReadInfo& aCloneReadInfo,
|
||||
JS::MutableHandle<JS::Value> aValue);
|
||||
static nsresult
|
||||
DeserializeUpgradeValueToFileIds(StructuredCloneReadInfo& aCloneReadInfo,
|
||||
nsAString& aFileIds);
|
||||
|
||||
static const JSClass*
|
||||
DummyPropClass()
|
||||
|
|
Загрузка…
Ссылка в новой задаче