diff --git a/lib/internal/bootstrap/pre_execution.js b/lib/internal/bootstrap/pre_execution.js index ab7e169d7ac938..297aea9dd77640 100644 --- a/lib/internal/bootstrap/pre_execution.js +++ b/lib/internal/bootstrap/pre_execution.js @@ -3,9 +3,9 @@ const { getOptionValue } = require('internal/options'); const { Buffer } = require('buffer'); -function prepareMainThreadExecution() { +function prepareMainThreadExecution(expandArgv1 = false) { // Patch the process object with legacy properties and normalizations - patchProcessObject(); + patchProcessObject(expandArgv1); setupTraceCategoryState(); setupInspectorHooks(); setupWarningHandler(); @@ -48,7 +48,13 @@ function prepareMainThreadExecution() { loadPreloadModules(); } -function patchProcessObject() { +function patchProcessObject(expandArgv1) { + const { + patchProcessObject: patchProcessObjectNative + } = internalBinding('process_methods'); + + patchProcessObjectNative(process); + Object.defineProperty(process, 'argv0', { enumerable: true, configurable: false, @@ -56,6 +62,12 @@ function patchProcessObject() { }); process.argv[0] = process.execPath; + if (expandArgv1 && process.argv[1] && !process.argv[1].startsWith('-')) { + // Expand process.argv[1] into a full path. + const path = require('path'); + process.argv[1] = path.resolve(process.argv[1]); + } + // TODO(joyeecheung): most of these should be deprecated and removed, // execpt some that we need to be able to mutate during run time. addReadOnlyProcessAlias('_eval', '--eval'); diff --git a/lib/internal/main/check_syntax.js b/lib/internal/main/check_syntax.js index 8c73d522edbf69..5bfe4ec3cd6d9c 100644 --- a/lib/internal/main/check_syntax.js +++ b/lib/internal/main/check_syntax.js @@ -18,20 +18,18 @@ const { stripShebang, stripBOM } = require('internal/modules/cjs/helpers'); -let CJSModule; -function CJSModuleInit() { - if (!CJSModule) - CJSModule = require('internal/modules/cjs/loader'); -} +// TODO(joyeecheung): not every one of these are necessary +prepareMainThreadExecution(true); if (process.argv[1] && process.argv[1] !== '-') { // Expand process.argv[1] into a full path. const path = require('path'); process.argv[1] = path.resolve(process.argv[1]); - // TODO(joyeecheung): not every one of these are necessary - prepareMainThreadExecution(); - CJSModuleInit(); + // This has to be done after prepareMainThreadExecution because it + // relies on process.execPath + const CJSModule = require('internal/modules/cjs/loader'); + // Read the source. const filename = CJSModule._resolveFilename(process.argv[1]); @@ -42,9 +40,6 @@ if (process.argv[1] && process.argv[1] !== '-') { checkSyntax(source, filename); } else { - // TODO(joyeecheung): not every one of these are necessary - prepareMainThreadExecution(); - CJSModuleInit(); markBootstrapComplete(); readStdin((code) => { @@ -56,6 +51,10 @@ function checkSyntax(source, filename) { // Remove Shebang. source = stripShebang(source); + // This has to be done after prepareMainThreadExecution because it + // relies on process.execPath + const CJSModule = require('internal/modules/cjs/loader'); + const { getOptionValue } = require('internal/options'); const experimentalModules = getOptionValue('--experimental-modules'); if (experimentalModules) { diff --git a/lib/internal/main/run_main_module.js b/lib/internal/main/run_main_module.js index 634abe493ea60e..8f9d256ecf2c73 100644 --- a/lib/internal/main/run_main_module.js +++ b/lib/internal/main/run_main_module.js @@ -4,11 +4,7 @@ const { prepareMainThreadExecution } = require('internal/bootstrap/pre_execution'); -// Expand process.argv[1] into a full path. -const path = require('path'); -process.argv[1] = path.resolve(process.argv[1]); - -prepareMainThreadExecution(); +prepareMainThreadExecution(true); const CJSModule = require('internal/modules/cjs/loader'); diff --git a/lib/internal/process/warning.js b/lib/internal/process/warning.js index e0e1709bdbd791..71a2c4fa3a3e99 100644 --- a/lib/internal/process/warning.js +++ b/lib/internal/process/warning.js @@ -1,6 +1,5 @@ 'use strict'; -const prefix = `(${process.release.name}:${process.pid}) `; const { ERR_INVALID_ARG_TYPE } = require('internal/errors').codes; // Lazily loaded @@ -55,7 +54,7 @@ function onWarning(warning) { if (isDeprecation && process.noDeprecation) return; const trace = process.traceProcessWarnings || (isDeprecation && process.traceDeprecation); - var msg = prefix; + var msg = `(${process.release.name}:${process.pid}) `; if (warning.code) msg += `[${warning.code}] `; if (trace && warning.stack) { diff --git a/src/env-inl.h b/src/env-inl.h index ef13ffdcc0c6cb..bce36c0f69fe3e 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -630,6 +630,10 @@ inline std::shared_ptr Environment::options() { return options_; } +inline const std::vector& Environment::argv() { + return argv_; +} + inline const std::vector& Environment::exec_argv() { return exec_argv_; } diff --git a/src/env.cc b/src/env.cc index 46f807a3c4fe3c..cc8554032ef0da 100644 --- a/src/env.cc +++ b/src/env.cc @@ -350,16 +350,8 @@ void Environment::ExitEnv() { MaybeLocal Environment::ProcessCliArgs( const std::vector& args, const std::vector& exec_args) { - if (args.size() > 1) { - std::string first_arg = args[1]; - if (first_arg == "inspect") { - execution_mode_ = ExecutionMode::kInspect; - } else if (first_arg == "debug") { - execution_mode_ = ExecutionMode::kDebug; - } else if (first_arg != "-") { - execution_mode_ = ExecutionMode::kRunMainModule; - } - } + argv_ = args; + exec_argv_ = exec_args; if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( TRACING_CATEGORY_NODE1(environment)) != 0) { @@ -377,7 +369,6 @@ MaybeLocal Environment::ProcessCliArgs( std::move(traced_value)); } - exec_argv_ = exec_args; Local process_object = node::CreateProcessObject(this, args, exec_args) .FromMaybe(Local()); diff --git a/src/env.h b/src/env.h index f22d57171d9d31..92b45ff563ec82 100644 --- a/src/env.h +++ b/src/env.h @@ -761,6 +761,7 @@ class Environment { const std::vector& args, const std::vector& exec_args); inline const std::vector& exec_argv(); + inline const std::vector& argv(); typedef void (*HandleCleanupCb)(Environment* env, uv_handle_t* handle, @@ -1057,23 +1058,6 @@ class Environment { inline std::shared_ptr options(); inline std::shared_ptr inspector_host_port(); - enum class ExecutionMode { - kDefault, - kInspect, // node inspect - kDebug, // node debug - kPrintHelp, // node --help - kPrintBashCompletion, // node --completion-bash - kProfProcess, // node --prof-process - kEvalString, // node --eval without --interactive - kCheckSyntax, // node --check (incompatible with --eval) - kRepl, - kEvalStdin, - kRunMainModule - }; - - inline ExecutionMode execution_mode() { return execution_mode_; } - - inline void set_execution_mode(ExecutionMode mode) { execution_mode_ = mode; } inline AsyncRequest* thread_stopper() { return &thread_stopper_; } private: @@ -1085,7 +1069,6 @@ class Environment { inline void ThrowError(v8::Local (*fun)(v8::Local), const char* errmsg); - ExecutionMode execution_mode_ = ExecutionMode::kDefault; std::list loaded_addons_; v8::Isolate* const isolate_; IsolateData* const isolate_data_; @@ -1117,6 +1100,7 @@ class Environment { // used. std::shared_ptr inspector_host_port_; std::vector exec_argv_; + std::vector argv_; uint32_t module_id_counter_ = 0; uint32_t script_id_counter_ = 0; diff --git a/src/node.cc b/src/node.cc index deb4246d357539..2da94b3b98c978 100644 --- a/src/node.cc +++ b/src/node.cc @@ -403,47 +403,44 @@ MaybeLocal StartMainThreadExecution(Environment* env) { return StartExecution(env, "internal/main/run_third_party_main"); } - if (env->execution_mode() == Environment::ExecutionMode::kInspect || - env->execution_mode() == Environment::ExecutionMode::kDebug) { + std::string first_argv; + if (env->argv().size() > 1) { + first_argv = env->argv()[1]; + } + + if (first_argv == "inspect" || first_argv == "debug") { return StartExecution(env, "internal/main/inspect"); } if (per_process::cli_options->print_help) { - env->set_execution_mode(Environment::ExecutionMode::kPrintHelp); return StartExecution(env, "internal/main/print_help"); } if (per_process::cli_options->print_bash_completion) { - env->set_execution_mode(Environment::ExecutionMode::kPrintBashCompletion); return StartExecution(env, "internal/main/print_bash_completion"); } if (env->options()->prof_process) { - env->set_execution_mode(Environment::ExecutionMode::kProfProcess); return StartExecution(env, "internal/main/prof_process"); } // -e/--eval without -i/--interactive if (env->options()->has_eval_string && !env->options()->force_repl) { - env->set_execution_mode(Environment::ExecutionMode::kEvalString); return StartExecution(env, "internal/main/eval_string"); } if (env->options()->syntax_check_only) { - env->set_execution_mode(Environment::ExecutionMode::kCheckSyntax); return StartExecution(env, "internal/main/check_syntax"); } - if (env->execution_mode() == Environment::ExecutionMode::kRunMainModule) { + if (!first_argv.empty() && first_argv != "-") { return StartExecution(env, "internal/main/run_main_module"); } if (env->options()->force_repl || uv_guess_handle(STDIN_FILENO) == UV_TTY) { - env->set_execution_mode(Environment::ExecutionMode::kRepl); return StartExecution(env, "internal/main/repl"); } - env->set_execution_mode(Environment::ExecutionMode::kEvalStdin); return StartExecution(env, "internal/main/eval_stdin"); } diff --git a/src/node_process.h b/src/node_process.h index 4edf10a1c546eb..cb6ad85828b608 100644 --- a/src/node_process.h +++ b/src/node_process.h @@ -35,7 +35,7 @@ v8::MaybeLocal CreateProcessObject( Environment* env, const std::vector& args, const std::vector& exec_args); - +void PatchProcessObject(const v8::FunctionCallbackInfo& args); } // namespace node #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #endif // SRC_NODE_PROCESS_H_ diff --git a/src/node_process_methods.cc b/src/node_process_methods.cc index d2ba00b89b0883..dd27329ee2bcf4 100644 --- a/src/node_process_methods.cc +++ b/src/node_process_methods.cc @@ -426,6 +426,7 @@ static void InitializeProcessMethods(Local target, env->SetMethod(target, "dlopen", binding::DLOpen); env->SetMethod(target, "reallyExit", ReallyExit); env->SetMethodNoSideEffect(target, "uptime", Uptime); + env->SetMethod(target, "patchProcessObject", PatchProcessObject); } } // namespace node diff --git a/src/node_process_object.cc b/src/node_process_object.cc index 0b97a5b21330cf..e36a2a5b148026 100644 --- a/src/node_process_object.cc +++ b/src/node_process_object.cc @@ -13,6 +13,7 @@ using v8::Context; using v8::DEFAULT; using v8::EscapableHandleScope; using v8::Function; +using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::HandleScope; using v8::Integer; @@ -84,20 +85,6 @@ MaybeLocal CreateProcessObject( return MaybeLocal(); } - // process.title - auto title_string = FIXED_ONE_BYTE_STRING(env->isolate(), "title"); - CHECK(process - ->SetAccessor( - env->context(), - title_string, - ProcessTitleGetter, - env->owns_process_state() ? ProcessTitleSetter : nullptr, - env->as_callback_data(), - DEFAULT, - None, - SideEffectType::kHasNoSideEffect) - .FromJust()); - // process.version READONLY_PROPERTY(process, "version", @@ -140,34 +127,56 @@ MaybeLocal CreateProcessObject( #endif // _WIN32 #endif // NODE_HAS_RELEASE_URLS + // process._rawDebug: may be overwritten later in JS land, but should be + // availbale from the begining for debugging purposes + env->SetMethod(process, "_rawDebug", RawDebug); + + return scope.Escape(process); +} + +void PatchProcessObject(const FunctionCallbackInfo& args) { + Isolate* isolate = args.GetIsolate(); + Local context = isolate->GetCurrentContext(); + Environment* env = Environment::GetCurrent(context); + CHECK(args[0]->IsObject()); + Local process = args[0].As(); + + // process.title + CHECK(process + ->SetAccessor( + context, + FIXED_ONE_BYTE_STRING(isolate, "title"), + ProcessTitleGetter, + env->owns_process_state() ? ProcessTitleSetter : nullptr, + env->as_callback_data(), + DEFAULT, + None, + SideEffectType::kHasNoSideEffect) + .FromJust()); + // process.argv - process->Set(env->context(), - FIXED_ONE_BYTE_STRING(env->isolate(), "argv"), - ToV8Value(env->context(), args).ToLocalChecked()).FromJust(); + process->Set(context, + FIXED_ONE_BYTE_STRING(isolate, "argv"), + ToV8Value(context, env->argv()).ToLocalChecked()).FromJust(); // process.execArgv - process->Set(env->context(), - FIXED_ONE_BYTE_STRING(env->isolate(), "execArgv"), - ToV8Value(env->context(), exec_args) + process->Set(context, + FIXED_ONE_BYTE_STRING(isolate, "execArgv"), + ToV8Value(context, env->exec_argv()) .ToLocalChecked()).FromJust(); READONLY_PROPERTY(process, "pid", - Integer::New(env->isolate(), uv_os_getpid())); + Integer::New(isolate, uv_os_getpid())); - CHECK(process->SetAccessor(env->context(), - FIXED_ONE_BYTE_STRING(env->isolate(), "ppid"), + CHECK(process->SetAccessor(context, + FIXED_ONE_BYTE_STRING(isolate, "ppid"), GetParentProcessId).FromJust()); - // TODO(joyeecheung): make this available in JS during pre-execution. - // Note that to use this in releases the code doing the revert need to be - // careful to delay the check until after the bootstrap but that may not - // be possible depending on the feature being reverted. - // --security-revert flags #define V(code, _, __) \ do { \ if (IsReverted(SECURITY_REVERT_ ## code)) { \ - READONLY_PROPERTY(process, "REVERT_" #code, True(env->isolate())); \ + READONLY_PROPERTY(process, "REVERT_" #code, True(isolate)); \ } \ } while (0); SECURITY_REVERSIONS(V) @@ -181,7 +190,7 @@ MaybeLocal CreateProcessObject( if (uv_exepath(exec_path_buf, &exec_path_len) == 0) { exec_path = std::string(exec_path_buf, exec_path_len); } else { - exec_path = args[0]; + exec_path = env->argv()[0]; } // On OpenBSD process.execPath will be relative unless we // get the full path before process.execPath is used. @@ -195,9 +204,9 @@ MaybeLocal CreateProcessObject( } #endif process - ->Set(env->context(), - FIXED_ONE_BYTE_STRING(env->isolate(), "execPath"), - String::NewFromUtf8(env->isolate(), + ->Set(context, + FIXED_ONE_BYTE_STRING(isolate, "execPath"), + String::NewFromUtf8(isolate, exec_path.c_str(), NewStringType::kInternalized, exec_path.size()) @@ -206,20 +215,13 @@ MaybeLocal CreateProcessObject( } // process.debugPort - auto debug_port_string = FIXED_ONE_BYTE_STRING(env->isolate(), "debugPort"); CHECK(process - ->SetAccessor(env->context(), - debug_port_string, + ->SetAccessor(context, + FIXED_ONE_BYTE_STRING(isolate, "debugPort"), DebugPortGetter, env->owns_process_state() ? DebugPortSetter : nullptr, env->as_callback_data()) .FromJust()); - - // process._rawDebug: may be overwritten later in JS land, but should be - // availbale from the begining for debugging purposes - env->SetMethod(process, "_rawDebug", RawDebug); - - return scope.Escape(process); } } // namespace node diff --git a/src/node_worker.cc b/src/node_worker.cc index 8fabbffba49939..c93584c68c8f6f 100644 --- a/src/node_worker.cc +++ b/src/node_worker.cc @@ -96,6 +96,7 @@ Worker::Worker(Environment* env, env->inspector_agent()->GetParentHandle(thread_id_, url); #endif + argv_ = std::vector{env->argv()[0]}; // Mark this Worker object as weak until we actually start the thread. MakeWeak(); @@ -260,8 +261,7 @@ void Worker::Run() { env_->set_worker_context(this); env_->InitializeLibuv(profiler_idle_notifier_started_); - env_->ProcessCliArgs(std::vector{}, - std::move(exec_argv_)); + env_->ProcessCliArgs(std::move(argv_), std::move(exec_argv_)); } { Mutex::ScopedLock lock(mutex_); diff --git a/src/node_worker.h b/src/node_worker.h index 94af8160c68ba5..8239826a0e8b04 100644 --- a/src/node_worker.h +++ b/src/node_worker.h @@ -58,6 +58,8 @@ class Worker : public AsyncWrap { std::shared_ptr per_isolate_opts_; std::vector exec_argv_; + std::vector argv_; + MultiIsolatePlatform* platform_; v8::Isolate* isolate_ = nullptr; bool profiler_idle_notifier_started_;