Skip to content

Commit d35f870

Browse files
legendecastargos
authored andcommitted
src: bootstrap prepare stack trace callback in shadow realm
Bootstrap per-realm callbacks like `prepare_stack_trace_callback` in the ShadowRealm. This enables stack trace decoration in the ShadowRealm. PR-URL: #47107 Reviewed-By: Yagiz Nizipli <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Joyee Cheung <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent d668738 commit d35f870

File tree

18 files changed

+79
-69
lines changed

18 files changed

+79
-69
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@
8989
/doc/api/module.md @nodejs/modules @nodejs/loaders
9090
/doc/api/modules.md @nodejs/modules @nodejs/loaders
9191
/doc/api/packages.md @nodejs/modules @nodejs/loaders
92-
/lib/internal/bootstrap/loaders.js @nodejs/modules @nodejs/loaders
92+
/lib/internal/bootstrap/realm.js @nodejs/modules @nodejs/loaders
9393
/lib/internal/modules/* @nodejs/modules @nodejs/loaders
9494
/lib/internal/process/esm_loader.js @nodejs/modules @nodejs/loaders
9595
/lib/internal/process/execution.js @nodejs/modules @nodejs/loaders

lib/assert.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ const { openSync, closeSync, readSync } = require('fs');
6565
const { inspect } = require('internal/util/inspect');
6666
const { isPromise, isRegExp } = require('internal/util/types');
6767
const { EOL } = require('internal/constants');
68-
const { BuiltinModule } = require('internal/bootstrap/loaders');
68+
const { BuiltinModule } = require('internal/bootstrap/realm');
6969
const { isError } = require('internal/util');
7070

7171
const errorCache = new SafeMap();

lib/internal/bootstrap/node.js

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Hello, and welcome to hacking node.js!
22
//
3-
// This file is invoked by `Realm::BootstrapNode()` in `src/node_realm.cc`,
3+
// This file is invoked by `Realm::BootstrapRealm()` in `src/node_realm.cc`,
44
// and is responsible for setting up Node.js core before main scripts
55
// under `lib/internal/main/` are executed.
66
//
@@ -32,9 +32,10 @@
3232
// `DOMException` class.
3333
// - `lib/internal/per_context/messageport.js`: JS-side components of the
3434
// `MessagePort` implementation.
35-
// - `lib/internal/bootstrap/loaders.js`: this sets up internal binding and
35+
// - `lib/internal/bootstrap/realm.js`: this sets up internal binding and
3636
// module loaders, including `process.binding()`, `process._linkedBinding()`,
37-
// `internalBinding()` and `BuiltinModule`.
37+
// `internalBinding()` and `BuiltinModule`, and per-realm internal states
38+
// and bindings, including `prepare_stack_trace_callback`.
3839
//
3940
// The initialization done in this script is included in both the main thread
4041
// and the worker threads. After this, further initialization is done based
@@ -52,8 +53,6 @@
5253
// passed by `BuiltinLoader::CompileAndCall()`.
5354
/* global process, require, internalBinding, primordials */
5455

55-
setupPrepareStackTrace();
56-
5756
const {
5857
FunctionPrototypeCall,
5958
JSONParse,
@@ -364,25 +363,6 @@ process.emitWarning = emitWarning;
364363
// Note: only after this point are the timers effective
365364
}
366365

367-
function setupPrepareStackTrace() {
368-
const {
369-
setEnhanceStackForFatalException,
370-
setPrepareStackTraceCallback,
371-
} = internalBinding('errors');
372-
const {
373-
prepareStackTrace,
374-
fatalExceptionStackEnhancers: {
375-
beforeInspector,
376-
afterInspector,
377-
},
378-
} = require('internal/errors');
379-
// Tell our PrepareStackTraceCallback passed to the V8 API
380-
// to call prepareStackTrace().
381-
setPrepareStackTraceCallback(prepareStackTrace);
382-
// Set the function used to enhance the error stack for printing
383-
setEnhanceStackForFatalException(beforeInspector, afterInspector);
384-
}
385-
386366
function setupProcessObject() {
387367
const EventEmitter = require('events');
388368
const origProcProto = ObjectGetPrototypeOf(process);

lib/internal/bootstrap/loaders.js renamed to lib/internal/bootstrap/realm.js

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
// This file is executed in every realm that is created by Node.js, including
2+
// the context of main thread, worker threads, and ShadowRealms.
3+
// Only per-realm internal states and bindings should be bootstrapped in this
4+
// file and no globals should be exposed to the user code.
5+
//
16
// This file creates the internal module & binding loaders used by built-in
27
// modules. In contrast, user land modules are loaded using
38
// lib/internal/modules/cjs/loader.js (CommonJS Modules) or
@@ -30,7 +35,7 @@
3035
// so they can be loaded faster without the cost of I/O. This class makes the
3136
// lib/internal/*, deps/internal/* modules and internalBinding() available by
3237
// default to core modules, and lets the core modules require itself via
33-
// require('internal/bootstrap/loaders') even when this file is not written in
38+
// require('internal/bootstrap/realm') even when this file is not written in
3439
// CommonJS style.
3540
//
3641
// Other objects:
@@ -181,7 +186,7 @@ let internalBinding;
181186
};
182187
}
183188

