Bug 1467720 - Fix "dead object" error raised from ext-storage.js on browser.storage.local API calls.
When ExtensionStorageIDB.selectBackend is called from a child process, it calls the main process
and cache the result as a promise, to be reused for the other contexts for the same extension
that are running in the same process.
The cached promise should not be tied to a particular extension context's cloneScope, otherwise
accessing it will raise "can't access dead object" errors after that cloneScope has been
destroyed.
MozReview-Commit-ID: GJuul8sQmlF
--- a/toolkit/components/extensions/ExtensionStorageIDB.jsm
+++ b/toolkit/components/extensions/ExtensionStorageIDB.jsm
@@ -359,32 +359,38 @@ this.ExtensionStorageIDB = {
*/
selectBackend(context) {
const {extension} = context;
if (!this.selectedBackendPromises.has(extension)) {
let promise;
if (context.childManager) {
- // Ask the parent process if the new backend is enabled for the
- // running extension.
- promise = context.childManager.callParentAsyncFunction(
- "storage.local.IDBBackend.selectBackend", []
- ).then(result => {
+ // Create a promise object that is not tied to the current extension context, because
+ // we are caching it for the entire life of the extension in the current process (and
+ // the promise returned by context.childManager.callParentAsyncFunction would become
+ // a dead object when the context.cloneScope has been destroyed).
+ promise = (async () => {
+ // Ask the parent process if the new backend is enabled for the
+ // running extension.
+ let result = await context.childManager.callParentAsyncFunction(
+ "storage.local.IDBBackend.selectBackend", []
+ );
+
if (!result.backendEnabled) {
return {backendEnabled: false};
}
return {
...result,
// In the child process, we need to deserialize the storagePrincipal
// from the StructuredCloneHolder used to send it across the processes.
storagePrincipal: result.storagePrincipal.deserialize(this),
};
- });
+ })();
} else {
// If migrating to the IDB backend is not enabled by the preference, then we
// don't need to migrate any data and the new backend is not enabled.
if (!this.isBackendEnabled) {
return Promise.resolve({backendEnabled: false});
}
// In the main process, lazily create a storagePrincipal isolated in a