electron: [Bug]: crash on browserView.webContents.destroy() call
Preflight Checklist
- I have read the Contributing Guidelines for this project.
- I agree to follow the Code of Conduct that this project adheres to.
- I have searched the issue tracker for a feature request that matches the one I want to file, without success.
Electron Version
13.1.2
What operating system are you using?
Other Linux
Operating System Version
kernel 5.12.8
What arch are you using?
x64
Last Known Working Electron version
No response
Expected Behavior
- The app doesn’t crash.
- The BrowserView process gets properly destroyed.
Actual Behavior
The app crashing if browserView.webContents.destroy()
called to destroy the browserView-related process (memory releasing). It doesn’t crash on first call but on 5-10th browserView.create() => browserView.destroy()
sequential scenario execution (in my case create/destroy calls get triggered by hotkey, so I just hit the respective hotkeys in sequence).
Testcase Gist URL
No response
Additional Information
See the attached crash stack.
Related issue: https://github.com/electron/electron/issues/26929.
As pointed in https://github.com/electron/electron/issues/26929#issuecomment-763837953 wrapping the destroy()
call into setImmediate
prevents the app from crash. So this is a workaround.
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 19 (8 by maintainers)
So will this allow us to call
browserView.webContents.destroy()
without callingwin.setBrowserView(null)
?Ok, here’s what I think is happening to cause this crash:
view.webContents.destroy()
call runs. This causesBrowserView::WebContentsDestroyed()
to run, which sets itsapi_web_contents_
tonullptr
. (ref)win.setBrowserView(null)
is called, which ends up inBaseWindow::ResetBrowserViews()
. (ref).ResetBrowserView
checksif (browser_view->web_contents())
, and usesbrowser_view->web_contents()->owner_window()
to check that the BrowserView is still in the same window that it was added to, and hasn’t been reparented. (ref)browser_view->web_contents()
is nullptr! So it can’t check the owner_window of the WebContents, so it does not callBaseWindow::RemoveBrowserView
on the browser view. It does, however, remove the v8::Global that keeps the BrowserView object alive, freeing it to be garbage-collected by V8. (ref)NativeWindow::browser_views()
list.NativeWindowViews::ShouldDescendIntoChildForEventHandling
iterates thebrowser_views()
list to check draggable regions. This is a Use-After-Free, because by this point the BrowserView could have been deleted by V8’s GC. (ref)I think the solution here has to involve BrowserView knowing which window it’s owned by, rather than using WebContents to indirect that knowledge.