Skip to content

Commit c205a80

Browse files
committed
errors: slights improvements for hideStackFrames
As suggested by @puzpuzpuz and @BridgeAR * Do not run the full loop for user-generated exceptions * Reduce the prefix * Add function names to the functions in errors.js so that they keep their names in the debugger/profiler Refs: nodejs#35644
1 parent c947273 commit c205a80

File tree

1 file changed

+49
-43
lines changed

1 file changed

+49
-43
lines changed

lib/internal/errors.js

+49-43
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ const MainContextError = Error;
5656
const overrideStackTrace = new WeakMap();
5757
const kNoOverride = Symbol('kNoOverride');
5858
let userStackTraceLimit = Error.stackTraceLimit;
59+
const nodeInternalPrefix = '__node_internal_';
5960
const prepareStackTrace = (globalThis, error, trace) => {
6061
// API for node internals to override error stack formatting
6162
// without interfering with userland code.
@@ -65,15 +66,18 @@ const prepareStackTrace = (globalThis, error, trace) => {
6566
return f(error, trace);
6667
}
6768

68-
for (let l = trace.length - 1; l >= 0; l--) {
69-
const fn = trace[l].getFunctionName();
70-
if (fn != null && fn.startsWith('__node_internal_hidden_')) {
71-
trace.splice(0, l + 1);
72-
break;
69+
const firstFrame = trace[0]?.getFunctionName();
70+
if (firstFrame && firstFrame.startsWith(nodeInternalPrefix)) {
71+
for (let l = trace.length - 1; l >= 0; l--) {
72+
const fn = trace[l].getFunctionName();
73+
if (fn != null && fn.startsWith(nodeInternalPrefix)) {
74+
trace.splice(0, l + 1);
75+
break;
76+
}
7377
}
78+
if (trace.length > userStackTraceLimit)
79+
trace.splice(userStackTraceLimit);
7480
}
75-
if (trace.length > userStackTraceLimit)
76-
trace.splice(userStackTraceLimit);
7781

7882
const globalOverride =
7983
maybeOverridePrepareStackTrace(globalThis, error, trace);
@@ -136,7 +140,7 @@ function lazyBuffer() {
136140
return buffer;
137141
}
138142

139-
const addCodeToName = hideStackFrames(function(err, name, code) {
143+
const addCodeToName = hideStackFrames(function addCodeToName(err, name, code) {
140144
// Set the stack
141145
err = captureLargerStackTrace(err);
142146
// Add the error code to the name to include it in the stack trace.
@@ -309,7 +313,7 @@ function makeNodeErrorWithCode(Base, key) {
309313
function hideStackFrames(fn) {
310314
// We rename the functions that will be hidden to cut off the stacktrace
311315
// at the outermost one
312-
const hidden = '__node_internal_hidden_' + fn.name;
316+
const hidden = nodeInternalPrefix + fn.name;
313317
ObjectDefineProperty(fn, 'name', { value: hidden });
314318
return fn;
315319
}
@@ -380,16 +384,17 @@ function uvErrmapGet(name) {
380384
return uvBinding.errmap.get(name);
381385
}
382386

383-
function captureLargerStackTrace(err) {
384-
userStackTraceLimit = Error.stackTraceLimit;
385-
Error.stackTraceLimit = Infinity;
386-
// eslint-disable-next-line no-restricted-syntax
387-
Error.captureStackTrace(err);
388-
// Reset the limit and setting the name property.
389-
Error.stackTraceLimit = userStackTraceLimit;
387+
const captureLargerStackTrace = hideStackFrames(
388+
function captureLargerStackTrace(err) {
389+
userStackTraceLimit = Error.stackTraceLimit;
390+
Error.stackTraceLimit = Infinity;
391+
// eslint-disable-next-line no-restricted-syntax
392+
Error.captureStackTrace(err);
393+
// Reset the limit
394+
Error.stackTraceLimit = userStackTraceLimit;
390395

391-
return err;
392-
}
396+
return err;
397+
});
393398

394399
/**
395400
* This creates an error compatible with errors produced in the C++
@@ -400,7 +405,7 @@ function captureLargerStackTrace(err) {
400405
* @param {Object} ctx
401406
* @returns {Error}
402407
*/
403-
const uvException = hideStackFrames(function(ctx) {
408+
const uvException = hideStackFrames(function uvException(ctx) {
404409
const [code, uvmsg] = uvErrmapGet(ctx.errno) || uvUnmappedError;
405410
let message = `${code}: ${ctx.message || uvmsg}, ${ctx.syscall}`;
406411

@@ -455,8 +460,8 @@ const uvException = hideStackFrames(function(ctx) {
455460
* @param {number} [port]
456461
* @returns {Error}
457462
*/
458-
const uvExceptionWithHostPort =
459-
hideStackFrames(function(err, syscall, address, port) {
463+
const uvExceptionWithHostPort = hideStackFrames(
464+
function uvExceptionWithHostPort(err, syscall, address, port) {
460465
const [code, uvmsg] = uvErrmapGet(err) || uvUnmappedError;
461466
const message = `${syscall} ${code}: ${uvmsg}`;
462467
let details = '';
@@ -495,28 +500,29 @@ const uvExceptionWithHostPort =
495500
* @param {string} [original]
496501
* @returns {Error}
497502
*/
498-
const errnoException = hideStackFrames(function(err, syscall, original) {
499-
// TODO(joyeecheung): We have to use the type-checked
500-
// getSystemErrorName(err) to guard against invalid arguments from users.
501-
// This can be replaced with [ code ] = errmap.get(err) when this method
502-
// is no longer exposed to user land.
503-
if (util === undefined) util = require('util');
504-
const code = util.getSystemErrorName(err);
505-
const message = original ?
506-
`${syscall} ${code} ${original}` : `${syscall} ${code}`;
503+
const errnoException = hideStackFrames(
504+
function errnoException(err, syscall, original) {
505+
// TODO(joyeecheung): We have to use the type-checked
506+
// getSystemErrorName(err) to guard against invalid arguments from users.
507+
// This can be replaced with [ code ] = errmap.get(err) when this method
508+
// is no longer exposed to user land.
509+
if (util === undefined) util = require('util');
510+
const code = util.getSystemErrorName(err);
511+
const message = original ?
512+
`${syscall} ${code} ${original}` : `${syscall} ${code}`;
507513

508-
const tmpLimit = Error.stackTraceLimit;
509-
Error.stackTraceLimit = 0;
510-
// eslint-disable-next-line no-restricted-syntax
511-
const ex = new Error(message);
512-
Error.stackTraceLimit = tmpLimit;
513-
ex.errno = err;
514-
ex.code = code;
515-
ex.syscall = syscall;
514+
const tmpLimit = Error.stackTraceLimit;
515+
Error.stackTraceLimit = 0;
516+
// eslint-disable-next-line no-restricted-syntax
517+
const ex = new Error(message);
518+
Error.stackTraceLimit = tmpLimit;
519+
ex.errno = err;
520+
ex.code = code;
521+
ex.syscall = syscall;
516522

517-
captureLargerStackTrace(ex);
518-
return ex;
519-
});
523+
captureLargerStackTrace(ex);
524+
return ex;
525+
});
520526

521527
/**
522528
* Deprecated, new function is `uvExceptionWithHostPort()`
@@ -529,8 +535,8 @@ const errnoException = hideStackFrames(function(err, syscall, original) {
529535
* @param {string} [additional]
530536
* @returns {Error}
531537
*/
532-
const exceptionWithHostPort =
533-
hideStackFrames(function(err, syscall, address, port, additional) {
538+
const exceptionWithHostPort = hideStackFrames(
539+
function exceptionWithHostPort(err, syscall, address, port, additional) {
534540
// TODO(joyeecheung): We have to use the type-checked
535541
// getSystemErrorName(err) to guard against invalid arguments from users.
536542
// This can be replaced with [ code ] = errmap.get(err) when this method

0 commit comments

Comments
 (0)