Browse Source

fix: throw instead of crash when using ipcRenderer after context released (#23977)

Co-authored-by: Jeremy Apthorp <[email protected]>
trop[bot] 4 years ago
parent
commit
1f0d2594bd
2 changed files with 55 additions and 1 deletions
  1. 33 0
      shell/renderer/api/electron_api_ipc_renderer.cc
  2. 22 1
      spec-main/api-ipc-renderer-spec.ts

+ 33 - 0
shell/renderer/api/electron_api_ipc_renderer.cc

@@ -16,6 +16,7 @@
 #include "shell/common/api/api.mojom.h"
 #include "shell/common/gin_converters/blink_converter.h"
 #include "shell/common/gin_converters/value_converter.h"
+#include "shell/common/gin_helper/error_thrower.h"
 #include "shell/common/gin_helper/function_template_extensions.h"
 #include "shell/common/gin_helper/promise.h"
 #include "shell/common/node_bindings.h"
@@ -29,6 +30,9 @@ using content::RenderFrame;
 
 namespace {
 
+const char kIPCMethodCalledAfterContextReleasedError[] =
+    "IPC method called after context was released";
+
 RenderFrame* GetCurrentRenderFrame() {
   WebLocalFrame* frame = WebLocalFrame::FrameForCurrentContext();
   if (!frame)
@@ -83,9 +87,14 @@ class IPCRenderer : public gin::Wrappable<IPCRenderer>,
 
  private:
   void SendMessage(v8::Isolate* isolate,
+                   gin_helper::ErrorThrower thrower,
                    bool internal,
                    const std::string& channel,
                    v8::Local<v8::Value> arguments) {
+    if (!electron_browser_ptr_) {
+      thrower.ThrowError(kIPCMethodCalledAfterContextReleasedError);
+      return;
+    }
     blink::CloneableMessage message;
     if (!electron::SerializeV8Value(isolate, arguments, &message)) {
       return;
@@ -94,9 +103,14 @@ class IPCRenderer : public gin::Wrappable<IPCRenderer>,
   }
 
   v8::Local<v8::Promise> Invoke(v8::Isolate* isolate,
+                                gin_helper::ErrorThrower thrower,
                                 bool internal,
                                 const std::string& channel,
                                 v8::Local<v8::Value> arguments) {
+    if (!electron_browser_ptr_) {
+      thrower.ThrowError(kIPCMethodCalledAfterContextReleasedError);
+      return v8::Local<v8::Promise>();
+    }
     blink::CloneableMessage message;
     if (!electron::SerializeV8Value(isolate, arguments, &message)) {
       return v8::Local<v8::Promise>();
@@ -119,6 +133,10 @@ class IPCRenderer : public gin::Wrappable<IPCRenderer>,
                    const std::string& channel,
                    v8::Local<v8::Value> message_value,
                    base::Optional<v8::Local<v8::Value>> transfer) {
+    if (!electron_browser_ptr_) {
+      thrower.ThrowError(kIPCMethodCalledAfterContextReleasedError);
+      return;
+    }
     blink::TransferableMessage transferable_message;
     if (!electron::SerializeV8Value(isolate, message_value,
                                     &transferable_message)) {
@@ -152,11 +170,16 @@ class IPCRenderer : public gin::Wrappable<IPCRenderer>,
   }
 
   void SendTo(v8::Isolate* isolate,
+              gin_helper::ErrorThrower thrower,
               bool internal,
               bool send_to_all,
               int32_t web_contents_id,
               const std::string& channel,
               v8::Local<v8::Value> arguments) {
+    if (!electron_browser_ptr_) {
+      thrower.ThrowError(kIPCMethodCalledAfterContextReleasedError);
+      return;
+    }
     blink::CloneableMessage message;
     if (!electron::SerializeV8Value(isolate, arguments, &message)) {
       return;
@@ -166,8 +189,13 @@ class IPCRenderer : public gin::Wrappable<IPCRenderer>,
   }
 
   void SendToHost(v8::Isolate* isolate,
+                  gin_helper::ErrorThrower thrower,
                   const std::string& channel,
                   v8::Local<v8::Value> arguments) {
+    if (!electron_browser_ptr_) {
+      thrower.ThrowError(kIPCMethodCalledAfterContextReleasedError);
+      return;
+    }
     blink::CloneableMessage message;
     if (!electron::SerializeV8Value(isolate, arguments, &message)) {
       return;
@@ -176,9 +204,14 @@ class IPCRenderer : public gin::Wrappable<IPCRenderer>,
   }
 
   v8::Local<v8::Value> SendSync(v8::Isolate* isolate,
+                                gin_helper::ErrorThrower thrower,
                                 bool internal,
                                 const std::string& channel,
                                 v8::Local<v8::Value> arguments) {
+    if (!electron_browser_ptr_) {
+      thrower.ThrowError(kIPCMethodCalledAfterContextReleasedError);
+      return v8::Local<v8::Value>();
+    }
     blink::CloneableMessage message;
     if (!electron::SerializeV8Value(isolate, arguments, &message)) {
       return v8::Local<v8::Value>();

+ 22 - 1
spec-main/api-ipc-renderer-spec.ts

@@ -9,7 +9,7 @@ describe('ipcRenderer module', () => {
 
   let w: BrowserWindow;
   before(async () => {
-    w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true } });
+    w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, nativeWindowOpen: true } });
     await w.loadURL('about:blank');
   });
   after(async () => {
@@ -182,4 +182,25 @@ describe('ipcRenderer module', () => {
       expect(result).to.deep.equal([]);
     });
   });
+
+  describe('after context is released', () => {
+    it('throws an exception', async () => {
+      const error = await w.webContents.executeJavaScript(`(${() => {
+        const child = window.open('', 'child', 'show=no,nodeIntegration=yes')! as any;
+        const childIpc = child.require('electron').ipcRenderer;
+        child.close();
+        return new Promise(resolve => {
+          setTimeout(() => {
+            try {
+              childIpc.send('hello');
+            } catch (e) {
+              resolve(e);
+            }
+            resolve(false);
+          }, 100);
+        });
+      }})()`);
+      expect(error).to.have.property('message', 'IPC method called after context was released');
+    });
+  });
 });