184-
const loaderId = 'internal/bootstrap/loaders';
189+
const selfId = 'internal/bootstrap/realm';
185190
const {
186191
builtinIds,
187192
compileFunction,
@@ -238,7 +243,7 @@ class BuiltinModule {
238243
static exposeInternals() {
239244
for (const { 0: id, 1: mod } of BuiltinModule.map) {
240245
// Do not expose this to user land even with --expose-internals.
241-
if (id !== loaderId) {
246+
if (id !== selfId) {
242247
mod.canBeRequiredByUsers = true;
243248
}
244249
}
@@ -357,7 +362,7 @@ const loaderExports = {
357362
};
358363

359364
function requireBuiltin(id) {
360-
if (id === loaderId) {
365+
if (id === selfId) {
361366
return loaderExports;
362367
}
363368

@@ -379,5 +384,27 @@ function requireWithFallbackInDeps(request) {
379384
return requireBuiltin(request);
380385
}
381386

387+
function setupPrepareStackTrace() {
388+
const {
389+
setEnhanceStackForFatalException,
390+
setPrepareStackTraceCallback,
391+
} = internalBinding('errors');
392+
const {
393+
prepareStackTrace,
394+
fatalExceptionStackEnhancers: {
395+
beforeInspector,
396+
afterInspector,
397+
},
398+
} = requireBuiltin('internal/errors');
399+
// Tell our PrepareStackTraceCallback passed to the V8 API
400+
// to call prepareStackTrace().
401+
setPrepareStackTraceCallback(prepareStackTrace);
402+
// Set the function used to enhance the error stack for printing
403+
setEnhanceStackForFatalException(beforeInspector, afterInspector);
404+
}
405+
382406
// Store the internal loaders in C++.
383407
setInternalLoaders(internalBinding, requireBuiltin);
408+
409+
// Setup per-realm bindings.
410+
setupPrepareStackTrace();

lib/internal/main/mksnapshot.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const {
1212
} = primordials;
1313

1414
const binding = internalBinding('mksnapshot');
15-
const { BuiltinModule } = require('internal/bootstrap/loaders');
15+
const { BuiltinModule } = require('internal/bootstrap/realm');
1616
const {
1717
compileSerializeMain,
1818
} = binding;

lib/internal/modules/cjs/loader.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ module.exports = {
7676
initializeCJS,
7777
};
7878

79-
const { BuiltinModule } = require('internal/bootstrap/loaders');
79+
const { BuiltinModule } = require('internal/bootstrap/realm');
8080
const {
8181
maybeCacheSourceMap,
8282
} = require('internal/source_map/source_map_cache');

lib/internal/modules/esm/hooks.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ class Hooks {
190190
filename: '<preload>',
191191
},
192192
);
193-
const { BuiltinModule } = require('internal/bootstrap/loaders');
193+
const { BuiltinModule } = require('internal/bootstrap/realm');
194194
// We only allow replacing the importMetaInitializer during preload;
195195
// after preload is finished, we disable the ability to replace it.
196196
//

lib/internal/modules/esm/resolve.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const {
2424
StringPrototypeStartsWith,
2525
} = primordials;
2626
const internalFS = require('internal/fs/utils');
27-
const { BuiltinModule } = require('internal/bootstrap/loaders');
27+
const { BuiltinModule } = require('internal/bootstrap/realm');
2828
const {
2929
realpathSync,
3030
statSync,

lib/internal/modules/helpers.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const {
1818
ERR_MANIFEST_DEPENDENCY_MISSING,
1919
ERR_UNKNOWN_BUILTIN_MODULE,
2020
} = require('internal/errors').codes;
21-
const { BuiltinModule } = require('internal/bootstrap/loaders');
21+
const { BuiltinModule } = require('internal/bootstrap/realm');
2222

2323
const { validateString } = require('internal/validators');
2424
const path = require('path');

lib/internal/process/pre_execution.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ function initializeReport() {
339339
function setupDebugEnv() {
340340
require('internal/util/debuglog').initializeDebugEnv(process.env.NODE_DEBUG);
341341
if (getOptionValue('--expose-internals')) {
342-
require('internal/bootstrap/loaders').BuiltinModule.exposeInternals();
342+
require('internal/bootstrap/realm').BuiltinModule.exposeInternals();
343343
}
344344
}
345345

lib/internal/util/inspect.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ const {
151151

152152
const assert = require('internal/assert');
153153

154-
const { BuiltinModule } = require('internal/bootstrap/loaders');
154+
const { BuiltinModule } = require('internal/bootstrap/realm');
155155
const {
156156
validateObject,
157157
validateString,

lib/repl.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ const {
9797
globalThis,
9898
} = primordials;
9999

100-
const { BuiltinModule } = require('internal/bootstrap/loaders');
100+
const { BuiltinModule } = require('internal/bootstrap/realm');
101101
const {
102102
makeRequireFunction,
103103
addBuiltinLibsToObject,

src/api/environment.cc

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,18 @@ MaybeLocal<Value> PrepareStackTraceCallback(Local<Context> context,
6565
if (env == nullptr) {
6666
return exception->ToString(context).FromMaybe(Local<Value>());
6767
}
68-
Local<Function> prepare = env->prepare_stack_trace_callback();
68+
Realm* realm = Realm::GetCurrent(context);
69+
Local<Function> prepare;
70+
if (realm != nullptr) {
71+
// If we are in a Realm, call the realm specific prepareStackTrace callback
72+
// to avoid passing the JS objects (the exception and trace) across the
73+
// realm boundary with the `Error.prepareStackTrace` override.
74+
prepare = realm->prepare_stack_trace_callback();
75+
} else {
76+
// The context is created with ContextifyContext, call the principal
77+
// realm's prepareStackTrace callback.
78+
prepare = env->principal_realm()->prepare_stack_trace_callback();
79+
}
6980
if (prepare.IsEmpty()) {
7081
return exception->ToString(context).FromMaybe(Local<Value>());
7182
}

src/node_builtins.cc

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -363,9 +363,9 @@ MaybeLocal<Function> BuiltinLoader::LookupAndCompile(Local<Context> context,
363363
std::vector<Local<String>> parameters;
364364
Isolate* isolate = context->GetIsolate();
365365
// Detects parameters of the scripts based on module ids.
366-
// internal/bootstrap/loaders: process, getLinkedBinding,
367-
// getInternalBinding, primordials
368-
if (strcmp(id, "internal/bootstrap/loaders") == 0) {
366+
// internal/bootstrap/realm: process, getLinkedBinding,
367+
// getInternalBinding, primordials
368+
if (strcmp(id, "internal/bootstrap/realm") == 0) {
369369
parameters = {
370370
FIXED_ONE_BYTE_STRING(isolate, "process"),
371371
FIXED_ONE_BYTE_STRING(isolate, "getLinkedBinding"),
@@ -427,9 +427,9 @@ MaybeLocal<Value> BuiltinLoader::CompileAndCall(Local<Context> context,
427427
// BuiltinLoader::LookupAndCompile().
428428
std::vector<Local<Value>> arguments;
429429
// Detects parameters of the scripts based on module ids.
430-
// internal/bootstrap/loaders: process, getLinkedBinding,
431-
// getInternalBinding, primordials
432-
if (strcmp(id, "internal/bootstrap/loaders") == 0) {
430+
// internal/bootstrap/realm: process, getLinkedBinding,
431+
// getInternalBinding, primordials
432+
if (strcmp(id, "internal/bootstrap/realm") == 0) {
433433
Local<Value> get_linked_binding;
434434
Local<Value> get_internal_binding;
435435
if (!NewFunctionTemplate(isolate, binding::GetLinkedBinding)

src/node_errors.cc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -954,9 +954,9 @@ void PerIsolateMessageListener(Local<Message> message, Local<Value> error) {
954954
}
955955

956956
void SetPrepareStackTraceCallback(const FunctionCallbackInfo<Value>& args) {
957-
Environment* env = Environment::GetCurrent(args);
957+
Realm* realm = Realm::GetCurrent(args);
958958
CHECK(args[0]->IsFunction());
959-
env->set_prepare_stack_trace_callback(args[0].As<Function>());
959+
realm->set_prepare_stack_trace_callback(args[0].As<Function>());
960960
}
961961

962962
static void SetSourceMapsEnabled(const FunctionCallbackInfo<Value>& args) {
@@ -981,11 +981,11 @@ static void SetMaybeCacheGeneratedSourceMap(
981981

982982
static void SetEnhanceStackForFatalException(
983983
const FunctionCallbackInfo<Value>& args) {
984-
Environment* env = Environment::GetCurrent(args);
984+
Realm* realm = Realm::GetCurrent(args);
985985
CHECK(args[0]->IsFunction());
986986
CHECK(args[1]->IsFunction());
987-
env->set_enhance_fatal_stack_before_inspector(args[0].As<Function>());
988-
env->set_enhance_fatal_stack_after_inspector(args[1].As<Function>());
987+
realm->set_enhance_fatal_stack_before_inspector(args[0].As<Function>());
988+
realm->set_enhance_fatal_stack_after_inspector(args[1].As<Function>());
989989
}
990990

991991
// Side effect-free stringification that will never throw exceptions.

src/node_realm.cc

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -183,18 +183,14 @@ MaybeLocal<Value> Realm::ExecuteBootstrapper(const char* id) {
183183
}
184184

185185
MaybeLocal<Value> Realm::BootstrapNode() {
186-
EscapableHandleScope scope(isolate_);
187-
188-
MaybeLocal<Value> result = ExecuteBootstrapper("internal/bootstrap/node");
186+
HandleScope scope(isolate_);
189187

190-
if (result.IsEmpty()) {
188+
if (ExecuteBootstrapper("internal/bootstrap/node").IsEmpty()) {
191189
return MaybeLocal<Value>();
192190
}
193191

194192
if (!env_->no_browser_globals()) {
195-
result = ExecuteBootstrapper("internal/bootstrap/browser");
196-
197-
if (result.IsEmpty()) {
193+
if (ExecuteBootstrapper("internal/bootstrap/browser").IsEmpty()) {
198194
return MaybeLocal<Value>();
199195
}
200196
}
@@ -203,19 +199,15 @@ MaybeLocal<Value> Realm::BootstrapNode() {
203199
auto thread_switch_id =
204200
env_->is_main_thread() ? "internal/bootstrap/switches/is_main_thread"
205201
: "internal/bootstrap/switches/is_not_main_thread";
206-
result = ExecuteBootstrapper(thread_switch_id);
207-
208-
if (result.IsEmpty()) {
202+
if (ExecuteBootstrapper(thread_switch_id).IsEmpty()) {
209203
return MaybeLocal<Value>();
210204
}
211205

212206
auto process_state_switch_id =
213207
env_->owns_process_state()
214208
? "internal/bootstrap/switches/does_own_process_state"
215209
: "internal/bootstrap/switches/does_not_own_process_state";
216-
result = ExecuteBootstrapper(process_state_switch_id);
217-
218-
if (result.IsEmpty()) {
210+
if (ExecuteBootstrapper(process_state_switch_id).IsEmpty()) {
219211
return MaybeLocal<Value>();
220212
}
221213

@@ -227,7 +219,7 @@ MaybeLocal<Value> Realm::BootstrapNode() {
227219
return MaybeLocal<Value>();
228220
}
229221

230-
return scope.EscapeMaybe(result);
222+
return v8::True(isolate_);
231223
}
232224

233225
MaybeLocal<Value> Realm::RunBootstrapping() {
@@ -236,7 +228,7 @@ MaybeLocal<Value> Realm::RunBootstrapping() {
236228
CHECK(!has_run_bootstrapping_code());
237229

238230
Local<Value> result;
239-
if (!ExecuteBootstrapper("internal/bootstrap/loaders").ToLocal(&result)) {
231+
if (!ExecuteBootstrapper("internal/bootstrap/realm").ToLocal(&result)) {
240232
return MaybeLocal<Value>();
241233
}
242234

test/es-module/test-loaders-hidden-from-users.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,16 @@ const assert = require('assert');
77

88
assert.throws(
99
() => {
10-
require('internal/bootstrap/loaders');
10+
require('internal/bootstrap/realm');
1111
}, {
1212
code: 'MODULE_NOT_FOUND',
13-
message: /Cannot find module 'internal\/bootstrap\/loaders'/
13+
message: /Cannot find module 'internal\/bootstrap\/realm'/
1414
}
1515
);
1616

1717
assert.throws(
1818
() => {
19-
const source = 'module.exports = require("internal/bootstrap/loaders")';
19+
const source = 'module.exports = require("internal/bootstrap/realm")';
2020
const { internalBinding } = require('internal/test/binding');
2121
internalBinding('natives').owo = source;
2222
require('owo');

test/parallel/test-inspector-inspect-brk-node.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ async function runTest() {
1616
await session.waitForNotification((notification) => {
1717
// The main assertion here is that we do hit the loader script first.
1818
return notification.method === 'Debugger.scriptParsed' &&
19-
notification.params.url === 'node:internal/bootstrap/loaders';
19+
notification.params.url === 'node:internal/bootstrap/realm';
2020
});
2121

2222
await session.waitForNotification('Debugger.paused');

0 commit comments

Comments
 (0)