Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

src: bootstrap prepare stack trace callback in shadow realm #47107

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
/doc/api/module.md @nodejs/modules @nodejs/loaders
/doc/api/modules.md @nodejs/modules @nodejs/loaders
/doc/api/packages.md @nodejs/modules @nodejs/loaders
/lib/internal/bootstrap/loaders.js @nodejs/modules @nodejs/loaders
/lib/internal/bootstrap/realm.js @nodejs/modules @nodejs/loaders
/lib/internal/modules/* @nodejs/modules @nodejs/loaders
/lib/internal/process/esm_loader.js @nodejs/modules @nodejs/loaders
/lib/internal/process/execution.js @nodejs/modules @nodejs/loaders
Expand Down
2 changes: 1 addition & 1 deletion lib/assert.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ const { openSync, closeSync, readSync } = require('fs');
const { inspect } = require('internal/util/inspect');
const { isPromise, isRegExp } = require('internal/util/types');
const { EOL } = require('internal/constants');
const { BuiltinModule } = require('internal/bootstrap/loaders');
const { BuiltinModule } = require('internal/bootstrap/realm');
const { isError } = require('internal/util');

const errorCache = new SafeMap();
Expand Down
28 changes: 4 additions & 24 deletions lib/internal/bootstrap/node.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Hello, and welcome to hacking node.js!
//
// This file is invoked by `Realm::BootstrapNode()` in `src/node_realm.cc`,
// This file is invoked by `Realm::BootstrapRealm()` in `src/node_realm.cc`,
// and is responsible for setting up Node.js core before main scripts
// under `lib/internal/main/` are executed.
//
Expand Down Expand Up @@ -32,9 +32,10 @@
// `DOMException` class.
// - `lib/internal/per_context/messageport.js`: JS-side components of the
// `MessagePort` implementation.
// - `lib/internal/bootstrap/loaders.js`: this sets up internal binding and
// - `lib/internal/bootstrap/realm.js`: this sets up internal binding and
// module loaders, including `process.binding()`, `process._linkedBinding()`,
// `internalBinding()` and `BuiltinModule`.
// `internalBinding()` and `BuiltinModule`, and per-realm internal states
// and bindings, including `prepare_stack_trace_callback`.
//
// The initialization done in this script is included in both the main thread
// and the worker threads. After this, further initialization is done based
Expand All @@ -52,8 +53,6 @@
// passed by `BuiltinLoader::CompileAndCall()`.
/* global process, require, internalBinding, primordials */

setupPrepareStackTrace();

const {
FunctionPrototypeCall,
JSONParse,
Expand Down Expand Up @@ -336,25 +335,6 @@ process.emitWarning = emitWarning;
// Note: only after this point are the timers effective
}

function setupPrepareStackTrace() {
const {
setEnhanceStackForFatalException,
setPrepareStackTraceCallback,
} = internalBinding('errors');
const {
prepareStackTrace,
fatalExceptionStackEnhancers: {
beforeInspector,
afterInspector,
},
} = require('internal/errors');
// Tell our PrepareStackTraceCallback passed to the V8 API
// to call prepareStackTrace().
setPrepareStackTraceCallback(prepareStackTrace);
// Set the function used to enhance the error stack for printing
setEnhanceStackForFatalException(beforeInspector, afterInspector);
}

function setupProcessObject() {
const EventEmitter = require('events');
const origProcProto = ObjectGetPrototypeOf(process);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
// This file is executed in every realm that is created by Node.js, including
// the context of main thread, worker threads, and ShadowRealms.
// Only per-realm internal states and bindings should be bootstrapped in this
// file and no globals should be exposed to the user code.
//
// This file creates the internal module & binding loaders used by built-in
// modules. In contrast, user land modules are loaded using
// lib/internal/modules/cjs/loader.js (CommonJS Modules) or
Expand Down Expand Up @@ -30,7 +35,7 @@
// so they can be loaded faster without the cost of I/O. This class makes the
// lib/internal/*, deps/internal/* modules and internalBinding() available by
// default to core modules, and lets the core modules require itself via
// require('internal/bootstrap/loaders') even when this file is not written in
// require('internal/bootstrap/realm') even when this file is not written in
// CommonJS style.
//
// Other objects:
Expand Down Expand Up @@ -178,7 +183,7 @@ let internalBinding;
};
}

