Browse Source

fix: renderer crash on setImmediate (#26365)

Shelley Vohr 4 years ago
parent
commit
e6db49686b

+ 23 - 0
shell/common/node_bindings.cc

@@ -170,6 +170,23 @@ bool AllowWasmCodeGenerationCallback(v8::Local<v8::Context> context,
                                                v8::String::Empty(isolate));
 }
 
+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.js cli options to pass to Node.js
 // See https://nodejs.org/api/cli.html#cli_options
 void SetNodeCliFlags() {
@@ -470,6 +487,12 @@ node::Environment* NodeBindings::CreateEnvironment(
     // Blink's.
     is.flags &= ~node::IsolateSettingsFlags::MESSAGE_LISTENER_WITH_ERROR_LEVEL;
 
+    // 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);
+
     // We do not want to use the promise rejection callback that Node.js uses,
     // because it does not send PromiseRejectionEvents to the global script
     // context. We need to use the one Blink already provides.

+ 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');
+});