diff --git a/shell/browser/api/electron_api_web_contents.cc b/shell/browser/api/electron_api_web_contents.cc index c74a17b4cfaa..c36f92bfd491 100644 --- a/shell/browser/api/electron_api_web_contents.cc +++ b/shell/browser/api/electron_api_web_contents.cc @@ -1077,7 +1077,7 @@ content::WebContents* WebContents::OpenURLFromTab( return nullptr; } - if (!weak_this) + if (!weak_this || !web_contents()) return nullptr; content::NavigationController::LoadURLParams load_url_params(params.url); @@ -1410,7 +1410,7 @@ void WebContents::RenderProcessGone(base::TerminationStatus status) { Emit("crashed", status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED); // User might destroy WebContents in the crashed event. - if (!weak_this) + if (!weak_this || !web_contents()) return; v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); @@ -1481,7 +1481,7 @@ void WebContents::DidFinishLoad(content::RenderFrameHost* render_frame_host, // ⚠️WARNING!⚠️ // Emit() triggers JS which can call destroy() on |this|. It's not safe to // assume that |this| points to valid memory at this point. - if (is_main_frame && weak_this) + if (is_main_frame && weak_this && web_contents()) Emit("did-finish-load"); } @@ -1885,6 +1885,7 @@ void WebContents::WebContentsDestroyed() { // also do not want any method to be used, so just mark as destroyed here. MarkDestroyed(); + Observe(nullptr); // this->web_contents() will return nullptr Emit("destroyed"); // For guest view based on OOPIF, the WebContents is released by the embedder @@ -2016,7 +2017,7 @@ void WebContents::LoadURL(const GURL& url, // ⚠️WARNING!⚠️ // LoadURLWithParams() triggers JS events which can call destroy() on |this|. // It's not safe to assume that |this| points to valid memory at this point. - if (!weak_this) + if (!weak_this || !web_contents()) return; // Required to make beforeunload handler work. diff --git a/spec-main/api-web-contents-spec.ts b/spec-main/api-web-contents-spec.ts index d0e113eeff46..ed30aa76c6a3 100644 --- a/spec-main/api-web-contents-spec.ts +++ b/spec-main/api-web-contents-spec.ts @@ -2016,6 +2016,13 @@ describe('webContents module', () => { }); contents.loadURL('about:blank').then(() => contents.forcefullyCrashRenderer()); }); + + it('does not crash main process when quiting in it', async () => { + const appPath = path.join(mainFixturesPath, 'apps', 'quit', 'main.js'); + const appProcess = ChildProcess.spawn(process.execPath, [appPath]); + const [code] = await emittedOnce(appProcess, 'close'); + expect(code).to.equal(0); + }); }); it('emits a cancelable event before creating a child webcontents', async () => { diff --git a/spec-main/fixtures/apps/quit/main.js b/spec-main/fixtures/apps/quit/main.js new file mode 100644 index 000000000000..0859ccb2becd --- /dev/null +++ b/spec-main/fixtures/apps/quit/main.js @@ -0,0 +1,10 @@ +const { app, BrowserWindow } = require('electron'); + +app.once('ready', () => { + const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true } }); + w.webContents.once('crashed', () => { + app.quit(); + }); + w.webContents.loadURL('about:blank'); + w.webContents.executeJavaScript('process.crash()'); +});