fix double-freeing remote references

After the page does navigations, garbage collection can still happen in
the old context. This commit changes to store references to remote objects
by _pages_, instead of by _WebContents_.
This commit is contained in:
Cheng Zhao 2018-07-10 17:15:40 +09:00
parent 9431677e79
commit adf49daaac
9 changed files with 139 additions and 113 deletions

View file

@ -17,16 +17,15 @@ class ObjectsRegistry {
// Register a new object and return its assigned ID. If the object is already
// registered then the already assigned ID would be returned.
add (webContents, obj) {
add (webContents, contextId, obj) {
// Get or assign an ID to the object.
const id = this.saveToStorage(obj)
// Add object to the set of referenced objects.
const webContentsId = webContents.getId()
let owner = this.owners[webContentsId]
let owner = this.owners[contextId]
if (!owner) {
owner = this.owners[webContentsId] = new Set()
this.registerDeleteListener(webContents, webContentsId)
owner = this.owners[contextId] = new Set()
this.registerDeleteListener(webContents, contextId)
}
if (!owner.has(id)) {
owner.add(id)
@ -43,25 +42,26 @@ class ObjectsRegistry {
}
// Dereference an object according to its ID.
remove (webContentsId, id) {
// Dereference from the storage.
this.dereference(id)
// Also remove the reference in owner.
let owner = this.owners[webContentsId]
// Note that an object may be double-freed (cleared when page is reloaded, and
// then garbage collected in old page).
remove (contextId, id) {
let owner = this.owners[contextId]
if (owner) {
// Remove the reference in owner.
owner.delete(id)
// Dereference from the storage.
this.dereference(id)
}
}
// Clear all references to objects refrenced by the WebContents.
clear (webContentsId) {
let owner = this.owners[webContentsId]
clear (contextId) {
let owner = this.owners[contextId]
if (!owner) return
for (let id of owner) this.dereference(id)
delete this.owners[webContentsId]
delete this.owners[contextId]
}
// Private: Saves the object into storage and assigns an ID for it.
@ -92,12 +92,12 @@ class ObjectsRegistry {
}
// Private: Clear the storage when webContents is reloaded/navigated.
registerDeleteListener (webContents, webContentsId) {
registerDeleteListener (webContents, contextId) {
const processId = webContents.getProcessId()
const listener = (event, deletedProcessId) => {
if (deletedProcessId === processId) {
webContents.removeListener('render-view-deleted', listener)
this.clear(webContentsId)
this.clear(contextId)
}
}
webContents.on('render-view-deleted', listener)