From d5f4ab4e55b41f43336c432874e12654b1d38c3a Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Wed, 13 Jul 2022 18:19:53 +0800 Subject: [PATCH] fixup! bootstrap: handle snapshot errors gracefully --- doc/api/process.md | 3 +++ src/node_snapshotable.cc | 21 ++++++++++++--------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/doc/api/process.md b/doc/api/process.md index 4b48a6590b7d2a..538020ff868983 100644 --- a/doc/api/process.md +++ b/doc/api/process.md @@ -3822,6 +3822,9 @@ cases: options were set, but the port number chosen was invalid or unavailable. * `13` **Unfinished Top-Level Await**: `await` was used outside of a function in the top-level code, but the passed `Promise` never resolved. +* `14` **Snapshot Failure**: Node.js was started to build a V8 startup + snapshot and it failed because certain requirements of the state of + the application were not met. * `>128` **Signal Exits**: If Node.js receives a fatal signal such as `SIGKILL` or `SIGHUP`, then its exit code will be `128` plus the value of the signal code. This is a standard POSIX practice, since diff --git a/src/node_snapshotable.cc b/src/node_snapshotable.cc index d3e5aa2e02e34f..a43b0e3c6a660d 100644 --- a/src/node_snapshotable.cc +++ b/src/node_snapshotable.cc @@ -177,7 +177,10 @@ void SnapshotBuilder::InitializeIsolateParams(const SnapshotData* data, const_cast(&(data->v8_snapshot_blob_data)); } -constexpr int INTERNAL_ERROR = 12; +// TODO(joyeecheung): share these exit code constants across the code base. +constexpr int UNCAUGHT_EXCEPTION_ERROR = 1; +constexpr int BOOTSTRAP_ERROR = 10; +constexpr int SNAPSHOT_ERROR = 14; int SnapshotBuilder::Generate(SnapshotData* out, const std::vector args, @@ -237,12 +240,12 @@ int SnapshotBuilder::Generate(SnapshotData* out, // without breaking compatibility. Local base_context = NewContext(isolate); if (base_context.IsEmpty()) { - return INTERNAL_ERROR; + return BOOTSTRAP_ERROR; } Local main_context = NewContext(isolate); if (main_context.IsEmpty()) { - return INTERNAL_ERROR; + return BOOTSTRAP_ERROR; } // Initialize the main instance context. { @@ -259,7 +262,7 @@ int SnapshotBuilder::Generate(SnapshotData* out, // Run scripts in lib/internal/bootstrap/ if (env->RunBootstrapping().IsEmpty()) { - return INTERNAL_ERROR; + return BOOTSTRAP_ERROR; } // If --build-snapshot is true, lib/internal/main/mksnapshot.js would be // loaded via LoadEnvironment() to execute process.argv[1] as the entry @@ -272,12 +275,12 @@ int SnapshotBuilder::Generate(SnapshotData* out, env->InitializeInspector({}); #endif if (LoadEnvironment(env, StartExecutionCallback{}).IsEmpty()) { - return 1; + return UNCAUGHT_EXCEPTION_ERROR; } // FIXME(joyeecheung): right now running the loop in the snapshot // builder seems to introduces inconsistencies in JS land that need to // be synchronized again after snapshot restoration. - int exit_code = SpinEventLoop(env).FromMaybe(1); + int exit_code = SpinEventLoop(env).FromMaybe(UNCAUGHT_EXCEPTION_ERROR); if (exit_code != 0) { return exit_code; } @@ -294,7 +297,7 @@ int SnapshotBuilder::Generate(SnapshotData* out, #ifdef NODE_USE_NODE_CODE_CACHE // Regenerate all the code cache. if (!native_module::NativeModuleEnv::CompileAllModules(main_context)) { - return INTERNAL_ERROR; + return UNCAUGHT_EXCEPTION_ERROR; } native_module::NativeModuleEnv::CopyCodeCache(&(out->code_cache)); for (const auto& item : out->code_cache) { @@ -325,7 +328,7 @@ int SnapshotBuilder::Generate(SnapshotData* out, // We must be able to rehash the blob when we restore it or otherwise // the hash seed would be fixed by V8, introducing a vulnerability. if (!out->v8_snapshot_blob_data.CanBeRehashed()) { - return INTERNAL_ERROR; + return SNAPSHOT_ERROR; } // We cannot resurrect the handles from the snapshot, so make sure that @@ -338,7 +341,7 @@ int SnapshotBuilder::Generate(SnapshotData* out, PrintLibuvHandleInformation(env->event_loop(), stderr); } if (!queues_are_empty) { - return INTERNAL_ERROR; + return SNAPSHOT_ERROR; } return 0; }