diff --git a/lib/browser/objects-registry.js b/lib/browser/objects-registry.js index aeaf5351dc0..bfb9091e658 100644 --- a/lib/browser/objects-registry.js +++ b/lib/browser/objects-registry.js @@ -19,17 +19,14 @@ class ObjectsRegistry { // registered then the already assigned ID would be returned. add (webContents, obj) { // Get or assign an ID to the object. - let id = this.saveToStorage(obj) + const id = this.saveToStorage(obj) // Add object to the set of referenced objects. - let webContentsId = webContents.getId() + const webContentsId = webContents.getId() let owner = this.owners[webContentsId] if (!owner) { owner = this.owners[webContentsId] = new Set() - // Clear the storage when webContents is reloaded/navigated. - webContents.once('render-view-deleted', () => { - this.clear(webContentsId) - }) + this.registerDeleteListener(webContents, webContentsId) } if (!owner.has(id)) { owner.add(id) @@ -90,9 +87,21 @@ class ObjectsRegistry { pointer.count -= 1 if (pointer.count === 0) { v8Util.deleteHiddenValue(pointer.object, 'atomId') - return delete this.storage[id] + delete this.storage[id] } } + + // Private: Clear the storage when webContents is reloaded/navigated. + registerDeleteListener (webContents, webContentsId) { + const processId = webContents.getProcessId() + const listener = (event, deletedProcessId) => { + if (deletedProcessId === processId) { + webContents.removeListener('render-view-deleted', listener) + this.clear(webContentsId) + } + } + webContents.on('render-view-deleted', listener) + } } module.exports = new ObjectsRegistry() diff --git a/spec/api-ipc-spec.js b/spec/api-ipc-spec.js index 4d368134469..9cb3a4c5069 100644 --- a/spec/api-ipc-spec.js +++ b/spec/api-ipc-spec.js @@ -517,4 +517,19 @@ describe('ipc module', function () { ipcRenderer.removeAllListeners('test-event') assert.equal(ipcRenderer.listenerCount('test-event'), 0) }) + + describe('remote objects registry', function () { + it('does not dereference until the render view is deleted (regression)', function (done) { + w = new BrowserWindow({ + show: true + }) + + ipcMain.once('error-message', (event, message) => { + assert(message.startsWith('Cannot call function \'getURL\' on missing remote object'), message) + done() + }) + + w.loadURL('file://' + path.join(fixtures, 'api', 'render-view-deleted.html')) + }) + }) }) diff --git a/spec/fixtures/api/render-view-deleted.html b/spec/fixtures/api/render-view-deleted.html new file mode 100644 index 00000000000..bfc281eb429 --- /dev/null +++ b/spec/fixtures/api/render-view-deleted.html @@ -0,0 +1,32 @@ + + +
+ +