Browse Source

fix: handle electron script errors better (#25331) (#25454)

Co-authored-by: Samuel Attard <[email protected]>

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Samuel Attard 4 years ago
parent
commit
eb8c6a8efd

+ 13 - 6
build/webpack/run-compiler.js

@@ -10,10 +10,9 @@ config.output = {
   filename: path.basename(outPath)
 }
 
-const { wrapInitWithProfilingTimeout } = config;
-delete config.wrapInitWithProfilingTimeout;
+const { wrapInitWithProfilingTimeout, wrapInitWithTryCatch, ...webpackConfig } = config;
 
-webpack(config, (err, stats) => {
+webpack(webpackConfig, (err, stats) => {
   if (err) {
     console.error(err)
     process.exit(1)
@@ -21,9 +20,17 @@ webpack(config, (err, stats) => {
     console.error(stats.toString('normal'))
     process.exit(1)
   } else {
+    let contents = fs.readFileSync(outPath, 'utf8');
+    if (wrapInitWithTryCatch) {
+      contents = `try {
+${contents}
+} catch (err) {
+  console.error('Electron ${webpackConfig.output.filename} script failed to run');
+  console.error(err);
+}`;
+    }
     if (wrapInitWithProfilingTimeout) {
-      const contents = fs.readFileSync(outPath, 'utf8');
-      const newContents = `function ___electron_webpack_init__() {
+      contents = `function ___electron_webpack_init__() {
 ${contents}
 };
 if ((globalThis.process || binding.process).argv.includes("--profile-electron-init")) {
@@ -31,8 +38,8 @@ if ((globalThis.process || binding.process).argv.includes("--profile-electron-in
 } else {
   ___electron_webpack_init__();
 }`;
-      fs.writeFileSync(outPath, newContents);
     }
+    fs.writeFileSync(outPath, contents)
     process.exit(0)
   }
 })

+ 3 - 1
build/webpack/webpack.config.base.js

@@ -25,7 +25,8 @@ module.exports = ({
   loadElectronFromAlternateTarget,
   targetDeletesNodeGlobals,
   target,
-  wrapInitWithProfilingTimeout
+  wrapInitWithProfilingTimeout,
+  wrapInitWithTryCatch
 }) => {
   let entry = path.resolve(electronRoot, 'lib', target, 'init.ts')
   if (!fs.existsSync(entry)) {
@@ -41,6 +42,7 @@ module.exports = ({
       filename: `${target}.bundle.js`
     },
     wrapInitWithProfilingTimeout,
+    wrapInitWithTryCatch,
     resolve: {
       alias: {
         '@electron/internal': path.resolve(electronRoot, 'lib'),

+ 2 - 1
build/webpack/webpack.config.isolated_renderer.js

@@ -1,4 +1,5 @@
 module.exports = require('./webpack.config.base')({
   target: 'isolated_renderer',
-  alwaysHasNode: false
+  alwaysHasNode: false,
+  wrapInitWithTryCatch: true
 })

+ 2 - 1
build/webpack/webpack.config.renderer.js

@@ -2,5 +2,6 @@ module.exports = require('./webpack.config.base')({
   target: 'renderer',
   alwaysHasNode: true,
   targetDeletesNodeGlobals: true,
-  wrapInitWithProfilingTimeout: true
+  wrapInitWithProfilingTimeout: true,
+  wrapInitWithTryCatch: true
 })

+ 1 - 0
build/webpack/webpack.config.sandboxed_renderer.js

@@ -2,4 +2,5 @@ module.exports = require('./webpack.config.base')({
   target: 'sandboxed_renderer',
   alwaysHasNode: false,
   wrapInitWithProfilingTimeout: true,
+  wrapInitWithTryCatch: true
 })

+ 2 - 1
build/webpack/webpack.config.worker.js

@@ -2,5 +2,6 @@ module.exports = require('./webpack.config.base')({
   target: 'worker',
   loadElectronFromAlternateTarget: 'renderer',
   alwaysHasNode: true,
-  targetDeletesNodeGlobals: true
+  targetDeletesNodeGlobals: true,
+  wrapInitWithTryCatch: true
 })

+ 19 - 4
shell/common/node_bindings.cc

@@ -338,10 +338,25 @@ node::Environment* NodeBindings::CreateEnvironment(
   args.insert(args.begin() + 1, init_script);
 
   std::unique_ptr<const char*[]> c_argv = StringVectorToArgArray(args);
-  node::Environment* env = node::CreateEnvironment(
-      node::CreateIsolateData(context->GetIsolate(), uv_loop_, platform),
-      context, args.size(), c_argv.get(), 0, nullptr);
-  DCHECK(env);
+  node::Environment* env;
+  if (browser_env_ != BrowserEnvironment::BROWSER) {
+    v8::TryCatch try_catch(context->GetIsolate());
+    env = node::CreateEnvironment(
+        node::CreateIsolateData(context->GetIsolate(), uv_loop_, platform),
+        context, args.size(), c_argv.get(), 0, nullptr);
+    DCHECK(env);
+    // This will only be caught when something has gone terrible wrong as all
+    // electron scripts are wrapped in a try {} catch {} in run-compiler.js
+    if (try_catch.HasCaught()) {
+      LOG(ERROR) << "Failed to initialize node environment in process: "
+                 << process_type;
+    }
+  } else {
+    env = node::CreateEnvironment(
+        node::CreateIsolateData(context->GetIsolate(), uv_loop_, platform),
+        context, args.size(), c_argv.get(), 0, nullptr);
+    DCHECK(env);
+  }
 
   // Clean up the global _noBrowserGlobals that we unironically injected into
   // the global scope

+ 10 - 2
shell/common/node_util.cc

@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "shell/common/node_util.h"
+#include "base/logging.h"
 #include "shell/common/node_includes.h"
 #include "third_party/electron_node/src/node_native_module_env.h"
 
@@ -17,6 +18,7 @@ v8::MaybeLocal<v8::Value> CompileAndCall(
     std::vector<v8::Local<v8::Value>>* arguments,
     node::Environment* optional_env) {
   v8::Isolate* isolate = context->GetIsolate();
+  v8::TryCatch try_catch(isolate);
   v8::MaybeLocal<v8::Function> compiled =
       node::native_module::NativeModuleEnv::LookupAndCompile(
           context, id, parameters, optional_env);
@@ -24,8 +26,14 @@ v8::MaybeLocal<v8::Value> CompileAndCall(
     return v8::MaybeLocal<v8::Value>();
   }
   v8::Local<v8::Function> fn = compiled.ToLocalChecked().As<v8::Function>();
-  return fn->Call(context, v8::Null(isolate), arguments->size(),
-                  arguments->data());
+  v8::MaybeLocal<v8::Value> ret = fn->Call(
+      context, v8::Null(isolate), arguments->size(), arguments->data());
+  // This will only be caught when something has gone terrible wrong as all
+  // electron scripts are wrapped in a try {} catch {} in run-compiler.js
+  if (try_catch.HasCaught()) {
+    LOG(ERROR) << "Failed to CompileAndCall electron script: " << id;
+  }
+  return ret;
 }
 
 }  // namespace util