Browse Source

fix: renderer crash on setImmediate (#26748)

Shelley Vohr 4 years ago
parent
commit
738740fd7d

+ 23 - 0
shell/common/node_bindings.cc

@@ -141,6 +141,23 @@ bool IsPackagedApp() {
 #endif
 }
 
+void ErrorMessageListener(v8::Local<v8::Message> message,
+                          v8::Local<v8::Value> data) {
+  v8::Isolate* isolate = v8::Isolate::GetCurrent();
+  node::Environment* env = node::Environment::GetCurrent(isolate);
+
+  // TODO(codebytere): properly emit the after() hooks now
+  // that the exception has been handled.
+  // See node/lib/internal/process/execution.js#L176-L180
+
+  // Ensure that the async id stack is properly cleared so the async
+  // hook stack does not become corrupted.
+
+  if (env) {
+    env->async_hooks()->clear_async_id_stack();
+  }
+}
+
 // Initialize NODE_OPTIONS to pass to Node.js
 void SetNodeOptions(base::Environment* env) {
   // Options that are unilaterally disallowed
@@ -379,6 +396,12 @@ node::Environment* NodeBindings::CreateEnvironment(
     // Node uses the deprecated SetAutorunMicrotasks(false) mode, we should
     // switch to use the scoped policy to match blink's behavior.
     context->GetIsolate()->SetMicrotasksPolicy(v8::MicrotasksPolicy::kScoped);
+
+    // Isolate message listeners are additive (you can add multiple), so instead
+    // we add an extra one here to ensure that the async hook stack is properly
+    // cleared when errors are thrown.
+    context->GetIsolate()->AddMessageListenerWithErrorLevel(
+        ErrorMessageListener, v8::Isolate::kMessageError);
   }
 
   gin_helper::Dictionary process(context->GetIsolate(), env->process_object());

+ 22 - 0
spec-main/fixtures/crash-cases/setimmediate-renderer-crash/index.js

@@ -0,0 +1,22 @@
+const { app, BrowserWindow } = require('electron');
+const path = require('path');
+
+app.whenReady().then(() => {
+  const win = new BrowserWindow({
+    show: false,
+    webPreferences: {
+      nodeIntegration: true,
+      preload: path.resolve(__dirname, 'preload.js')
+    }
+  });
+
+  win.loadURL('about:blank');
+
+  win.webContents.on('render-process-gone', () => {
+    process.exit(1);
+  });
+
+  win.webContents.on('did-finish-load', () => {
+    setTimeout(() => app.quit());
+  });
+});

+ 3 - 0
spec-main/fixtures/crash-cases/setimmediate-renderer-crash/preload.js

@@ -0,0 +1,3 @@
+setImmediate(() => {
+  throw new Error('oh no');
+});