Skip to content

Commit 698508a

Browse files
legendecasRafaelGSS
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 1b9e573 commit 698508a

20 files changed

+141
-83
lines changed

.github/CODEOWNERS

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@
8484
/doc/api/module.md @nodejs/modules @nodejs/loaders
8585
/doc/api/modules.md @nodejs/modules @nodejs/loaders
8686
/doc/api/packages.md @nodejs/modules @nodejs/loaders
87-
/lib/internal/bootstrap/loaders.js @nodejs/modules @nodejs/loaders
87+
/lib/internal/bootstrap/realm.js @nodejs/modules @nodejs/loaders
8888
/lib/internal/modules/* @nodejs/modules @nodejs/loaders
8989
/lib/internal/process/esm_loader.js @nodejs/modules @nodejs/loaders
9090
/lib/internal/process/execution.js @nodejs/modules @nodejs/loaders

lib/assert.js

+1-1
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

+4-24
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,
@@ -336,25 +335,6 @@ process.emitWarning = emitWarning;
336335
// Note: only after this point are the timers effective
337336
}
338337

339-
function setupPrepareStackTrace() {
340-
const {
341-
setEnhanceStackForFatalException,
342-
setPrepareStackTraceCallback,
343-
} = internalBinding('errors');
344-
const {
345-
prepareStackTrace,
346-
fatalExceptionStackEnhancers: {
347-
beforeInspector,
348-
afterInspector,
349-
},
350-
} = require('internal/errors');
351-
// Tell our PrepareStackTraceCallback passed to the V8 API
352-
// to call prepareStackTrace().
353-
setPrepareStackTraceCallback(prepareStackTrace);
354-
// Set the function used to enhance the error stack for printing
355-
setEnhanceStackForFatalException(beforeInspector, afterInspector);
356-
}
357-
358338
function setupProcessObject() {
359339
const EventEmitter = require('events');
360340
const origProcProto = ObjectGetPrototypeOf(process);

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

+31-4
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:
@@ -178,7 +183,7 @@ let internalBinding;
178183
};
179184
}
180185

181-
const loaderId = 'internal/bootstrap/loaders';
186+
const selfId = 'internal/bootstrap/realm';
182187
const {
183188
builtinIds,
184189
compileFunction,
@@ -235,7 +240,7 @@ class BuiltinModule {
235240
static exposeInternals() {
236241
for (const { 0: id, 1: mod } of BuiltinModule.map) {
237242
// Do not expose this to user land even with --expose-internals.
238-
if (id !== loaderId) {
243+
if (id !== selfId) {
239244
mod.canBeRequiredByUsers = true;
240245
}
241246
}
@@ -354,7 +359,7 @@ const loaderExports = {
354359
};
355360

356361
function requireBuiltin(id) {
357-
if (id === loaderId) {
362+
if (id === selfId) {
358363
return loaderExports;
359364
}
360365

@@ -374,5 +379,27 @@ function requireWithFallbackInDeps(request) {
374379
return requireBuiltin(request);
375380
}
376381

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

lib/internal/main/mksnapshot.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const {
1010
} = primordials;
1111

1212
const binding = internalBinding('mksnapshot');
13-
const { BuiltinModule } = require('internal/bootstrap/loaders');
13+
const { BuiltinModule } = require('internal/bootstrap/realm');
1414
const {
1515
getEmbedderEntryFunction,
1616
compileSerializeMain,

lib/internal/modules/cjs/loader.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ module.exports = {
7575
initializeCJS,
7676
};
7777

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

lib/internal/modules/esm/hooks.js

+1-1
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

+1-1
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

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const {
1717
ERR_MANIFEST_DEPENDENCY_MISSING,
1818
ERR_UNKNOWN_BUILTIN_MODULE,
1919
} = require('internal/errors').codes;
20-
const { BuiltinModule } = require('internal/bootstrap/loaders');
20+
const { BuiltinModule } = require('internal/bootstrap/realm');
2121

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

lib/internal/process/pre_execution.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ function initializeReport() {
351351
function setupDebugEnv() {
352352
require('internal/util/debuglog').initializeDebugEnv(process.env.NODE_DEBUG);
353353
if (getOptionValue('--expose-internals')) {
354-
require('internal/bootstrap/loaders').BuiltinModule.exposeInternals();
354+
require('internal/bootstrap/realm').BuiltinModule.exposeInternals();
355355
}
356356
}
357357

lib/internal/util/inspect.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ const {
150150

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

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

lib/repl.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ const {
9696
globalThis,
9797
} = primordials;
9898

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

src/api/environment.cc

+11-10
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,18 @@ MaybeLocal<Value> PrepareStackTraceCallback(Local<Context> context,
6767
if (env == nullptr) {
6868
return exception->ToString(context).FromMaybe(Local<Value>());
6969
}
70-
// TODO(legendecas): Per-realm prepareStackTrace callback.
71-
// If we are in a Realm that is not the principal Realm (e.g. ShadowRealm),
72-
// skip the prepareStackTrace callback to avoid passing the JS objects (
73-
// the exception and trace) across the realm boundary with the
74-
// `Error.prepareStackTrace` override.
75-
Realm* current_realm = Realm::GetCurrent(context);
76-
if (current_realm != nullptr &&
77-
current_realm->kind() != Realm::Kind::kPrincipal) {
78-
return exception->ToString(context).FromMaybe(Local<Value>());
70+
Realm* realm = Realm::GetCurrent(context);
71+
Local<Function> prepare;
72+
if (realm != nullptr) {
73+
// If we are in a Realm, call the realm specific prepareStackTrace callback
74+
// to avoid passing the JS objects (the exception and trace) across the
75+
// realm boundary with the `Error.prepareStackTrace` override.
76+
prepare = realm->prepare_stack_trace_callback();
77+
} else {
78+
// The context is created with ContextifyContext, call the principal
79+
// realm's prepareStackTrace callback.
80+
prepare = env->principal_realm()->prepare_stack_trace_callback();
7981
}
80-
Local<Function> prepare = env->prepare_stack_trace_callback();
8182
if (prepare.IsEmpty()) {
8283
return exception->ToString(context).FromMaybe(Local<Value>());
8384
}

src/node_builtins.cc

+6-6
Original file line numberDiff line numberDiff line change
@@ -356,9 +356,9 @@ MaybeLocal<Function> BuiltinLoader::LookupAndCompile(Local<Context> context,
356356
std::vector<Local<String>> parameters;
357357
Isolate* isolate = context->GetIsolate();
358358
// Detects parameters of the scripts based on module ids.
359-
// internal/bootstrap/loaders: process, getLinkedBinding,
360-
// getInternalBinding, primordials
361-
if (strcmp(id, "internal/bootstrap/loaders") == 0) {
359+
// internal/bootstrap/realm: process, getLinkedBinding,
360+
// getInternalBinding, primordials
361+
if (strcmp(id, "internal/bootstrap/realm") == 0) {
362362
parameters = {
363363
FIXED_ONE_BYTE_STRING(isolate, "process"),
364364
FIXED_ONE_BYTE_STRING(isolate, "getLinkedBinding"),
@@ -414,9 +414,9 @@ MaybeLocal<Value> BuiltinLoader::CompileAndCall(Local<Context> context,
414414
// BuiltinLoader::LookupAndCompile().
415415
std::vector<Local<Value>> arguments;
416416
// Detects parameters of the scripts based on module ids.
417-
// internal/bootstrap/loaders: process, getLinkedBinding,
418-
// getInternalBinding, primordials
419-
if (strcmp(id, "internal/bootstrap/loaders") == 0) {
417+
// internal/bootstrap/realm: process, getLinkedBinding,
418+
// getInternalBinding, primordials
419+
if (strcmp(id, "internal/bootstrap/realm") == 0) {
420420
Local<Value> get_linked_binding;
421421
Local<Value> get_internal_binding;
422422
if (!NewFunctionTemplate(isolate, binding::GetLinkedBinding)

src/node_errors.cc

+5-5
Original file line numberDiff line numberDiff line change
@@ -960,9 +960,9 @@ void PerIsolateMessageListener(Local<Message> message, Local<Value> error) {
960960
}
961961

962962
void SetPrepareStackTraceCallback(const FunctionCallbackInfo<Value>& args) {
963-
Environment* env = Environment::GetCurrent(args);
963+
Realm* realm = Realm::GetCurrent(args);
964964
CHECK(args[0]->IsFunction());
965-
env->set_prepare_stack_trace_callback(args[0].As<Function>());
965+
realm->set_prepare_stack_trace_callback(args[0].As<Function>());
966966
}
967967

968968
static void SetSourceMapsEnabled(const FunctionCallbackInfo<Value>& args) {
@@ -987,11 +987,11 @@ static void SetMaybeCacheGeneratedSourceMap(
987987

988988
static void SetEnhanceStackForFatalException(
989989
const FunctionCallbackInfo<Value>& args) {
990-
Environment* env = Environment::GetCurrent(args);
990+
Realm* realm = Realm::GetCurrent(args);
991991
CHECK(args[0]->IsFunction());
992992
CHECK(args[1]->IsFunction());
993-
env->set_enhance_fatal_stack_before_inspector(args[0].As<Function>());
994-
env->set_enhance_fatal_stack_after_inspector(args[1].As<Function>());
993+
realm->set_enhance_fatal_stack_before_inspector(args[0].As<Function>());
994+
realm->set_enhance_fatal_stack_after_inspector(args[1].As<Function>());
995995
}
996996

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

src/node_realm.cc

+6-12
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ MaybeLocal<Value> Realm::RunBootstrapping() {
179179
CHECK(!has_run_bootstrapping_code());
180180

181181
Local<Value> result;
182-
if (!ExecuteBootstrapper("internal/bootstrap/loaders").ToLocal(&result) ||
182+
if (!ExecuteBootstrapper("internal/bootstrap/realm").ToLocal(&result) ||
183183
!BootstrapRealm().ToLocal(&result)) {
184184
return MaybeLocal<Value>();
185185
}
@@ -306,11 +306,9 @@ void PrincipalRealm::MemoryInfo(MemoryTracker* tracker) const {
306306
}
307307

308308
MaybeLocal<Value> PrincipalRealm::BootstrapRealm() {
309-
EscapableHandleScope scope(isolate_);
310-
311-
MaybeLocal<Value> result = ExecuteBootstrapper("internal/bootstrap/node");
309+
HandleScope scope(isolate_);
312310

313-
if (result.IsEmpty()) {
311+
if (ExecuteBootstrapper("internal/bootstrap/node").IsEmpty()) {
314312
return MaybeLocal<Value>();
315313
}
316314

@@ -327,19 +325,15 @@ MaybeLocal<Value> PrincipalRealm::BootstrapRealm() {
327325
auto thread_switch_id =
328326
env_->is_main_thread() ? "internal/bootstrap/switches/is_main_thread"
329327
: "internal/bootstrap/switches/is_not_main_thread";
330-
result = ExecuteBootstrapper(thread_switch_id);
331-
332-
if (result.IsEmpty()) {
328+
if (ExecuteBootstrapper(thread_switch_id).IsEmpty()) {
333329
return MaybeLocal<Value>();
334330
}
335331

336332
auto process_state_switch_id =
337333
env_->owns_process_state()
338334
? "internal/bootstrap/switches/does_own_process_state"
339335
: "internal/bootstrap/switches/does_not_own_process_state";
340-
result = ExecuteBootstrapper(process_state_switch_id);
341-
342-
if (result.IsEmpty()) {
336+
if (ExecuteBootstrapper(process_state_switch_id).IsEmpty()) {
343337
return MaybeLocal<Value>();
344338
}
345339

@@ -351,7 +345,7 @@ MaybeLocal<Value> PrincipalRealm::BootstrapRealm() {
351345
return MaybeLocal<Value>();
352346
}
353347

354-
return scope.EscapeMaybe(result);
348+
return v8::True(isolate_);
355349
}
356350

357351
} // namespace node

0 commit comments

Comments
 (0)