diff --git a/shell/common/node_bindings.cc b/shell/common/node_bindings.cc index 6354eb8bf819e..bba182a82229e 100644 --- a/shell/common/node_bindings.cc +++ b/shell/common/node_bindings.cc @@ -141,6 +141,23 @@ bool IsPackagedApp() { #endif } +void ErrorMessageListener(v8::Local message, + v8::Local 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()); diff --git a/spec-main/fixtures/crash-cases/setimmediate-renderer-crash/index.js b/spec-main/fixtures/crash-cases/setimmediate-renderer-crash/index.js new file mode 100644 index 0000000000000..7960616214020 --- /dev/null +++ b/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()); + }); +}); diff --git a/spec-main/fixtures/crash-cases/setimmediate-renderer-crash/preload.js b/spec-main/fixtures/crash-cases/setimmediate-renderer-crash/preload.js new file mode 100644 index 0000000000000..8e8afb06af723 --- /dev/null +++ b/spec-main/fixtures/crash-cases/setimmediate-renderer-crash/preload.js @@ -0,0 +1,3 @@ +setImmediate(() => { + throw new Error('oh no'); +});