const loaderId = 'internal/bootstrap/loaders';
const selfId = 'internal/bootstrap/realm';
const {
builtinIds,
compileFunction,
Expand Down Expand Up @@ -235,7 +240,7 @@ class BuiltinModule {
static exposeInternals() {
for (const { 0: id, 1: mod } of BuiltinModule.map) {
// Do not expose this to user land even with --expose-internals.
if (id !== loaderId) {
if (id !== selfId) {
mod.canBeRequiredByUsers = true;
}
}
Expand Down Expand Up @@ -354,7 +359,7 @@ const loaderExports = {
};

function requireBuiltin(id) {
if (id === loaderId) {
if (id === selfId) {
return loaderExports;
}

Expand All @@ -374,5 +379,27 @@ function requireWithFallbackInDeps(request) {
return requireBuiltin(request);
}

function setupPrepareStackTrace() {
const {
setEnhanceStackForFatalException,
setPrepareStackTraceCallback,
} = internalBinding('errors');
const {
prepareStackTrace,
fatalExceptionStackEnhancers: {
beforeInspector,
afterInspector,
},
} = requireBuiltin('internal/errors');
// Tell our PrepareStackTraceCallback passed to the V8 API
// to call prepareStackTrace().
setPrepareStackTraceCallback(prepareStackTrace);
// Set the function used to enhance the error stack for printing
setEnhanceStackForFatalException(beforeInspector, afterInspector);
}

// Store the internal loaders in C++.
setInternalLoaders(internalBinding, requireBuiltin);

// Setup per-realm bindings.
setupPrepareStackTrace();
2 changes: 1 addition & 1 deletion lib/internal/main/mksnapshot.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const {
} = primordials;

const binding = internalBinding('mksnapshot');
const { BuiltinModule } = require('internal/bootstrap/loaders');
const { BuiltinModule } = require('internal/bootstrap/realm');
const {
getEmbedderEntryFunction,
compileSerializeMain,
Expand Down
2 changes: 1 addition & 1 deletion lib/internal/modules/cjs/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ module.exports = {
initializeCJS,
};

const { BuiltinModule } = require('internal/bootstrap/loaders');
const { BuiltinModule } = require('internal/bootstrap/realm');
const {
maybeCacheSourceMap,
} = require('internal/source_map/source_map_cache');
Expand Down
2 changes: 1 addition & 1 deletion lib/internal/modules/esm/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ class Hooks {
filename: '<preload>',
},
);
const { BuiltinModule } = require('internal/bootstrap/loaders');
const { BuiltinModule } = require('internal/bootstrap/realm');
// We only allow replacing the importMetaInitializer during preload;
// after preload is finished, we disable the ability to replace it.
//
Expand Down
2 changes: 1 addition & 1 deletion lib/internal/modules/esm/resolve.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const {
StringPrototypeStartsWith,
} = primordials;
const internalFS = require('internal/fs/utils');
const { BuiltinModule } = require('internal/bootstrap/loaders');
const { BuiltinModule } = require('internal/bootstrap/realm');
const {
realpathSync,
statSync,
Expand Down
2 changes: 1 addition & 1 deletion lib/internal/modules/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const {
ERR_MANIFEST_DEPENDENCY_MISSING,
ERR_UNKNOWN_BUILTIN_MODULE,
} = require('internal/errors').codes;
const { BuiltinModule } = require('internal/bootstrap/loaders');
const { BuiltinModule } = require('internal/bootstrap/realm');

const { validateString } = require('internal/validators');
const path = require('path');
Expand Down
2 changes: 1 addition & 1 deletion lib/internal/process/pre_execution.js
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ function initializeReport() {
function setupDebugEnv() {
require('internal/util/debuglog').initializeDebugEnv(process.env.NODE_DEBUG);
if (getOptionValue('--expose-internals')) {
require('internal/bootstrap/loaders').BuiltinModule.exposeInternals();
require('internal/bootstrap/realm').BuiltinModule.exposeInternals();
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/internal/util/inspect.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ const {

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

const { BuiltinModule } = require('internal/bootstrap/loaders');
const { BuiltinModule } = require('internal/bootstrap/realm');
const {
validateObject,
validateString,
Expand Down
2 changes: 1 addition & 1 deletion lib/repl.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ const {
globalThis,
} = primordials;

const { BuiltinModule } = require('internal/bootstrap/loaders');
const { BuiltinModule } = require('internal/bootstrap/realm');
const {
makeRequireFunction,
addBuiltinLibsToObject,
Expand Down
21 changes: 11 additions & 10 deletions src/api/environment.cc
Original file line number Diff line number Diff line change
Expand Up @@ -67,17 +67,18 @@ MaybeLocal<Value> PrepareStackTraceCallback(Local<Context> context,
if (env == nullptr) {
return exception->ToString(context).FromMaybe(Local<Value>());
}
// TODO(legendecas): Per-realm prepareStackTrace callback.
// If we are in a Realm that is not the principal Realm (e.g. ShadowRealm),
// skip the prepareStackTrace callback to avoid passing the JS objects (
// the exception and trace) across the realm boundary with the
// `Error.prepareStackTrace` override.
Realm* current_realm = Realm::GetCurrent(context);
if (current_realm != nullptr &&
current_realm->kind() != Realm::Kind::kPrincipal) {
return exception->ToString(context).FromMaybe(Local<Value>());
Realm* realm = Realm::GetCurrent(context);
Local<Function> prepare;
if (realm != nullptr) {
// If we are in a Realm, call the realm specific prepareStackTrace callback
// to avoid passing the JS objects (the exception and trace) across the
// realm boundary with the `Error.prepareStackTrace` override.
prepare = realm->prepare_stack_trace_callback();
} else {
// The context is created with ContextifyContext, call the principal
// realm's prepareStackTrace callback.
prepare = env->principal_realm()->prepare_stack_trace_callback();
}
Local<Function> prepare = env->prepare_stack_trace_callback();
if (prepare.IsEmpty()) {
return exception->ToString(context).FromMaybe(Local<Value>());
}
Expand Down
12 changes: 6 additions & 6 deletions src/node_builtins.cc
Original file line number Diff line number Diff line change
Expand Up @@ -356,9 +356,9 @@ MaybeLocal<Function> BuiltinLoader::LookupAndCompile(Local<Context> context,
std::vector<Local<String>> parameters;
Isolate* isolate = context->GetIsolate();
// Detects parameters of the scripts based on module ids.
// internal/bootstrap/loaders: process, getLinkedBinding,
// getInternalBinding, primordials
if (strcmp(id, "internal/bootstrap/loaders") == 0) {
// internal/bootstrap/realm: process, getLinkedBinding,
// getInternalBinding, primordials
if (strcmp(id, "internal/bootstrap/realm") == 0) {
parameters = {
FIXED_ONE_BYTE_STRING(isolate, "process"),
FIXED_ONE_BYTE_STRING(isolate, "getLinkedBinding"),
Expand Down Expand Up @@ -414,9 +414,9 @@ MaybeLocal<Value> BuiltinLoader::CompileAndCall(Local<Context> context,
// BuiltinLoader::LookupAndCompile().
std::vector<Local<Value>> arguments;
// Detects parameters of the scripts based on module ids.
// internal/bootstrap/loaders: process, getLinkedBinding,
// getInternalBinding, primordials
if (strcmp(id, "internal/bootstrap/loaders") == 0) {
// internal/bootstrap/realm: process, getLinkedBinding,
// getInternalBinding, primordials
if (strcmp(id, "internal/bootstrap/realm") == 0) {
Local<Value> get_linked_binding;
Local<Value> get_internal_binding;
if (!NewFunctionTemplate(isolate, binding::GetLinkedBinding)
Expand Down
10 changes: 5 additions & 5 deletions src/node_errors.cc
Original file line number Diff line number Diff line change
Expand Up @@ -960,9 +960,9 @@ void PerIsolateMessageListener(Local<Message> message, Local<Value> error) {
}

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

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

static void SetEnhanceStackForFatalException(
const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
Realm* realm = Realm::GetCurrent(args);
CHECK(args[0]->IsFunction());
CHECK(args[1]->IsFunction());
env->set_enhance_fatal_stack_before_inspector(args[0].As<Function>());
env->set_enhance_fatal_stack_after_inspector(args[1].As<Function>());
realm->set_enhance_fatal_stack_before_inspector(args[0].As<Function>());
realm->set_enhance_fatal_stack_after_inspector(args[1].As<Function>());
}

// Side effect-free stringification that will never throw exceptions.
Expand Down
18 changes: 6 additions & 12 deletions src/node_realm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ MaybeLocal<Value> Realm::RunBootstrapping() {
CHECK(!has_run_bootstrapping_code());

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

MaybeLocal<Value> PrincipalRealm::BootstrapRealm() {
EscapableHandleScope scope(isolate_);

MaybeLocal<Value> result = ExecuteBootstrapper("internal/bootstrap/node");
HandleScope scope(isolate_);

if (result.IsEmpty()) {
if (ExecuteBootstrapper("internal/bootstrap/node").IsEmpty()) {
return MaybeLocal<Value>();
}

Expand All @@ -327,19 +325,15 @@ MaybeLocal<Value> PrincipalRealm::BootstrapRealm() {
auto thread_switch_id =
env_->is_main_thread() ? "internal/bootstrap/switches/is_main_thread"
: "internal/bootstrap/switches/is_not_main_thread";
result = ExecuteBootstrapper(thread_switch_id);

if (result.IsEmpty()) {
if (ExecuteBootstrapper(thread_switch_id).IsEmpty()) {
return MaybeLocal<Value>();
}

auto process_state_switch_id =
env_->owns_process_state()
? "internal/bootstrap/switches/does_own_process_state"
: "internal/bootstrap/switches/does_not_own_process_state";
result = ExecuteBootstrapper(process_state_switch_id);

if (result.IsEmpty()) {
if (ExecuteBootstrapper(process_state_switch_id).IsEmpty()) {
return MaybeLocal<Value>();
}

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

return scope.EscapeMaybe(result);
return v8::True(isolate_);
}

} // namespace node