From 3697c19c805df5e355aa8db0a26dbb2892684932 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Wed, 11 Oct 2023 04:50:50 +0200 Subject: [PATCH] vm: use internal versions of compileFunction and Script Instead of using the public versions of the vm APIs internally, use the internal versions so that we can skip unnecessary argument validation. The public versions would need special care to the generation of host-defined options to hit the isolate compilation cache when imporModuleDynamically isn't used, while internally it's almost always used, so this allows us to handle the host-defined options separately. PR-URL: https://github.com/nodejs/node/pull/50137 Refs: https://github.com/nodejs/node/issues/35375 Reviewed-By: Geoffrey Booth Reviewed-By: Yagiz Nizipli Reviewed-By: Chengzhong Wu Reviewed-By: Antoine du Hamel --- lib/internal/modules/cjs/loader.js | 73 +++++++------ lib/internal/modules/esm/translators.js | 35 ++++--- lib/internal/process/execution.js | 35 ++++--- lib/internal/vm.js | 131 +++++++++++++----------- lib/repl.js | 85 +++++++-------- lib/vm.js | 63 ++++++++++-- test/message/eval_messages.out | 14 +-- test/message/stdin_messages.out | 18 ++-- 8 files changed, 268 insertions(+), 186 deletions(-) diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index 8be147c8e233ca..b3b438372fe9ed 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -52,6 +52,7 @@ const { SafeMap, SafeWeakMap, String, + Symbol, StringPrototypeCharAt, StringPrototypeCharCodeAt, StringPrototypeEndsWith, @@ -84,7 +85,12 @@ const { setOwnProperty, getLazy, } = require('internal/util'); -const { internalCompileFunction } = require('internal/vm'); +const { + internalCompileFunction, + makeContextifyScript, + runScriptInThisContext, +} = require('internal/vm'); + const assert = require('internal/assert'); const fs = require('fs'); const path = require('path'); @@ -1240,7 +1246,6 @@ Module.prototype.require = function(id) { let resolvedArgv; let hasPausedEntry = false; /** @type {import('vm').Script} */ -let Script; /** * Wraps the given content in a script and runs it in a new context. @@ -1250,47 +1255,49 @@ let Script; * @param {object} codeCache The SEA code cache */ function wrapSafe(filename, content, cjsModuleInstance, codeCache) { + const hostDefinedOptionId = Symbol(`cjs:${filename}`); + async function importModuleDynamically(specifier, _, importAttributes) { + const cascadedLoader = getCascadedLoader(); + return cascadedLoader.import(specifier, normalizeReferrerURL(filename), + importAttributes); + } if (patched) { - const wrapper = Module.wrap(content); - if (Script === undefined) { - ({ Script } = require('vm')); - } - const script = new Script(wrapper, { - filename, - lineOffset: 0, - importModuleDynamically: async (specifier, _, importAttributes) => { - const cascadedLoader = getCascadedLoader(); - return cascadedLoader.import(specifier, normalizeReferrerURL(filename), - importAttributes); - }, - }); + const wrapped = Module.wrap(content); + const script = makeContextifyScript( + wrapped, // code + filename, // filename + 0, // lineOffset + 0, // columnOffset + undefined, // cachedData + false, // produceCachedData + undefined, // parsingContext + hostDefinedOptionId, // hostDefinedOptionId + importModuleDynamically, // importModuleDynamically + ); // Cache the source map for the module if present. if (script.sourceMapURL) { maybeCacheSourceMap(filename, content, this, false, undefined, script.sourceMapURL); } - return script.runInThisContext({ - displayErrors: true, - }); + return runScriptInThisContext(script, true, false); } + const params = [ 'exports', 'require', 'module', '__filename', '__dirname' ]; try { - const result = internalCompileFunction(content, [ - 'exports', - 'require', - 'module', - '__filename', - '__dirname', - ], { - filename, - cachedData: codeCache, - importModuleDynamically(specifier, _, importAttributes) { - const cascadedLoader = getCascadedLoader(); - return cascadedLoader.import(specifier, normalizeReferrerURL(filename), - importAttributes); - }, - }); + const result = internalCompileFunction( + content, // code, + filename, // filename + 0, // lineOffset + 0, // columnOffset, + codeCache, // cachedData + false, // produceCachedData + undefined, // parsingContext + undefined, // contextExtensions + params, // params + hostDefinedOptionId, // hostDefinedOptionId + importModuleDynamically, // importModuleDynamically + ); // The code cache is used for SEAs only. if (codeCache && diff --git a/lib/internal/modules/esm/translators.js b/lib/internal/modules/esm/translators.js index 5627d98cf294d0..c36fe07a9503ae 100644 --- a/lib/internal/modules/esm/translators.js +++ b/lib/internal/modules/esm/translators.js @@ -15,6 +15,7 @@ const { StringPrototypeReplaceAll, StringPrototypeSlice, StringPrototypeStartsWith, + Symbol, SyntaxErrorPrototype, globalThis: { WebAssembly }, } = primordials; @@ -192,19 +193,29 @@ function enrichCJSError(err, content, filename) { */ function loadCJSModule(module, source, url, filename) { let compiledWrapper; + async function importModuleDynamically(specifier, _, importAttributes) { + return asyncESM.esmLoader.import(specifier, url, importAttributes); + } try { - compiledWrapper = internalCompileFunction(source, [ - 'exports', - 'require', - 'module', - '__filename', - '__dirname', - ], { - filename, - importModuleDynamically(specifier, _, importAttributes) { - return asyncESM.esmLoader.import(specifier, url, importAttributes); - }, - }).function; + compiledWrapper = internalCompileFunction( + source, // code, + filename, // filename + 0, // lineOffset + 0, // columnOffset, + undefined, // cachedData + false, // produceCachedData + undefined, // parsingContext + undefined, // contextExtensions + [ // params + 'exports', + 'require', + 'module', + '__filename', + '__dirname', + ], + Symbol(`cjs:${filename}`), // hostDefinedOptionsId + importModuleDynamically, // importModuleDynamically + ).function; } catch (err) { enrichCJSError(err, source, url); throw err; diff --git a/lib/internal/process/execution.js b/lib/internal/process/execution.js index 8ae6a1678af1b5..b8c507c798182e 100644 --- a/lib/internal/process/execution.js +++ b/lib/internal/process/execution.js @@ -1,6 +1,7 @@ 'use strict'; const { + Symbol, RegExpPrototypeExec, globalThis, } = primordials; @@ -25,7 +26,9 @@ const { emitAfter, popAsyncContext, } = require('internal/async_hooks'); - +const { + makeContextifyScript, runScriptInThisContext, +} = require('internal/vm'); // shouldAbortOnUncaughtToggle is a typed array for faster // communication with JS. const { shouldAbortOnUncaughtToggle } = internalBinding('util'); @@ -53,7 +56,6 @@ function evalModule(source, print) { function evalScript(name, body, breakFirstLine, print, shouldLoadESM = false) { const CJSModule = require('internal/modules/cjs/loader').Module; - const { kVmBreakFirstLineSymbol } = require('internal/util'); const { pathToFileURL } = require('internal/url'); const cwd = tryGetCwd(); @@ -79,16 +81,25 @@ function evalScript(name, body, breakFirstLine, print, shouldLoadESM = false) { `; globalThis.__filename = name; RegExpPrototypeExec(/^/, ''); // Necessary to reset RegExp statics before user code runs. - const result = module._compile(script, `${name}-wrapper`)(() => - require('vm').runInThisContext(body, { - filename: name, - displayErrors: true, - [kVmBreakFirstLineSymbol]: !!breakFirstLine, - importModuleDynamically(specifier, _, importAttributes) { - const loader = asyncESM.esmLoader; - return loader.import(specifier, baseUrl, importAttributes); - }, - })); + const result = module._compile(script, `${name}-wrapper`)(() => { + const hostDefinedOptionId = Symbol(name); + async function importModuleDynamically(specifier, _, importAttributes) { + const loader = asyncESM.esmLoader; + return loader.import(specifier, baseUrl, importAttributes); + } + const script = makeContextifyScript( + body, // code + name, // filename, + 0, // lineOffset + 0, // columnOffset, + undefined, // cachedData + false, // produceCachedData + undefined, // parsingContext + hostDefinedOptionId, // hostDefinedOptionId + importModuleDynamically, // importModuleDynamically + ); + return runScriptInThisContext(script, true, !!breakFirstLine); + }); if (print) { const { log } = require('internal/console/global'); log(result); diff --git a/lib/internal/vm.js b/lib/internal/vm.js index a463bdec88bdd4..4f7b8c652f3c26 100644 --- a/lib/internal/vm.js +++ b/lib/internal/vm.js @@ -1,32 +1,26 @@ 'use strict'; const { - ArrayPrototypeForEach, + ReflectApply, Symbol, } = primordials; const { + ContextifyScript, compileFunction, isContext: _isContext, } = internalBinding('contextify'); +const { + runInContext, +} = ContextifyScript.prototype; const { default_host_defined_options, } = internalBinding('symbols'); const { - validateArray, - validateBoolean, - validateBuffer, validateFunction, validateObject, - validateString, - validateStringArray, kValidateObjectAllowArray, - kValidateObjectAllowNullable, - validateInt32, } = require('internal/validators'); -const { - ERR_INVALID_ARG_TYPE, -} = require('internal/errors').codes; function isContext(object) { validateObject(object, 'object', kValidateObjectAllowArray); @@ -50,49 +44,20 @@ function getHostDefinedOptionId(importModuleDynamically, filename) { return Symbol(filename); } -function internalCompileFunction(code, params, options) { - validateString(code, 'code'); - if (params !== undefined) { - validateStringArray(params, 'params'); - } - const { - filename = '', - columnOffset = 0, - lineOffset = 0, - cachedData = undefined, - produceCachedData = false, - parsingContext = undefined, - contextExtensions = [], - importModuleDynamically, - } = options; - - validateString(filename, 'options.filename'); - validateInt32(columnOffset, 'options.columnOffset'); - validateInt32(lineOffset, 'options.lineOffset'); - if (cachedData !== undefined) - validateBuffer(cachedData, 'options.cachedData'); - validateBoolean(produceCachedData, 'options.produceCachedData'); - if (parsingContext !== undefined) { - if ( - typeof parsingContext !== 'object' || - parsingContext === null || - !isContext(parsingContext) - ) { - throw new ERR_INVALID_ARG_TYPE( - 'options.parsingContext', - 'Context', - parsingContext, - ); - } - } - validateArray(contextExtensions, 'options.contextExtensions'); - ArrayPrototypeForEach(contextExtensions, (extension, i) => { - const name = `options.contextExtensions[${i}]`; - validateObject(extension, name, kValidateObjectAllowNullable); +function registerImportModuleDynamically(referrer, importModuleDynamically) { + const { importModuleDynamicallyWrap } = require('internal/vm/module'); + const { registerModule } = require('internal/modules/esm/utils'); + registerModule(referrer, { + __proto__: null, + importModuleDynamically: + importModuleDynamicallyWrap(importModuleDynamically), }); +} - const hostDefinedOptionId = - getHostDefinedOptionId(importModuleDynamically, filename); +function internalCompileFunction( + code, filename, lineOffset, columnOffset, + cachedData, produceCachedData, parsingContext, contextExtensions, + params, hostDefinedOptionId, importModuleDynamically) { const result = compileFunction( code, filename, @@ -119,23 +84,65 @@ function internalCompileFunction(code, params, options) { } if (importModuleDynamically !== undefined) { - validateFunction(importModuleDynamically, - 'options.importModuleDynamically'); - const { importModuleDynamicallyWrap } = require('internal/vm/module'); - const wrapped = importModuleDynamicallyWrap(importModuleDynamically); - const func = result.function; - const { registerModule } = require('internal/modules/esm/utils'); - registerModule(func, { - __proto__: null, - importModuleDynamically: wrapped, - }); + registerImportModuleDynamically(result.function, importModuleDynamically); } return result; } +function makeContextifyScript(code, + filename, + lineOffset, + columnOffset, + cachedData, + produceCachedData, + parsingContext, + hostDefinedOptionId, + importModuleDynamically) { + let script; + // Calling `ReThrow()` on a native TryCatch does not generate a new + // abort-on-uncaught-exception check. A dummy try/catch in JS land + // protects against that. + try { // eslint-disable-line no-useless-catch + script = new ContextifyScript(code, + filename, + lineOffset, + columnOffset, + cachedData, + produceCachedData, + parsingContext, + hostDefinedOptionId); + } catch (e) { + throw e; /* node-do-not-add-exception-line */ + } + + if (importModuleDynamically !== undefined) { + registerImportModuleDynamically(script, importModuleDynamically); + } + return script; +} + +// Internal version of vm.Script.prototype.runInThisContext() which skips +// argument validation. +function runScriptInThisContext(script, displayErrors, breakOnFirstLine) { + return ReflectApply( + runInContext, + script, + [ + null, // sandbox - use current context + -1, // timeout + displayErrors, // displayErrors + false, // breakOnSigint + breakOnFirstLine, // breakOnFirstLine + ], + ); +} + module.exports = { getHostDefinedOptionId, internalCompileFunction, isContext, + makeContextifyScript, + registerImportModuleDynamically, + runScriptInThisContext, }; diff --git a/lib/repl.js b/lib/repl.js index 52f3026414d72d..d8021215b3f425 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -118,6 +118,9 @@ const { } = require('internal/util'); const { inspect } = require('internal/util/inspect'); const vm = require('vm'); + +const { runInThisContext, runInContext } = vm.Script.prototype; + const path = require('path'); const fs = require('fs'); const { Interface } = require('readline'); @@ -185,7 +188,9 @@ const history = require('internal/repl/history'); const { extensionFormatMap, } = require('internal/modules/esm/formats'); - +const { + makeContextifyScript, +} = require('internal/vm'); let nextREPLResourceNumber = 1; // This prevents v8 code cache from getting confused and using a different // cache from a resource of the same name @@ -430,8 +435,6 @@ function REPLServer(prompt, } function defaultEval(code, context, file, cb) { - const asyncESM = require('internal/process/esm_loader'); - let result, script, wrappedErr; let err = null; let wrappedCmd = false; @@ -449,6 +452,21 @@ function REPLServer(prompt, wrappedCmd = true; } + const hostDefinedOptionId = Symbol(`eval:${file}`); + let parentURL; + try { + const { pathToFileURL } = require('internal/url'); + // Adding `/repl` prevents dynamic imports from loading relative + // to the parent of `process.cwd()`. + parentURL = pathToFileURL(path.join(process.cwd(), 'repl')).href; + } catch { + // Continue regardless of error. + } + async function importModuleDynamically(specifier, _, importAttributes) { + const asyncESM = require('internal/process/esm_loader'); + return asyncESM.esmLoader.import(specifier, parentURL, + importAttributes); + } // `experimentalREPLAwait` is set to true by default. // Shall be false in case `--no-experimental-repl-await` flag is used. if (experimentalREPLAwait && StringPrototypeIncludes(code, 'await')) { @@ -466,28 +484,21 @@ function REPLServer(prompt, } catch (e) { let recoverableError = false; if (e.name === 'SyntaxError') { - let parentURL; - try { - const { pathToFileURL } = require('internal/url'); - // Adding `/repl` prevents dynamic imports from loading relative - // to the parent of `process.cwd()`. - parentURL = pathToFileURL(path.join(process.cwd(), 'repl')).href; - } catch { - // Continue regardless of error. - } - // Remove all "await"s and attempt running the script // in order to detect if error is truly non recoverable const fallbackCode = SideEffectFreeRegExpPrototypeSymbolReplace(/\bawait\b/g, code, ''); try { - vm.createScript(fallbackCode, { - filename: file, - displayErrors: true, - importModuleDynamically: (specifier, _, importAttributes) => { - return asyncESM.esmLoader.import(specifier, parentURL, - importAttributes); - }, - }); + makeContextifyScript( + fallbackCode, // code + file, // filename, + 0, // lineOffset + 0, // columnOffset, + undefined, // cachedData + false, // produceCachedData + undefined, // parsingContext + hostDefinedOptionId, // hostDefinedOptionId + importModuleDynamically, // importModuleDynamically + ); } catch (fallbackError) { if (isRecoverableError(fallbackError, fallbackCode)) { recoverableError = true; @@ -507,15 +518,6 @@ function REPLServer(prompt, return cb(null); if (err === null) { - let parentURL; - try { - const { pathToFileURL } = require('internal/url'); - // Adding `/repl` prevents dynamic imports from loading relative - // to the parent of `process.cwd()`. - parentURL = pathToFileURL(path.join(process.cwd(), 'repl')).href; - } catch { - // Continue regardless of error. - } while (true) { try { if (self.replMode === module.exports.REPL_MODE_STRICT && @@ -524,14 +526,17 @@ function REPLServer(prompt, // value for statements and declarations that don't return a value. code = `'use strict'; void 0;\n${code}`; } - script = vm.createScript(code, { - filename: file, - displayErrors: true, - importModuleDynamically: (specifier, _, importAttributes) => { - return asyncESM.esmLoader.import(specifier, parentURL, - importAttributes); - }, - }); + script = makeContextifyScript( + code, // code + file, // filename, + 0, // lineOffset + 0, // columnOffset, + undefined, // cachedData + false, // produceCachedData + undefined, // parsingContext + hostDefinedOptionId, // hostDefinedOptionId + importModuleDynamically, // importModuleDynamically + ); } catch (e) { debug('parse error %j', code, e); if (wrappedCmd) { @@ -591,9 +596,9 @@ function REPLServer(prompt, }; if (self.useGlobal) { - result = script.runInThisContext(scriptOptions); + result = ReflectApply(runInThisContext, script, [scriptOptions]); } else { - result = script.runInContext(context, scriptOptions); + result = ReflectApply(runInContext, script, [context, scriptOptions]); } } finally { if (self.breakEvalOnSigint) { diff --git a/lib/vm.js b/lib/vm.js index fe2981019a6170..d396a3df8c0e13 100644 --- a/lib/vm.js +++ b/lib/vm.js @@ -39,13 +39,16 @@ const { ERR_INVALID_ARG_TYPE, } = require('internal/errors').codes; const { + validateArray, validateBoolean, validateBuffer, validateInt32, - validateObject, validateOneOf, + validateObject, validateString, + validateStringArray, validateUint32, + kValidateObjectAllowNullable, } = require('internal/validators'); const { emitExperimentalWarning, @@ -56,6 +59,7 @@ const { getHostDefinedOptionId, internalCompileFunction, isContext, + registerImportModuleDynamically, } = require('internal/vm'); const kParsingContext = Symbol('script parsing context'); @@ -105,13 +109,7 @@ class Script extends ContextifyScript { } if (importModuleDynamically !== undefined) { - const { importModuleDynamicallyWrap } = require('internal/vm/module'); - const { registerModule } = require('internal/modules/esm/utils'); - registerModule(this, { - __proto__: null, - importModuleDynamically: - importModuleDynamicallyWrap(importModuleDynamically), - }); + registerImportModuleDynamically(this, importModuleDynamically); } } @@ -298,7 +296,54 @@ function runInThisContext(code, options) { } function compileFunction(code, params, options = kEmptyObject) { - return internalCompileFunction(code, params, options).function; + validateString(code, 'code'); + if (params !== undefined) { + validateStringArray(params, 'params'); + } + const { + filename = '', + columnOffset = 0, + lineOffset = 0, + cachedData = undefined, + produceCachedData = false, + parsingContext = undefined, + contextExtensions = [], + importModuleDynamically, + } = options; + + validateString(filename, 'options.filename'); + validateInt32(columnOffset, 'options.columnOffset'); + validateInt32(lineOffset, 'options.lineOffset'); + if (cachedData !== undefined) + validateBuffer(cachedData, 'options.cachedData'); + validateBoolean(produceCachedData, 'options.produceCachedData'); + if (parsingContext !== undefined) { + if ( + typeof parsingContext !== 'object' || + parsingContext === null || + !isContext(parsingContext) + ) { + throw new ERR_INVALID_ARG_TYPE( + 'options.parsingContext', + 'Context', + parsingContext, + ); + } + } + validateArray(contextExtensions, 'options.contextExtensions'); + ArrayPrototypeForEach(contextExtensions, (extension, i) => { + const name = `options.contextExtensions[${i}]`; + validateObject(extension, name, kValidateObjectAllowNullable); + }); + + const hostDefinedOptionId = + getHostDefinedOptionId(importModuleDynamically, filename); + + return internalCompileFunction( + code, filename, lineOffset, columnOffset, + cachedData, produceCachedData, parsingContext, contextExtensions, + params, hostDefinedOptionId, importModuleDynamically, + ).function; } const measureMemoryModes = { diff --git a/test/message/eval_messages.out b/test/message/eval_messages.out index 3f44332c03a470..e07bbe4d6acd3c 100644 --- a/test/message/eval_messages.out +++ b/test/message/eval_messages.out @@ -2,10 +2,9 @@ [eval]:1 with(this){__filename} ^^^^ + SyntaxError: Strict mode code may not include a with statement - at new Script (node:vm:*:*) - at createScript (node:vm:*:*) - at Object.runInThisContext (node:vm:*:*) + at makeContextifyScript (node:internal/vm:*:*) at node:internal/process/execution:*:* at [eval]-wrapper:*:* at runScript (node:internal/process/execution:*:*) @@ -21,8 +20,7 @@ throw new Error("hello") Error: hello at [eval]:1:7 - at Script.runInThisContext (node:vm:*:*) - at Object.runInThisContext (node:vm:*:*) + at runScriptInThisContext (node:internal/vm:*:*) at node:internal/process/execution:*:* at [eval]-wrapper:*:* at runScript (node:internal/process/execution:*:*) @@ -37,8 +35,7 @@ throw new Error("hello") Error: hello at [eval]:1:7 - at Script.runInThisContext (node:vm:*:*) - at Object.runInThisContext (node:vm:*:*) + at runScriptInThisContext (node:internal/vm:*:*) at node:internal/process/execution:*:* at [eval]-wrapper:*:* at runScript (node:internal/process/execution:*:*) @@ -53,8 +50,7 @@ var x = 100; y = x; ReferenceError: y is not defined at [eval]:1:16 - at Script.runInThisContext (node:vm:*:*) - at Object.runInThisContext (node:vm:*:*) + at runScriptInThisContext (node:internal/vm:*:*) at node:internal/process/execution:*:* at [eval]-wrapper:*:* at runScript (node:internal/process/execution:*:*) diff --git a/test/message/stdin_messages.out b/test/message/stdin_messages.out index 3fd047aacb11a2..6afc8a62d7fcd9 100644 --- a/test/message/stdin_messages.out +++ b/test/message/stdin_messages.out @@ -4,9 +4,7 @@ with(this){__filename} ^^^^ SyntaxError: Strict mode code may not include a with statement - at new Script (node:vm:*) - at createScript (node:vm:*) - at Object.runInThisContext (node:vm:*) + at makeContextifyScript (node:internal/vm:*:*) at node:internal/process/execution:*:* at [stdin]-wrapper:*:* at runScript (node:internal/process/execution:*:*) @@ -14,6 +12,8 @@ SyntaxError: Strict mode code may not include a with statement at node:internal/main/eval_stdin:*:* at Socket. (node:internal/process/execution:*:*) at Socket.emit (node:events:*:*) + at endReadableNT (node:internal/streams/readable:*:*) + at process.processTicksAndRejections (node:internal/process/task_queues:*:*) Node.js * 42 @@ -24,8 +24,7 @@ throw new Error("hello") Error: hello at [stdin]:1:7 - at Script.runInThisContext (node:vm:*) - at Object.runInThisContext (node:vm:*) + at runScriptInThisContext (node:internal/vm:*:*) at node:internal/process/execution:*:* at [stdin]-wrapper:*:* at runScript (node:internal/process/execution:*:*) @@ -33,6 +32,7 @@ Error: hello at node:internal/main/eval_stdin:*:* at Socket. (node:internal/process/execution:*:*) at Socket.emit (node:events:*:*) + at endReadableNT (node:internal/streams/readable:*:*) Node.js * [stdin]:1 @@ -41,8 +41,7 @@ throw new Error("hello") Error: hello at [stdin]:1:* - at Script.runInThisContext (node:vm:*) - at Object.runInThisContext (node:vm:*) + at runScriptInThisContext (node:internal/vm:*:*) at node:internal/process/execution:*:* at [stdin]-wrapper:*:* at runScript (node:internal/process/execution:*:*) @@ -50,6 +49,7 @@ Error: hello at node:internal/main/eval_stdin:*:* at Socket. (node:internal/process/execution:*:*) at Socket.emit (node:events:*:*) + at endReadableNT (node:internal/streams/readable:*:*) Node.js * 100 @@ -59,8 +59,7 @@ let x = 100; y = x; ReferenceError: y is not defined at [stdin]:1:16 - at Script.runInThisContext (node:vm:*) - at Object.runInThisContext (node:vm:*) + at runScriptInThisContext (node:internal/vm:*:*) at node:internal/process/execution:*:* at [stdin]-wrapper:*:* at runScript (node:internal/process/execution:*:*) @@ -68,6 +67,7 @@ ReferenceError: y is not defined at node:internal/main/eval_stdin:*:* at Socket. (node:internal/process/execution:*:*) at Socket.emit (node:events:*:*) + at endReadableNT (node:internal/streams/readable:*:*) Node.js *