mirror of
https://github.com/zebrajr/node.git
synced 2026-01-15 12:15:26 +00:00
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: https://github.com/nodejs/node/pull/47107 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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.
|
||||
//
|
||||
@@ -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
|
||||
@@ -52,8 +53,6 @@
|
||||
// passed by `BuiltinLoader::CompileAndCall()`.
|
||||
/* global process, require, internalBinding, primordials */
|
||||
|
||||
setupPrepareStackTrace();
|
||||
|
||||
const {
|
||||
FunctionPrototypeCall,
|
||||
JSONParse,
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
@@ -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:
|
||||
@@ -178,7 +183,7 @@ let internalBinding;
|
||||
};
|
||||
}
|
||||
|
||||
const loaderId = 'internal/bootstrap/loaders';
|
||||
const selfId = 'internal/bootstrap/realm';
|
||||
const {
|
||||
builtinIds,
|
||||
compileFunction,
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -354,7 +359,7 @@ const loaderExports = {
|
||||
};
|
||||
|
||||
function requireBuiltin(id) {
|
||||
if (id === loaderId) {
|
||||
if (id === selfId) {
|
||||
return loaderExports;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
@@ -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,
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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.
|
||||
//
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -96,7 +96,7 @@ const {
|
||||
globalThis,
|
||||
} = primordials;
|
||||
|
||||
const { BuiltinModule } = require('internal/bootstrap/loaders');
|
||||
const { BuiltinModule } = require('internal/bootstrap/realm');
|
||||
const {
|
||||
makeRequireFunction,
|
||||
addBuiltinLibsToObject,
|
||||
|
||||
@@ -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>());
|
||||
}
|
||||
|
||||
@@ -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"),
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
@@ -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.
|
||||
|
||||
@@ -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>();
|
||||
}
|
||||
@@ -306,11 +306,9 @@ void PrincipalRealm::MemoryInfo(MemoryTracker* tracker) const {
|
||||
}
|
||||
|
||||
MaybeLocal<Value> PrincipalRealm::BootstrapRealm() {
|
||||
EscapableHandleScope scope(isolate_);
|
||||
HandleScope scope(isolate_);
|
||||
|
||||
MaybeLocal<Value> result = ExecuteBootstrapper("internal/bootstrap/node");
|
||||
|
||||
if (result.IsEmpty()) {
|
||||
if (ExecuteBootstrapper("internal/bootstrap/node").IsEmpty()) {
|
||||
return MaybeLocal<Value>();
|
||||
}
|
||||
|
||||
@@ -327,9 +325,7 @@ 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>();
|
||||
}
|
||||
|
||||
@@ -337,9 +333,7 @@ MaybeLocal<Value> PrincipalRealm::BootstrapRealm() {
|
||||
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>();
|
||||
}
|
||||
|
||||
@@ -351,7 +345,7 @@ MaybeLocal<Value> PrincipalRealm::BootstrapRealm() {
|
||||
return MaybeLocal<Value>();
|
||||
}
|
||||
|
||||
return scope.EscapeMaybe(result);
|
||||
return v8::True(isolate_);
|
||||
}
|
||||
|
||||
} // namespace node
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
#include "node_shadow_realm.h"
|
||||
#include "env-inl.h"
|
||||
#include "node_errors.h"
|
||||
|
||||
namespace node {
|
||||
namespace shadow_realm {
|
||||
using v8::Context;
|
||||
using v8::EscapableHandleScope;
|
||||
using v8::HandleScope;
|
||||
using v8::Local;
|
||||
using v8::MaybeLocal;
|
||||
using v8::Value;
|
||||
|
||||
using TryCatchScope = node::errors::TryCatchScope;
|
||||
|
||||
// static
|
||||
ShadowRealm* ShadowRealm::New(Environment* env) {
|
||||
ShadowRealm* realm = new ShadowRealm(env);
|
||||
env->AssignToContext(realm->context(), realm, ContextInfo(""));
|
||||
|
||||
// We do not expect the realm bootstrapping to throw any
|
||||
// exceptions. If it does, exit the current Node.js instance.
|
||||
TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
|
||||
if (realm->RunBootstrapping().IsEmpty()) {
|
||||
delete realm;
|
||||
return nullptr;
|
||||
@@ -91,21 +96,19 @@ PER_REALM_STRONG_PERSISTENT_VALUES(V)
|
||||
#undef V
|
||||
|
||||
v8::MaybeLocal<v8::Value> ShadowRealm::BootstrapRealm() {
|
||||
EscapableHandleScope scope(isolate_);
|
||||
MaybeLocal<Value> result = v8::True(isolate_);
|
||||
HandleScope scope(isolate_);
|
||||
|
||||
// Skip "internal/bootstrap/node" as it installs node globals and per-isolate
|
||||
// callbacks like PrepareStackTraceCallback.
|
||||
// callbacks.
|
||||
|
||||
if (!env_->no_browser_globals()) {
|
||||
result = ExecuteBootstrapper("internal/bootstrap/web/exposed-wildcard");
|
||||
|
||||
if (result.IsEmpty()) {
|
||||
if (ExecuteBootstrapper("internal/bootstrap/web/exposed-wildcard")
|
||||
.IsEmpty()) {
|
||||
return MaybeLocal<Value>();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return v8::True(isolate_);
|
||||
}
|
||||
|
||||
} // namespace shadow_realm
|
||||
|
||||
@@ -7,16 +7,16 @@ const assert = require('assert');
|
||||
|
||||
assert.throws(
|
||||
() => {
|
||||
require('internal/bootstrap/loaders');
|
||||
require('internal/bootstrap/realm');
|
||||
}, {
|
||||
code: 'MODULE_NOT_FOUND',
|
||||
message: /Cannot find module 'internal\/bootstrap\/loaders'/
|
||||
message: /Cannot find module 'internal\/bootstrap\/realm'/
|
||||
}
|
||||
);
|
||||
|
||||
assert.throws(
|
||||
() => {
|
||||
const source = 'module.exports = require("internal/bootstrap/loaders")';
|
||||
const source = 'module.exports = require("internal/bootstrap/realm")';
|
||||
const { internalBinding } = require('internal/test/binding');
|
||||
internalBinding('natives').owo = source;
|
||||
require('owo');
|
||||
|
||||
@@ -16,7 +16,7 @@ async function runTest() {
|
||||
await session.waitForNotification((notification) => {
|
||||
// The main assertion here is that we do hit the loader script first.
|
||||
return notification.method === 'Debugger.scriptParsed' &&
|
||||
notification.params.url === 'node:internal/bootstrap/loaders';
|
||||
notification.params.url === 'node:internal/bootstrap/realm';
|
||||
});
|
||||
|
||||
await session.waitForNotification('Debugger.paused');
|
||||
|
||||
53
test/parallel/test-shadow-realm-prepare-stack-trace.js
Normal file
53
test/parallel/test-shadow-realm-prepare-stack-trace.js
Normal file
@@ -0,0 +1,53 @@
|
||||
// Flags: --experimental-shadow-realm
|
||||
'use strict';
|
||||
|
||||
require('../common');
|
||||
const assert = require('assert');
|
||||
|
||||
let principalRealmPrepareStackTraceCalled = false;
|
||||
Error.prepareStackTrace = (error, trace) => {
|
||||
principalRealmPrepareStackTraceCalled = true;
|
||||
return `${String(error)}\n at ${trace.join('\n at ')}`;
|
||||
};
|
||||
|
||||
{
|
||||
// Validates inner Error.prepareStackTrace can not leak into the outer realm.
|
||||
const shadowRealm = new ShadowRealm();
|
||||
|
||||
const stack = shadowRealm.evaluate(`
|
||||
Error.prepareStackTrace = (error, trace) => {
|
||||
globalThis.leaked = 'inner';
|
||||
return 'from shadow realm';
|
||||
};
|
||||
|
||||
try {
|
||||
throw new Error('boom');
|
||||
} catch (e) {
|
||||
e.stack;
|
||||
}
|
||||
`);
|
||||
assert.ok(!principalRealmPrepareStackTraceCalled);
|
||||
assert.strictEqual(stack, 'from shadow realm');
|
||||
assert.strictEqual('leaked' in globalThis, false);
|
||||
}
|
||||
|
||||
{
|
||||
// Validates stacks can be generated in the ShadowRealm.
|
||||
const shadowRealm = new ShadowRealm();
|
||||
|
||||
const stack = shadowRealm.evaluate(`
|
||||
function myFunc() {
|
||||
throw new Error('boom');
|
||||
}
|
||||
|
||||
try {
|
||||
myFunc();
|
||||
} catch (e) {
|
||||
e.stack;
|
||||
}
|
||||
`);
|
||||
assert.ok(!principalRealmPrepareStackTraceCalled);
|
||||
const lines = stack.split('\n');
|
||||
assert.strictEqual(lines[0], 'Error: boom');
|
||||
assert.match(lines[1], /^ {4}at myFunc \(.*\)/);
|
||||
}
|
||||
Reference in New Issue
Block a user