process: patch more process properties during pre-execution
Delay the creation of process properties that depend on runtime states and properties that should not be accessed during bootstrap and patch them during pre-execution: - process.argv - process.execPath - process.title - process.pid - process.ppid - process.REVERT_* - process.debugPort PR-URL: https://github.com/nodejs/node/pull/26945 Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
This commit is contained in:
parent
d005f382cd
commit
9dba96dc1a
@ -3,9 +3,9 @@
|
|||||||
const { getOptionValue } = require('internal/options');
|
const { getOptionValue } = require('internal/options');
|
||||||
const { Buffer } = require('buffer');
|
const { Buffer } = require('buffer');
|
||||||
|
|
||||||
function prepareMainThreadExecution() {
|
function prepareMainThreadExecution(expandArgv1 = false) {
|
||||||
// Patch the process object with legacy properties and normalizations
|
// Patch the process object with legacy properties and normalizations
|
||||||
patchProcessObject();
|
patchProcessObject(expandArgv1);
|
||||||
setupTraceCategoryState();
|
setupTraceCategoryState();
|
||||||
setupInspectorHooks();
|
setupInspectorHooks();
|
||||||
setupWarningHandler();
|
setupWarningHandler();
|
||||||
@ -48,7 +48,13 @@ function prepareMainThreadExecution() {
|
|||||||
loadPreloadModules();
|
loadPreloadModules();
|
||||||
}
|
}
|
||||||
|
|
||||||
function patchProcessObject() {
|
function patchProcessObject(expandArgv1) {
|
||||||
|
const {
|
||||||
|
patchProcessObject: patchProcessObjectNative
|
||||||
|
} = internalBinding('process_methods');
|
||||||
|
|
||||||
|
patchProcessObjectNative(process);
|
||||||
|
|
||||||
Object.defineProperty(process, 'argv0', {
|
Object.defineProperty(process, 'argv0', {
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
configurable: false,
|
configurable: false,
|
||||||
@ -56,6 +62,12 @@ function patchProcessObject() {
|
|||||||
});
|
});
|
||||||
process.argv[0] = process.execPath;
|
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,
|
// TODO(joyeecheung): most of these should be deprecated and removed,
|
||||||
// execpt some that we need to be able to mutate during run time.
|
// execpt some that we need to be able to mutate during run time.
|
||||||
addReadOnlyProcessAlias('_eval', '--eval');
|
addReadOnlyProcessAlias('_eval', '--eval');
|
||||||
|
@ -18,20 +18,18 @@ const {
|
|||||||
stripShebang, stripBOM
|
stripShebang, stripBOM
|
||||||
} = require('internal/modules/cjs/helpers');
|
} = require('internal/modules/cjs/helpers');
|
||||||
|
|
||||||
let CJSModule;
|
// TODO(joyeecheung): not every one of these are necessary
|
||||||
function CJSModuleInit() {
|
prepareMainThreadExecution(true);
|
||||||
if (!CJSModule)
|
|
||||||
CJSModule = require('internal/modules/cjs/loader');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (process.argv[1] && process.argv[1] !== '-') {
|
if (process.argv[1] && process.argv[1] !== '-') {
|
||||||
// Expand process.argv[1] into a full path.
|
// Expand process.argv[1] into a full path.
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
process.argv[1] = path.resolve(process.argv[1]);
|
process.argv[1] = path.resolve(process.argv[1]);
|
||||||
|
|
||||||
// TODO(joyeecheung): not every one of these are necessary
|
// This has to be done after prepareMainThreadExecution because it
|
||||||
prepareMainThreadExecution();
|
// relies on process.execPath
|
||||||
CJSModuleInit();
|
const CJSModule = require('internal/modules/cjs/loader');
|
||||||
|
|
||||||
// Read the source.
|
// Read the source.
|
||||||
const filename = CJSModule._resolveFilename(process.argv[1]);
|
const filename = CJSModule._resolveFilename(process.argv[1]);
|
||||||
|
|
||||||
@ -42,9 +40,6 @@ if (process.argv[1] && process.argv[1] !== '-') {
|
|||||||
|
|
||||||
checkSyntax(source, filename);
|
checkSyntax(source, filename);
|
||||||
} else {
|
} else {
|
||||||
// TODO(joyeecheung): not every one of these are necessary
|
|
||||||
prepareMainThreadExecution();
|
|
||||||
CJSModuleInit();
|
|
||||||
markBootstrapComplete();
|
markBootstrapComplete();
|
||||||
|
|
||||||
readStdin((code) => {
|
readStdin((code) => {
|
||||||
@ -56,6 +51,10 @@ function checkSyntax(source, filename) {
|
|||||||
// Remove Shebang.
|
// Remove Shebang.
|
||||||
source = stripShebang(source);
|
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 { getOptionValue } = require('internal/options');
|
||||||
const experimentalModules = getOptionValue('--experimental-modules');
|
const experimentalModules = getOptionValue('--experimental-modules');
|
||||||
if (experimentalModules) {
|
if (experimentalModules) {
|
||||||
|
@ -4,11 +4,7 @@ const {
|
|||||||
prepareMainThreadExecution
|
prepareMainThreadExecution
|
||||||
} = require('internal/bootstrap/pre_execution');
|
} = require('internal/bootstrap/pre_execution');
|
||||||
|
|
||||||
// Expand process.argv[1] into a full path.
|
prepareMainThreadExecution(true);
|
||||||
const path = require('path');
|
|
||||||
process.argv[1] = path.resolve(process.argv[1]);
|
|
||||||
|
|
||||||
prepareMainThreadExecution();
|
|
||||||
|
|
||||||
const CJSModule = require('internal/modules/cjs/loader');
|
const CJSModule = require('internal/modules/cjs/loader');
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const prefix = `(${process.release.name}:${process.pid}) `;
|
|
||||||
const { ERR_INVALID_ARG_TYPE } = require('internal/errors').codes;
|
const { ERR_INVALID_ARG_TYPE } = require('internal/errors').codes;
|
||||||
|
|
||||||
// Lazily loaded
|
// Lazily loaded
|
||||||
@ -55,7 +54,7 @@ function onWarning(warning) {
|
|||||||
if (isDeprecation && process.noDeprecation) return;
|
if (isDeprecation && process.noDeprecation) return;
|
||||||
const trace = process.traceProcessWarnings ||
|
const trace = process.traceProcessWarnings ||
|
||||||
(isDeprecation && process.traceDeprecation);
|
(isDeprecation && process.traceDeprecation);
|
||||||
var msg = prefix;
|
var msg = `(${process.release.name}:${process.pid}) `;
|
||||||
if (warning.code)
|
if (warning.code)
|
||||||
msg += `[${warning.code}] `;
|
msg += `[${warning.code}] `;
|
||||||
if (trace && warning.stack) {
|
if (trace && warning.stack) {
|
||||||
|
@ -35,7 +35,7 @@ v8::MaybeLocal<v8::Object> CreateProcessObject(
|
|||||||
Environment* env,
|
Environment* env,
|
||||||
const std::vector<std::string>& args,
|
const std::vector<std::string>& args,
|
||||||
const std::vector<std::string>& exec_args);
|
const std::vector<std::string>& exec_args);
|
||||||
|
void PatchProcessObject(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
} // namespace node
|
} // namespace node
|
||||||
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
||||||
#endif // SRC_NODE_PROCESS_H_
|
#endif // SRC_NODE_PROCESS_H_
|
||||||
|
@ -426,6 +426,7 @@ static void InitializeProcessMethods(Local<Object> target,
|
|||||||
env->SetMethod(target, "dlopen", binding::DLOpen);
|
env->SetMethod(target, "dlopen", binding::DLOpen);
|
||||||
env->SetMethod(target, "reallyExit", ReallyExit);
|
env->SetMethod(target, "reallyExit", ReallyExit);
|
||||||
env->SetMethodNoSideEffect(target, "uptime", Uptime);
|
env->SetMethodNoSideEffect(target, "uptime", Uptime);
|
||||||
|
env->SetMethod(target, "patchProcessObject", PatchProcessObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace node
|
} // namespace node
|
||||||
|
@ -13,6 +13,7 @@ using v8::Context;
|
|||||||
using v8::DEFAULT;
|
using v8::DEFAULT;
|
||||||
using v8::EscapableHandleScope;
|
using v8::EscapableHandleScope;
|
||||||
using v8::Function;
|
using v8::Function;
|
||||||
|
using v8::FunctionCallbackInfo;
|
||||||
using v8::FunctionTemplate;
|
using v8::FunctionTemplate;
|
||||||
using v8::HandleScope;
|
using v8::HandleScope;
|
||||||
using v8::Integer;
|
using v8::Integer;
|
||||||
@ -84,20 +85,6 @@ MaybeLocal<Object> CreateProcessObject(
|
|||||||
return MaybeLocal<Object>();
|
return MaybeLocal<Object>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
// process.version
|
||||||
READONLY_PROPERTY(process,
|
READONLY_PROPERTY(process,
|
||||||
"version",
|
"version",
|
||||||
@ -140,34 +127,56 @@ MaybeLocal<Object> CreateProcessObject(
|
|||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
#endif // NODE_HAS_RELEASE_URLS
|
#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<Value>& args) {
|
||||||
|
Isolate* isolate = args.GetIsolate();
|
||||||
|
Local<Context> context = isolate->GetCurrentContext();
|
||||||
|
Environment* env = Environment::GetCurrent(context);
|
||||||
|
CHECK(args[0]->IsObject());
|
||||||
|
Local<Object> process = args[0].As<Object>();
|
||||||
|
|
||||||
|
// 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.argv
|
||||||
process->Set(env->context(),
|
process->Set(context,
|
||||||
FIXED_ONE_BYTE_STRING(env->isolate(), "argv"),
|
FIXED_ONE_BYTE_STRING(isolate, "argv"),
|
||||||
ToV8Value(env->context(), args).ToLocalChecked()).FromJust();
|
ToV8Value(context, env->argv()).ToLocalChecked()).FromJust();
|
||||||
|
|
||||||
// process.execArgv
|
// process.execArgv
|
||||||
process->Set(env->context(),
|
process->Set(context,
|
||||||
FIXED_ONE_BYTE_STRING(env->isolate(), "execArgv"),
|
FIXED_ONE_BYTE_STRING(isolate, "execArgv"),
|
||||||
ToV8Value(env->context(), exec_args)
|
ToV8Value(context, env->exec_argv())
|
||||||
.ToLocalChecked()).FromJust();
|
.ToLocalChecked()).FromJust();
|
||||||
|
|
||||||
READONLY_PROPERTY(process, "pid",
|
READONLY_PROPERTY(process, "pid",
|
||||||
Integer::New(env->isolate(), uv_os_getpid()));
|
Integer::New(isolate, uv_os_getpid()));
|
||||||
|
|
||||||
CHECK(process->SetAccessor(env->context(),
|
CHECK(process->SetAccessor(context,
|
||||||
FIXED_ONE_BYTE_STRING(env->isolate(), "ppid"),
|
FIXED_ONE_BYTE_STRING(isolate, "ppid"),
|
||||||
GetParentProcessId).FromJust());
|
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
|
// --security-revert flags
|
||||||
#define V(code, _, __) \
|
#define V(code, _, __) \
|
||||||
do { \
|
do { \
|
||||||
if (IsReverted(SECURITY_REVERT_ ## code)) { \
|
if (IsReverted(SECURITY_REVERT_ ## code)) { \
|
||||||
READONLY_PROPERTY(process, "REVERT_" #code, True(env->isolate())); \
|
READONLY_PROPERTY(process, "REVERT_" #code, True(isolate)); \
|
||||||
} \
|
} \
|
||||||
} while (0);
|
} while (0);
|
||||||
SECURITY_REVERSIONS(V)
|
SECURITY_REVERSIONS(V)
|
||||||
@ -181,7 +190,7 @@ MaybeLocal<Object> CreateProcessObject(
|
|||||||
if (uv_exepath(exec_path_buf, &exec_path_len) == 0) {
|
if (uv_exepath(exec_path_buf, &exec_path_len) == 0) {
|
||||||
exec_path = std::string(exec_path_buf, exec_path_len);
|
exec_path = std::string(exec_path_buf, exec_path_len);
|
||||||
} else {
|
} else {
|
||||||
exec_path = args[0];
|
exec_path = env->argv()[0];
|
||||||
}
|
}
|
||||||
// On OpenBSD process.execPath will be relative unless we
|
// On OpenBSD process.execPath will be relative unless we
|
||||||
// get the full path before process.execPath is used.
|
// get the full path before process.execPath is used.
|
||||||
@ -196,9 +205,9 @@ MaybeLocal<Object> CreateProcessObject(
|
|||||||
uv_fs_req_cleanup(&req);
|
uv_fs_req_cleanup(&req);
|
||||||
#endif
|
#endif
|
||||||
process
|
process
|
||||||
->Set(env->context(),
|
->Set(context,
|
||||||
FIXED_ONE_BYTE_STRING(env->isolate(), "execPath"),
|
FIXED_ONE_BYTE_STRING(isolate, "execPath"),
|
||||||
String::NewFromUtf8(env->isolate(),
|
String::NewFromUtf8(isolate,
|
||||||
exec_path.c_str(),
|
exec_path.c_str(),
|
||||||
NewStringType::kInternalized,
|
NewStringType::kInternalized,
|
||||||
exec_path.size())
|
exec_path.size())
|
||||||
@ -207,20 +216,13 @@ MaybeLocal<Object> CreateProcessObject(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// process.debugPort
|
// process.debugPort
|
||||||
auto debug_port_string = FIXED_ONE_BYTE_STRING(env->isolate(), "debugPort");
|
|
||||||
CHECK(process
|
CHECK(process
|
||||||
->SetAccessor(env->context(),
|
->SetAccessor(context,
|
||||||
debug_port_string,
|
FIXED_ONE_BYTE_STRING(isolate, "debugPort"),
|
||||||
DebugPortGetter,
|
DebugPortGetter,
|
||||||
env->owns_process_state() ? DebugPortSetter : nullptr,
|
env->owns_process_state() ? DebugPortSetter : nullptr,
|
||||||
env->as_callback_data())
|
env->as_callback_data())
|
||||||
.FromJust());
|
.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
|
} // namespace node
|
||||||
|
Loading…
x
Reference in New Issue
Block a user