Skip to content

Commit 74a69ab

Browse files
devsnekBridgeAR
authored andcommitted
lib: stop using prepareStackTrace
PR-URL: #29777 Reviewed-By: Ben Coe <[email protected]> Reviewed-By: Colin Ihrig <[email protected]>
1 parent bede981 commit 74a69ab

File tree

4 files changed

+65
-52
lines changed

4 files changed

+65
-52
lines changed

lib/assert.js

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,16 @@
2323
const { Object } = primordials;
2424

2525
const { Buffer } = require('buffer');
26-
const { codes: {
27-
ERR_AMBIGUOUS_ARGUMENT,
28-
ERR_INVALID_ARG_TYPE,
29-
ERR_INVALID_ARG_VALUE,
30-
ERR_INVALID_RETURN_VALUE,
31-
ERR_MISSING_ARGS
32-
} } = require('internal/errors');
26+
const {
27+
codes: {
28+
ERR_AMBIGUOUS_ARGUMENT,
29+
ERR_INVALID_ARG_TYPE,
30+
ERR_INVALID_ARG_VALUE,
31+
ERR_INVALID_RETURN_VALUE,
32+
ERR_MISSING_ARGS,
33+
},
34+
overrideStackTrace,
35+
} = require('internal/errors');
3336
const AssertionError = require('internal/assert/assertion_error');
3437
const { openSync, closeSync, readSync } = require('fs');
3538
const { inspect } = require('internal/util/inspect');
@@ -261,10 +264,8 @@ function getErrMessage(message, fn) {
261264
Error.captureStackTrace(err, fn);
262265
Error.stackTraceLimit = tmpLimit;
263266

264-
const tmpPrepare = Error.prepareStackTrace;
265-
Error.prepareStackTrace = (_, stack) => stack;
267+
overrideStackTrace.set(err, (_, stack) => stack);
266268
const call = err.stack[0];
267-
Error.prepareStackTrace = tmpPrepare;
268269

269270
const filename = call.getFileName();
270271
const line = call.getLineNumber() - 1;

lib/internal/errors.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,18 @@ const { kMaxLength } = internalBinding('buffer');
2121

2222
const MainContextError = Error;
2323
const ErrorToString = Error.prototype.toString;
24-
// Polyfill of V8's Error.prepareStackTrace API.
25-
// https://crbug.com/v8/7848
24+
const overrideStackTrace = new WeakMap();
2625
const prepareStackTrace = (globalThis, error, trace) => {
26+
// API for node internals to override error stack formatting
27+
// without interfering with userland code.
28+
if (overrideStackTrace.has(error)) {
29+
const f = overrideStackTrace.get(error);
30+
overrideStackTrace.delete(error);
31+
return f(error, trace);
32+
}
33+
34+
// Polyfill of V8's Error.prepareStackTrace API.
35+
// https://crbug.com/v8/7848
2736
// `globalThis` is the global that contains the constructor which
2837
// created `error`.
2938
if (typeof globalThis.Error.prepareStackTrace === 'function') {
@@ -36,6 +45,11 @@ const prepareStackTrace = (globalThis, error, trace) => {
3645
return MainContextError.prepareStackTrace(error, trace);
3746
}
3847

48+
// Normal error formatting:
49+
//
50+
// Error: Message
51+
// at function (file)
52+
// at file
3953
const errorString = ErrorToString.call(error);
4054
if (trace.length === 0) {
4155
return errorString;
@@ -675,6 +689,7 @@ module.exports = {
675689
// This is exported only to facilitate testing.
676690
E,
677691
prepareStackTrace,
692+
overrideStackTrace,
678693
kEnhanceStackBeforeInspector,
679694
fatalExceptionStackEnhancers
680695
};

lib/internal/util.js

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ const {
77
ERR_NO_CRYPTO,
88
ERR_UNKNOWN_SIGNAL
99
},
10-
uvErrmapGet
10+
uvErrmapGet,
11+
overrideStackTrace,
1112
} = require('internal/errors');
1213
const { signals } = internalBinding('constants').os;
1314
const {
@@ -338,15 +339,13 @@ function isInsideNodeModules() {
338339
// side-effect-free. Since this is currently only used for a deprecated API,
339340
// the perf implications should be okay.
340341
getStructuredStack = runInNewContext(`(function() {
341-
Error.prepareStackTrace = function(err, trace) {
342-
return trace;
343-
};
344342
Error.stackTraceLimit = Infinity;
345-
346343
return function structuredStack() {
347-
return new Error().stack;
344+
const e = new Error();
345+
overrideStackTrace.set(e, (err, trace) => trace);
346+
return e.stack;
348347
};
349-
})()`, {}, { filename: 'structured-stack' });
348+
})()`, { overrideStackTrace }, { filename: 'structured-stack' });
350349
}
351350

352351
const stack = getStructuredStack();

lib/repl.js

Lines changed: 31 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,15 @@ const CJSModule = require('internal/modules/cjs/loader');
6969
const domain = require('domain');
7070
const debug = require('internal/util/debuglog').debuglog('repl');
7171
const {
72-
ERR_CANNOT_WATCH_SIGINT,
73-
ERR_INVALID_ARG_TYPE,
74-
ERR_INVALID_REPL_EVAL_CONFIG,
75-
ERR_INVALID_REPL_INPUT,
76-
ERR_SCRIPT_EXECUTION_INTERRUPTED
77-
} = require('internal/errors').codes;
72+
codes: {
73+
ERR_CANNOT_WATCH_SIGINT,
74+
ERR_INVALID_ARG_TYPE,
75+
ERR_INVALID_REPL_EVAL_CONFIG,
76+
ERR_INVALID_REPL_INPUT,
77+
ERR_SCRIPT_EXECUTION_INTERRUPTED,
78+
},
79+
overrideStackTrace,
80+
} = require('internal/errors');
7881
const { sendInspectorCommand } = require('internal/util/inspector');
7982
const experimentalREPLAwait = require('internal/options').getOptionValue(
8083
'--experimental-repl-await'
@@ -473,10 +476,29 @@ function REPLServer(prompt,
473476
let errStack = '';
474477

475478
if (typeof e === 'object' && e !== null) {
476-
const pstrace = Error.prepareStackTrace;
477-
Error.prepareStackTrace = prepareStackTrace(pstrace);
479+
overrideStackTrace.set(e, (error, stackFrames) => {
480+
let frames;
481+
if (typeof stackFrames === 'object') {
482+
// Search from the bottom of the call stack to
483+
// find the first frame with a null function name
484+
const idx = stackFrames
485+
.reverse()
486+
.findIndex((frame) => frame.getFunctionName() === null);
487+
// If found, get rid of it and everything below it
488+
frames = stackFrames.splice(idx + 1);
489+
} else {
490+
frames = stackFrames;
491+
}
492+
// FIXME(devsnek): this is inconsistent with the checks
493+
// that the real prepareStackTrace dispatch uses in
494+
// lib/internal/errors.js.
495+
if (typeof Error.prepareStackTrace === 'function') {
496+
return Error.prepareStackTrace(error, frames);
497+
}
498+
frames.push(error);
499+
return frames.reverse().join('\n at ');
500+
});
478501
decorateErrorStack(e);
479-
Error.prepareStackTrace = pstrace;
480502

481503
if (e.domainThrown) {
482504
delete e.domain;
@@ -590,30 +612,6 @@ function REPLServer(prompt,
590612
}
591613
}
592614

593-
function filterInternalStackFrames(structuredStack) {
594-
// Search from the bottom of the call stack to
595-
// find the first frame with a null function name
596-
if (typeof structuredStack !== 'object')
597-
return structuredStack;
598-
const idx = structuredStack.reverse().findIndex(
599-
(frame) => frame.getFunctionName() === null);
600-
601-
// If found, get rid of it and everything below it
602-
structuredStack = structuredStack.splice(idx + 1);
603-
return structuredStack;
604-
}
605-
606-
function prepareStackTrace(fn) {
607-
return (error, stackFrames) => {
608-
const frames = filterInternalStackFrames(stackFrames);
609-
if (fn) {
610-
return fn(error, frames);
611-
}
612-
frames.push(error);
613-
return frames.reverse().join('\n at ');
614-
};
615-
}
616-
617615
function _parseREPLKeyword(keyword, rest) {
618616
const cmd = this.commands[keyword];
619617
if (cmd) {

0 commit comments

Comments
 (0)