Skip to content

Commit 9dba96d

Browse files
committed
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: #26945 Reviewed-By: Gus Caplan <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]>
1 parent d005f38 commit 9dba96d

7 files changed

+73
-64
lines changed

lib/internal/bootstrap/pre_execution.js

+15-3
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
const { getOptionValue } = require('internal/options');
44
const { Buffer } = require('buffer');
55

6-
function prepareMainThreadExecution() {
6+
function prepareMainThreadExecution(expandArgv1 = false) {
77
// Patch the process object with legacy properties and normalizations
8-
patchProcessObject();
8+
patchProcessObject(expandArgv1);
99
setupTraceCategoryState();
1010
setupInspectorHooks();
1111
setupWarningHandler();
@@ -48,14 +48,26 @@ function prepareMainThreadExecution() {
4848
loadPreloadModules();
4949
}
5050

51-
function patchProcessObject() {
51+
function patchProcessObject(expandArgv1) {
52+
const {
53+
patchProcessObject: patchProcessObjectNative
54+
} = internalBinding('process_methods');
55+
56+
patchProcessObjectNative(process);
57+
5258
Object.defineProperty(process, 'argv0', {
5359
enumerable: true,
5460
configurable: false,
5561
value: process.argv[0]
5662
});
5763
process.argv[0] = process.execPath;
5864

65+
if (expandArgv1 && process.argv[1] && !process.argv[1].startsWith('-')) {
66+
// Expand process.argv[1] into a full path.
67+
const path = require('path');
68+
process.argv[1] = path.resolve(process.argv[1]);
69+
}
70+
5971
// TODO(joyeecheung): most of these should be deprecated and removed,
6072
// execpt some that we need to be able to mutate during run time.
6173
addReadOnlyProcessAlias('_eval', '--eval');

lib/internal/main/check_syntax.js

+10-11
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,18 @@ const {
1818
stripShebang, stripBOM
1919
} = require('internal/modules/cjs/helpers');
2020

21-
let CJSModule;
22-
function CJSModuleInit() {
23-
if (!CJSModule)
24-
CJSModule = require('internal/modules/cjs/loader');
25-
}
21+
// TODO(joyeecheung): not every one of these are necessary
22+
prepareMainThreadExecution(true);
2623

2724
if (process.argv[1] && process.argv[1] !== '-') {
2825
// Expand process.argv[1] into a full path.
2926
const path = require('path');
3027
process.argv[1] = path.resolve(process.argv[1]);
3128

32-
// TODO(joyeecheung): not every one of these are necessary
33-
prepareMainThreadExecution();
34-
CJSModuleInit();
29+
// This has to be done after prepareMainThreadExecution because it
30+
// relies on process.execPath
31+
const CJSModule = require('internal/modules/cjs/loader');
32+
3533
// Read the source.
3634
const filename = CJSModule._resolveFilename(process.argv[1]);
3735

@@ -42,9 +40,6 @@ if (process.argv[1] && process.argv[1] !== '-') {
4240

4341
checkSyntax(source, filename);
4442
} else {
45-
// TODO(joyeecheung): not every one of these are necessary
46-
prepareMainThreadExecution();
47-
CJSModuleInit();
4843
markBootstrapComplete();
4944

5045
readStdin((code) => {
@@ -56,6 +51,10 @@ function checkSyntax(source, filename) {
5651
// Remove Shebang.
5752
source = stripShebang(source);
5853

54+
// This has to be done after prepareMainThreadExecution because it
55+
// relies on process.execPath
56+
const CJSModule = require('internal/modules/cjs/loader');
57+
5958
const { getOptionValue } = require('internal/options');
6059
const experimentalModules = getOptionValue('--experimental-modules');
6160
if (experimentalModules) {

lib/internal/main/run_main_module.js

+1-5
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,7 @@ const {
44
prepareMainThreadExecution
55
} = require('internal/bootstrap/pre_execution');
66

7-
// Expand process.argv[1] into a full path.
8-
const path = require('path');
9-
process.argv[1] = path.resolve(process.argv[1]);
10-
11-
prepareMainThreadExecution();
7+
prepareMainThreadExecution(true);
128

139
const CJSModule = require('internal/modules/cjs/loader');
1410

lib/internal/process/warning.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
'use strict';
22

3-
const prefix = `(${process.release.name}:${process.pid}) `;
43
const { ERR_INVALID_ARG_TYPE } = require('internal/errors').codes;
54

65
// Lazily loaded
@@ -55,7 +54,7 @@ function onWarning(warning) {
5554
if (isDeprecation && process.noDeprecation) return;
5655
const trace = process.traceProcessWarnings ||
5756
(isDeprecation && process.traceDeprecation);
58-
var msg = prefix;
57+
var msg = `(${process.release.name}:${process.pid}) `;
5958
if (warning.code)
6059
msg += `[${warning.code}] `;
6160
if (trace && warning.stack) {

src/node_process.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ v8::MaybeLocal<v8::Object> CreateProcessObject(
3535
Environment* env,
3636
const std::vector<std::string>& args,
3737
const std::vector<std::string>& exec_args);
38-
38+
void PatchProcessObject(const v8::FunctionCallbackInfo<v8::Value>& args);
3939
} // namespace node
4040
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
4141
#endif // SRC_NODE_PROCESS_H_

src/node_process_methods.cc

+1
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,7 @@ static void InitializeProcessMethods(Local<Object> target,
426426
env->SetMethod(target, "dlopen", binding::DLOpen);
427427
env->SetMethod(target, "reallyExit", ReallyExit);
428428
env->SetMethodNoSideEffect(target, "uptime", Uptime);
429+
env->SetMethod(target, "patchProcessObject", PatchProcessObject);
429430
}
430431

431432
} // namespace node

src/node_process_object.cc

+44-42
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ using v8::Context;
1313
using v8::DEFAULT;
1414
using v8::EscapableHandleScope;
1515
using v8::Function;
16+
using v8::FunctionCallbackInfo;
1617
using v8::FunctionTemplate;
1718
using v8::HandleScope;
1819
using v8::Integer;
@@ -84,20 +85,6 @@ MaybeLocal<Object> CreateProcessObject(
8485
return MaybeLocal<Object>();
8586
}
8687

87-
// process.title
88-
auto title_string = FIXED_ONE_BYTE_STRING(env->isolate(), "title");
89-
CHECK(process
90-
->SetAccessor(
91-
env->context(),
92-
title_string,
93-
ProcessTitleGetter,
94-
env->owns_process_state() ? ProcessTitleSetter : nullptr,
95-
env->as_callback_data(),
96-
DEFAULT,
97-
None,
98-
SideEffectType::kHasNoSideEffect)
99-
.FromJust());
100-
10188
// process.version
10289
READONLY_PROPERTY(process,
10390
"version",
@@ -140,34 +127,56 @@ MaybeLocal<Object> CreateProcessObject(
140127
#endif // _WIN32
141128
#endif // NODE_HAS_RELEASE_URLS
142129

130+
// process._rawDebug: may be overwritten later in JS land, but should be
131+
// availbale from the begining for debugging purposes
132+
env->SetMethod(process, "_rawDebug", RawDebug);
133+
134+
return scope.Escape(process);
135+
}
136+
137+
void PatchProcessObject(const FunctionCallbackInfo<Value>& args) {
138+
Isolate* isolate = args.GetIsolate();
139+
Local<Context> context = isolate->GetCurrentContext();
140+
Environment* env = Environment::GetCurrent(context);
141+
CHECK(args[0]->IsObject());
142+
Local<Object> process = args[0].As<Object>();
143+
144+
// process.title
145+
CHECK(process
146+
->SetAccessor(
147+
context,
148+
FIXED_ONE_BYTE_STRING(isolate, "title"),
149+
ProcessTitleGetter,
150+
env->owns_process_state() ? ProcessTitleSetter : nullptr,
151+
env->as_callback_data(),
152+
DEFAULT,
153+
None,
154+
SideEffectType::kHasNoSideEffect)
155+
.FromJust());
156+
143157
// process.argv
144-
process->Set(env->context(),
145-
FIXED_ONE_BYTE_STRING(env->isolate(), "argv"),
146-
ToV8Value(env->context(), args).ToLocalChecked()).FromJust();
158+
process->Set(context,
159+
FIXED_ONE_BYTE_STRING(isolate, "argv"),
160+
ToV8Value(context, env->argv()).ToLocalChecked()).FromJust();
147161

148162
// process.execArgv
149-
process->Set(env->context(),
150-
FIXED_ONE_BYTE_STRING(env->isolate(), "execArgv"),
151-
ToV8Value(env->context(), exec_args)
163+
process->Set(context,
164+
FIXED_ONE_BYTE_STRING(isolate, "execArgv"),
165+
ToV8Value(context, env->exec_argv())
152166
.ToLocalChecked()).FromJust();
153167

154168
READONLY_PROPERTY(process, "pid",
155-
Integer::New(env->isolate(), uv_os_getpid()));
169+
Integer::New(isolate, uv_os_getpid()));
156170

157-
CHECK(process->SetAccessor(env->context(),
158-
FIXED_ONE_BYTE_STRING(env->isolate(), "ppid"),
171+
CHECK(process->SetAccessor(context,
172+
FIXED_ONE_BYTE_STRING(isolate, "ppid"),
159173
GetParentProcessId).FromJust());
160174

161-
// TODO(joyeecheung): make this available in JS during pre-execution.
162-
// Note that to use this in releases the code doing the revert need to be
163-
// careful to delay the check until after the bootstrap but that may not
164-
// be possible depending on the feature being reverted.
165-
166175
// --security-revert flags
167176
#define V(code, _, __) \
168177
do { \
169178
if (IsReverted(SECURITY_REVERT_ ## code)) { \
170-
READONLY_PROPERTY(process, "REVERT_" #code, True(env->isolate())); \
179+
READONLY_PROPERTY(process, "REVERT_" #code, True(isolate)); \
171180
} \
172181
} while (0);
173182
SECURITY_REVERSIONS(V)
@@ -181,7 +190,7 @@ MaybeLocal<Object> CreateProcessObject(
181190
if (uv_exepath(exec_path_buf, &exec_path_len) == 0) {
182191
exec_path = std::string(exec_path_buf, exec_path_len);
183192
} else {
184-
exec_path = args[0];
193+
exec_path = env->argv()[0];
185194
}
186195
// On OpenBSD process.execPath will be relative unless we
187196
// get the full path before process.execPath is used.
@@ -196,9 +205,9 @@ MaybeLocal<Object> CreateProcessObject(
196205
uv_fs_req_cleanup(&req);
197206
#endif
198207
process
199-
->Set(env->context(),
200-
FIXED_ONE_BYTE_STRING(env->isolate(), "execPath"),
201-
String::NewFromUtf8(env->isolate(),
208+
->Set(context,
209+
FIXED_ONE_BYTE_STRING(isolate, "execPath"),
210+
String::NewFromUtf8(isolate,
202211
exec_path.c_str(),
203212
NewStringType::kInternalized,
204213
exec_path.size())
@@ -207,20 +216,13 @@ MaybeLocal<Object> CreateProcessObject(
207216
}
208217

209218
// process.debugPort
210-
auto debug_port_string = FIXED_ONE_BYTE_STRING(env->isolate(), "debugPort");
211219
CHECK(process
212-
->SetAccessor(env->context(),
213-
debug_port_string,
220+
->SetAccessor(context,
221+
FIXED_ONE_BYTE_STRING(isolate, "debugPort"),
214222
DebugPortGetter,
215223
env->owns_process_state() ? DebugPortSetter : nullptr,
216224
env->as_callback_data())
217225
.FromJust());
218-
219-
// process._rawDebug: may be overwritten later in JS land, but should be
220-
// availbale from the begining for debugging purposes
221-
env->SetMethod(process, "_rawDebug", RawDebug);
222-
223-
return scope.Escape(process);
224226
}
225227

226228
} // namespace node

0 commit comments

Comments
 (0)