errors: improve hideStackFrames

PR-URL: https://github.com/nodejs/node/pull/49990
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
Aras Abbasi 2023-11-11 17:25:08 +01:00 committed by GitHub
parent 6b27f5b09e
commit 83e6350b82
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 984 additions and 572 deletions

View file

@ -0,0 +1,62 @@
'use strict';
const common = require('../common.js');
const assert = require('assert');
const bench = common.createBenchmark(main, {
type: [
'hide-stackframes',
'direct-call',
],
n: [1e7],
}, {
flags: ['--expose-internals'],
});
function main({ n, type }) {
const {
hideStackFrames,
codes: {
ERR_INVALID_ARG_TYPE,
},
} = require('internal/errors');
const testfn = (value) => {
if (typeof value !== 'number') {
throw new ERR_INVALID_ARG_TYPE('Benchmark', 'number', value);
}
};
const hideStackFramesTestfn = hideStackFrames((value) => {
if (typeof value !== 'number') {
throw new ERR_INVALID_ARG_TYPE.HideStackFrameError('Benchmark', 'number', value);
}
});
const fn = type === 'hide-stackframe' ? hideStackFramesTestfn : testfn;
const value = 42;
const length = 1024;
const array = [];
const errCase = false;
for (let i = 0; i < length; ++i) {
array.push(fn(value));
}
bench.start();
for (let i = 0; i < n; i++) {
const index = i % length;
array[index] = fn(value);
}
bench.end(n);
// Verify the entries to prevent dead code elimination from making
// the benchmark invalid.
for (let i = 0; i < length; ++i) {
assert.strictEqual(typeof array[i], errCase ? 'object' : 'undefined');
}
}

View file

@ -0,0 +1,87 @@
'use strict';
const common = require('../common.js');
const assert = require('assert');
const bench = common.createBenchmark(main, {
type: [
'hide-stackframes',
'direct-call',
],
double: ['true', 'false'],
n: [1e5],
}, {
flags: ['--expose-internals'],
});
function main({ n, type, double }) {
const {
hideStackFrames,
codes: {
ERR_INVALID_ARG_TYPE,
},
} = require('internal/errors');
const value = 'err';
const testfn = (value) => {
if (typeof value !== 'number') {
throw new ERR_INVALID_ARG_TYPE('Benchmark', 'number', value);
}
};
const hideStackFramesTestfn = hideStackFrames((value) => {
if (typeof value !== 'number') {
throw new ERR_INVALID_ARG_TYPE.HideStackFrameError('Benchmark', 'number', value);
}
});
function doubleTestfn(value) {
testfn(value);
}
const doubleHideStackFramesTestfn = hideStackFrames((value) => {
hideStackFramesTestfn.withoutStackTrace(value);
});
const fn = type === 'hide-stackframe' ?
double === 'true' ?
doubleHideStackFramesTestfn :
hideStackFramesTestfn :
double === 'true' ?
doubleTestfn :
testfn;
const length = 1024;
const array = [];
let errCase = false;
// Warm up.
for (let i = 0; i < length; ++i) {
try {
fn(value);
} catch (e) {
errCase = true;
array.push(e);
}
}
bench.start();
for (let i = 0; i < n; i++) {
const index = i % length;
try {
fn(value);
} catch (e) {
array[index] = e;
}
}
bench.end(n);
// Verify the entries to prevent dead code elimination from making
// the benchmark invalid.
for (let i = 0; i < length; ++i) {
assert.strictEqual(typeof array[i], errCase ? 'object' : 'undefined');
}
}

View file

@ -1,45 +0,0 @@
'use strict';
const common = require('../common.js');
const bench = common.createBenchmark(main, {
type: ['hide-stackframes-throw', 'direct-call-throw',
'hide-stackframes-noerr', 'direct-call-noerr'],
n: [10e4],
}, {
flags: ['--expose-internals'],
});
function main({ n, type }) {
const {
hideStackFrames,
codes: {
ERR_INVALID_ARG_TYPE,
},
} = require('internal/errors');
const testfn = (value) => {
if (typeof value !== 'number') {
throw new ERR_INVALID_ARG_TYPE('Benchmark', 'number', value);
}
};
let fn = testfn;
if (type.startsWith('hide-stackframe'))
fn = hideStackFrames(testfn);
let value = 42;
if (type.endsWith('-throw'))
value = 'err';
bench.start();
for (let i = 0; i < n; i++) {
try {
fn(value);
} catch {
// No-op
}
}
bench.end(n);
}

View file

@ -19,7 +19,7 @@ rules:
- selector: ThrowStatement > CallExpression[callee.name=/Error$/]
message: Use new keyword when throwing an Error.
# Config specific to lib
- selector: NewExpression[callee.name=/Error$/]:not([callee.name=/^(AssertionError|NghttpError|AbortError)$/])
- selector: NewExpression[callee.name=/Error$/]:not([callee.name=/^(AssertionError|NghttpError|AbortError|NodeAggregateError)$/])
message: Use an error exported by the internal/errors module.
- selector: CallExpression[callee.object.name='Error'][callee.property.name='captureStackTrace']
message: Please use `require('internal/errors').hideStackFrames()` instead.

View file

@ -72,7 +72,7 @@ const {
traceEnd,
getNextTraceEventId,
} = require('internal/http');
const { connResetException, codes } = require('internal/errors');
const { ConnResetException, codes } = require('internal/errors');
const {
ERR_HTTP_HEADERS_SENT,
ERR_INVALID_ARG_TYPE,
@ -452,7 +452,7 @@ function socketCloseListener() {
if (res) {
// Socket closed before we emitted 'end' below.
if (!res.complete) {
res.destroy(connResetException('aborted'));
res.destroy(new ConnResetException('aborted'));
}
req._closed = true;
req.emit('close');
@ -465,7 +465,7 @@ function socketCloseListener() {
// receive a response. The error needs to
// fire on the request.
req.socket._hadError = true;
req.emit('error', connResetException('socket hang up'));
req.emit('error', new ConnResetException('socket hang up'));
}
req._closed = true;
req.emit('close');
@ -516,7 +516,7 @@ function socketOnEnd() {
// If we don't have a response then we know that the socket
// ended prematurely and we need to emit an error on the request.
req.socket._hadError = true;
req.emit('error', connResetException('socket hang up'));
req.emit('error', new ConnResetException('socket hang up'));
}
if (parser) {
parser.finish();
@ -869,7 +869,7 @@ function onSocketNT(req, socket, err) {
function _destroy(req, err) {
if (!req.aborted && !err) {
err = connResetException('socket hang up');
err = new ConnResetException('socket hang up');
}
if (err) {
req.emit('error', err);

View file

@ -663,17 +663,17 @@ function matchHeader(self, state, field, value) {
const validateHeaderName = hideStackFrames((name, label) => {
if (typeof name !== 'string' || !name || !checkIsHttpToken(name)) {
throw new ERR_INVALID_HTTP_TOKEN(label || 'Header name', name);
throw new ERR_INVALID_HTTP_TOKEN.HideStackFramesError(label || 'Header name', name);
}
});
const validateHeaderValue = hideStackFrames((name, value) => {
if (value === undefined) {
throw new ERR_HTTP_INVALID_HEADER_VALUE(value, name);
throw new ERR_HTTP_INVALID_HEADER_VALUE.HideStackFramesError(value, name);
}
if (checkInvalidHeaderChar(value)) {
debug('Header "%s" contains invalid characters', name);
throw new ERR_INVALID_CHAR('header content', name);
throw new ERR_INVALID_CHAR.HideStackFramesError('header content', name);
}
});

View file

@ -69,7 +69,7 @@ const {
} = require('internal/async_hooks');
const { IncomingMessage } = require('_http_incoming');
const {
connResetException,
ConnResetException,
codes,
} = require('internal/errors');
const {
@ -790,7 +790,7 @@ function socketOnClose(socket, state) {
function abortIncoming(incoming) {
while (incoming.length) {
const req = incoming.shift();
req.destroy(connResetException('aborted'));
req.destroy(new ConnResetException('aborted'));
}
// Abort socket._httpMessage ?
}

View file

@ -66,7 +66,7 @@ const { Pipe, constants: PipeConstants } = internalBinding('pipe_wrap');
const { owner_symbol } = require('internal/async_hooks').symbols;
const { isArrayBufferView } = require('internal/util/types');
const { SecureContext: NativeSecureContext } = internalBinding('crypto');
const { connResetException, codes } = require('internal/errors');
const { ConnResetException, codes } = require('internal/errors');
const {
ERR_INVALID_ARG_TYPE,
ERR_INVALID_ARG_VALUE,
@ -1218,7 +1218,7 @@ function onSocketClose(err) {
// Emit ECONNRESET
if (!this._controlReleased && !this[kErrorEmitted]) {
this[kErrorEmitted] = true;
const connReset = connResetException('socket hang up');
const connReset = new ConnResetException('socket hang up');
this._tlsOptions.server.emit('tlsClientError', connReset, this);
}
}
@ -1724,9 +1724,9 @@ function onConnectEnd() {
if (!this._hadError) {
const options = this[kConnectOptions];
this._hadError = true;
const error = connResetException('Client network socket disconnected ' +
'before secure TLS connection was ' +
'established');
const error = new ConnResetException('Client network socket disconnected ' +
'before secure TLS connection was ' +
'established');
error.path = options.path;
error.host = options.host;
error.port = options.port;

View file

@ -108,7 +108,6 @@ const {
ERR_UNKNOWN_ENCODING,
},
genericNodeError,
hideStackFrames,
} = require('internal/errors');
const {
validateArray,
@ -386,19 +385,12 @@ Buffer.of = of;
ObjectSetPrototypeOf(Buffer, Uint8Array);
// The 'assertSize' method will remove itself from the callstack when an error
// occurs. This is done simply to keep the internal details of the
// implementation from bleeding out to users.
const assertSize = hideStackFrames((size) => {
validateNumber(size, 'size', 0, kMaxLength);
});
/**
* Creates a new filled Buffer instance.
* alloc(size[, fill[, encoding]])
*/
Buffer.alloc = function alloc(size, fill, encoding) {
assertSize(size);
validateNumber(size, 'size', 0, kMaxLength);
if (fill !== undefined && fill !== 0 && size > 0) {
const buf = createUnsafeBuffer(size);
return _fill(buf, fill, 0, buf.length, encoding);
@ -411,7 +403,7 @@ Buffer.alloc = function alloc(size, fill, encoding) {
* instance. If `--zero-fill-buffers` is set, will zero-fill the buffer.
*/
Buffer.allocUnsafe = function allocUnsafe(size) {
assertSize(size);
validateNumber(size, 'size', 0, kMaxLength);
return allocate(size);
};
@ -421,15 +413,15 @@ Buffer.allocUnsafe = function allocUnsafe(size) {
* If `--zero-fill-buffers` is set, will zero-fill the buffer.
*/
Buffer.allocUnsafeSlow = function allocUnsafeSlow(size) {
assertSize(size);
validateNumber(size, 'size', 0, kMaxLength);
return createUnsafeBuffer(size);
};
// If --zero-fill-buffers command line argument is set, a zero-filled
// buffer is returned.
function SlowBuffer(length) {
assertSize(length);
return createUnsafeBuffer(length);
function SlowBuffer(size) {
validateNumber(size, 'size', 0, kMaxLength);
return createUnsafeBuffer(size);
}
ObjectSetPrototypeOf(SlowBuffer.prototype, Uint8ArrayPrototype);

View file

@ -96,9 +96,10 @@ function lazyLoadCluster() {
return _cluster;
}
const errnoException = errors.errnoException;
const exceptionWithHostPort = errors.exceptionWithHostPort;
const {
ErrnoException,
ExceptionWithHostPort,
} = errors;
function Socket(type, listener) {
FunctionPrototypeCall(EventEmitter, this);
@ -286,7 +287,7 @@ Socket.prototype.bind = function(port_, address_ /* , callback */) {
flags: null,
}, (err) => {
// Callback to handle error.
const ex = errnoException(err, 'open');
const ex = new ErrnoException(err, 'open');
state.bindState = BIND_STATE_UNBOUND;
this.emit('error', ex);
});
@ -299,7 +300,7 @@ Socket.prototype.bind = function(port_, address_ /* , callback */) {
const err = state.handle.open(fd);
if (err)
throw errnoException(err, 'open');
throw new ErrnoException(err, 'open');
startListening(this);
return this;
@ -350,7 +351,7 @@ Socket.prototype.bind = function(port_, address_ /* , callback */) {
flags: flags,
}, (err) => {
// Callback to handle error.
const ex = exceptionWithHostPort(err, 'bind', ip, port);
const ex = new ExceptionWithHostPort(err, 'bind', ip, port);
state.bindState = BIND_STATE_UNBOUND;
this.emit('error', ex);
});
@ -360,7 +361,7 @@ Socket.prototype.bind = function(port_, address_ /* , callback */) {
const err = state.handle.bind(ip, port || 0, flags);
if (err) {
const ex = exceptionWithHostPort(err, 'bind', ip, port);
const ex = new ExceptionWithHostPort(err, 'bind', ip, port);
state.bindState = BIND_STATE_UNBOUND;
this.emit('error', ex);
// Todo: close?
@ -429,7 +430,7 @@ function doConnect(ex, self, ip, address, port, callback) {
if (!ex) {
const err = state.handle.connect(ip, port);
if (err) {
ex = exceptionWithHostPort(err, 'connect', address, port);
ex = new ExceptionWithHostPort(err, 'connect', address, port);
}
}
@ -457,7 +458,7 @@ Socket.prototype.disconnect = function() {
const err = state.handle.disconnect();
if (err)
throw errnoException(err, 'connect');
throw new ErrnoException(err, 'connect');
else
state.connectState = CONNECT_STATE_DISCONNECTED;
};
@ -714,14 +715,14 @@ function doSend(ex, self, ip, list, address, port, callback) {
if (err && callback) {
// Don't emit as error, dgram_legacy.js compatibility
const ex = exceptionWithHostPort(err, 'send', address, port);
const ex = new ExceptionWithHostPort(err, 'send', address, port);
process.nextTick(callback, ex);
}
}
function afterSend(err, sent) {
if (err) {
err = exceptionWithHostPort(err, 'send', this.address, this.port);
err = new ExceptionWithHostPort(err, 'send', this.address, this.port);
} else {
err = null;
}
@ -772,7 +773,7 @@ Socket.prototype.address = function() {
const out = {};
const err = this[kStateSymbol].handle.getsockname(out);
if (err) {
throw errnoException(err, 'getsockname');
throw new ErrnoException(err, 'getsockname');
}
return out;
@ -788,7 +789,7 @@ Socket.prototype.remoteAddress = function() {
const out = {};
const err = state.handle.getpeername(out);
if (err)
throw errnoException(err, 'getpeername');
throw new ErrnoException(err, 'getpeername');
return out;
};
@ -797,7 +798,7 @@ Socket.prototype.remoteAddress = function() {
Socket.prototype.setBroadcast = function(arg) {
const err = this[kStateSymbol].handle.setBroadcast(arg ? 1 : 0);
if (err) {
throw errnoException(err, 'setBroadcast');
throw new ErrnoException(err, 'setBroadcast');
}
};
@ -807,7 +808,7 @@ Socket.prototype.setTTL = function(ttl) {
const err = this[kStateSymbol].handle.setTTL(ttl);
if (err) {
throw errnoException(err, 'setTTL');
throw new ErrnoException(err, 'setTTL');
}
return ttl;
@ -819,7 +820,7 @@ Socket.prototype.setMulticastTTL = function(ttl) {
const err = this[kStateSymbol].handle.setMulticastTTL(ttl);
if (err) {
throw errnoException(err, 'setMulticastTTL');
throw new ErrnoException(err, 'setMulticastTTL');
}
return ttl;
@ -829,7 +830,7 @@ Socket.prototype.setMulticastTTL = function(ttl) {
Socket.prototype.setMulticastLoopback = function(arg) {
const err = this[kStateSymbol].handle.setMulticastLoopback(arg ? 1 : 0);
if (err) {
throw errnoException(err, 'setMulticastLoopback');
throw new ErrnoException(err, 'setMulticastLoopback');
}
return arg; // 0.4 compatibility
@ -842,7 +843,7 @@ Socket.prototype.setMulticastInterface = function(interfaceAddress) {
const err = this[kStateSymbol].handle.setMulticastInterface(interfaceAddress);
if (err) {
throw errnoException(err, 'setMulticastInterface');
throw new ErrnoException(err, 'setMulticastInterface');
}
};
@ -857,7 +858,7 @@ Socket.prototype.addMembership = function(multicastAddress,
const { handle } = this[kStateSymbol];
const err = handle.addMembership(multicastAddress, interfaceAddress);
if (err) {
throw errnoException(err, 'addMembership');
throw new ErrnoException(err, 'addMembership');
}
};
@ -873,7 +874,7 @@ Socket.prototype.dropMembership = function(multicastAddress,
const { handle } = this[kStateSymbol];
const err = handle.dropMembership(multicastAddress, interfaceAddress);
if (err) {
throw errnoException(err, 'dropMembership');
throw new ErrnoException(err, 'dropMembership');
}
};
@ -890,7 +891,7 @@ Socket.prototype.addSourceSpecificMembership = function(sourceAddress,
groupAddress,
interfaceAddress);
if (err) {
throw errnoException(err, 'addSourceSpecificMembership');
throw new ErrnoException(err, 'addSourceSpecificMembership');
}
};
@ -908,7 +909,7 @@ Socket.prototype.dropSourceSpecificMembership = function(sourceAddress,
groupAddress,
interfaceAddress);
if (err) {
throw errnoException(err, 'dropSourceSpecificMembership');
throw new ErrnoException(err, 'dropSourceSpecificMembership');
}
};
@ -935,7 +936,7 @@ function stopReceiving(socket) {
function onMessage(nread, handle, buf, rinfo) {
const self = handle[owner_symbol];
if (nread < 0) {
return self.emit('error', errnoException(nread, 'recvmsg'));
return self.emit('error', new ErrnoException(nread, 'recvmsg'));
}
rinfo.size = buf.length; // compatibility
self.emit('message', buf, rinfo);

View file

@ -30,7 +30,14 @@ const {
const cares = internalBinding('cares_wrap');
const { isIP } = require('internal/net');
const { customPromisifyArgs } = require('internal/util');
const errors = require('internal/errors');
const {
codes: {
ERR_INVALID_ARG_TYPE,
ERR_INVALID_ARG_VALUE,
ERR_MISSING_ARGS,
},
DNSException,
} = require('internal/errors');
const {
bindDefaultResolver,
setDefaultResolver,
@ -70,11 +77,6 @@ const {
ADDRGETNETWORKPARAMS,
CANCELLED,
} = dnsErrorCodes;
const {
ERR_INVALID_ARG_TYPE,
ERR_INVALID_ARG_VALUE,
ERR_MISSING_ARGS,
} = errors.codes;
const {
validateBoolean,
validateFunction,
@ -98,13 +100,11 @@ const {
stopPerf,
} = require('internal/perf/observe');
const dnsException = errors.dnsException;
let promises = null; // Lazy loaded
function onlookup(err, addresses) {
if (err) {
return this.callback(dnsException(err, 'getaddrinfo', this.hostname));
return this.callback(new DNSException(err, 'getaddrinfo', this.hostname));
}
this.callback(null, addresses[0], this.family || isIP(addresses[0]));
if (this[kPerfHooksDnsLookupContext] && hasObserver('dns')) {
@ -115,7 +115,7 @@ function onlookup(err, addresses) {
function onlookupall(err, addresses) {
if (err) {
return this.callback(dnsException(err, 'getaddrinfo', this.hostname));
return this.callback(new DNSException(err, 'getaddrinfo', this.hostname));
}
const family = this.family;
@ -222,7 +222,7 @@ function lookup(hostname, options, callback) {
req, hostname, family, hints, verbatim,
);
if (err) {
process.nextTick(callback, dnsException(err, 'getaddrinfo', hostname));
process.nextTick(callback, new DNSException(err, 'getaddrinfo', hostname));
return {};
}
if (hasObserver('dns')) {
@ -243,7 +243,7 @@ ObjectDefineProperty(lookup, customPromisifyArgs,
function onlookupservice(err, hostname, service) {
if (err)
return this.callback(dnsException(err, 'getnameinfo', this.hostname));
return this.callback(new DNSException(err, 'getnameinfo', this.hostname));
this.callback(null, hostname, service);
if (this[kPerfHooksDnsLookupServiceContext] && hasObserver('dns')) {
@ -272,7 +272,7 @@ function lookupService(address, port, callback) {
req.oncomplete = onlookupservice;
const err = cares.getnameinfo(req, address, port);
if (err) throw dnsException(err, 'getnameinfo', address);
if (err) throw new DNSException(err, 'getnameinfo', address);
if (hasObserver('dns')) {
startPerf(req, kPerfHooksDnsLookupServiceContext, {
type: 'dns',

View file

@ -73,7 +73,7 @@ const {
},
AbortError,
uvErrmapGet,
uvException,
UVException,
} = require('internal/errors');
const {
@ -402,7 +402,7 @@ function tryStatSync(fd, isUserFd) {
const stats = binding.fstat(fd, false, undefined, ctx);
if (ctx.errno !== undefined && !isUserFd) {
fs.closeSync(fd);
throw uvException(ctx);
throw new UVException(ctx);
}
return stats;
}

View file

@ -17,7 +17,7 @@ const {
} = primordials;
const {
errnoException,
ErrnoException,
codes: {
ERR_INVALID_ARG_TYPE,
ERR_INVALID_ARG_VALUE,
@ -283,7 +283,7 @@ function ChildProcess() {
if (exitCode < 0) {
const syscall = this.spawnfile ? 'spawn ' + this.spawnfile : 'spawn';
const err = errnoException(exitCode, syscall);
const err = new ErrnoException(exitCode, syscall);
if (this.spawnfile)
err.path = this.spawnfile;
@ -418,7 +418,7 @@ ChildProcess.prototype.spawn = function(options) {
this._handle.close();
this._handle = null;
throw errnoException(err, 'spawn');
throw new ErrnoException(err, 'spawn');
} else {
process.nextTick(onSpawnNT, this);
}
@ -506,10 +506,10 @@ ChildProcess.prototype.kill = function(sig) {
/* Already dead. */
} else if (err === UV_EINVAL || err === UV_ENOSYS) {
/* The underlying platform doesn't support this signal. */
throw errnoException(err, 'kill');
throw new ErrnoException(err, 'kill');
} else {
/* Other error, almost certainly EPERM. */
this.emit('error', errnoException(err, 'kill'));
this.emit('error', new ErrnoException(err, 'kill'));
}
}
@ -876,7 +876,7 @@ function setupChannel(target, channel, serializationMode) {
obj.postSend(message, handle, options, callback);
if (!options.swallowErrors) {
const ex = errnoException(err, 'write');
const ex = new ErrnoException(err, 'write');
if (typeof callback === 'function') {
process.nextTick(callback, ex);
} else {
@ -1121,7 +1121,7 @@ function spawnSync(options) {
result.stderr = result.output && result.output[2];
if (result.error) {
result.error = errnoException(result.error, 'spawnSync ' + options.file);
result.error = new ErrnoException(result.error, 'spawnSync ' + options.file);
result.error.path = options.file;
result.error.spawnargs = ArrayPrototypeSlice(options.args, 1);
}

View file

@ -49,15 +49,15 @@ const {
} = require('internal/errors');
const validateParameters = hideStackFrames((hash, key, salt, info, length) => {
validateString(hash, 'digest');
validateString.withoutStackTrace(hash, 'digest');
key = prepareKey(key);
salt = validateByteSource(salt, 'salt');
info = validateByteSource(info, 'info');
salt = validateByteSource.withoutStackTrace(salt, 'salt');
info = validateByteSource.withoutStackTrace(info, 'info');
validateInteger(length, 'length', 0, kMaxLength);
validateInteger.withoutStackTrace(length, 'length', 0, kMaxLength);
if (info.byteLength > 1024) {
throw new ERR_OUT_OF_RANGE(
throw new ERR_OUT_OF_RANGE.HideStackFramesError(
'info',
'must not contain more than 1024 bytes',
info.byteLength);

View file

@ -116,7 +116,7 @@ const getArrayBufferOrView = hideStackFrames((buffer, name, encoding) => {
return Buffer.from(buffer, encoding);
}
if (!isArrayBufferView(buffer)) {
throw new ERR_INVALID_ARG_TYPE(
throw new ERR_INVALID_ARG_TYPE.HideStackFramesError(
name,
[
'string',
@ -403,7 +403,7 @@ const validateByteSource = hideStackFrames((val, name) => {
if (isAnyArrayBuffer(val) || isArrayBufferView(val))
return val;
throw new ERR_INVALID_ARG_TYPE(
throw new ERR_INVALID_ARG_TYPE.HideStackFramesError(
name,
[
'string',

View file

@ -12,7 +12,7 @@ const {
ERR_INVALID_ARG_TYPE,
ERR_INVALID_ARG_VALUE,
},
dnsException,
DNSException,
} = require('internal/errors');
const {
@ -42,7 +42,7 @@ function onresolve(err, result, ttls) {
result, (address, index) => ({ address, ttl: ttls[index] }));
if (err)
this.callback(dnsException(err, this.bindingName, this.hostname));
this.callback(new DNSException(err, this.bindingName, this.hostname));
else {
this.callback(null, result);
if (this[kPerfHooksDnsLookupResolveContext] && hasObserver('dns')) {
@ -69,7 +69,7 @@ function resolver(bindingName) {
req.oncomplete = onresolve;
req.ttl = !!(options && options.ttl);
const err = this._handle[bindingName](req, name);
if (err) throw dnsException(err, bindingName, name);
if (err) throw new DNSException(err, bindingName, name);
if (hasObserver('dns')) {
startPerf(req, kPerfHooksDnsLookupResolveContext, {
type: 'dns',

View file

@ -45,7 +45,7 @@ const {
ADDRGETNETWORKPARAMS,
CANCELLED,
} = dnsErrorCodes;
const { codes, dnsException } = require('internal/errors');
const { codes, DNSException } = require('internal/errors');
const { isIP } = require('internal/net');
const {
getaddrinfo,
@ -79,7 +79,7 @@ const {
function onlookup(err, addresses) {
if (err) {
this.reject(dnsException(err, 'getaddrinfo', this.hostname));
this.reject(new DNSException(err, 'getaddrinfo', this.hostname));
return;
}
@ -92,7 +92,7 @@ function onlookup(err, addresses) {
function onlookupall(err, addresses) {
if (err) {
this.reject(dnsException(err, 'getaddrinfo', this.hostname));
this.reject(new DNSException(err, 'getaddrinfo', this.hostname));
return;
}
@ -153,7 +153,7 @@ function createLookupPromise(family, hostname, all, hints, verbatim) {
const err = getaddrinfo(req, hostname, family, hints, verbatim);
if (err) {
reject(dnsException(err, 'getaddrinfo', hostname));
reject(new DNSException(err, 'getaddrinfo', hostname));
} else if (hasObserver('dns')) {
const detail = {
hostname,
@ -220,7 +220,7 @@ function lookup(hostname, options) {
function onlookupservice(err, hostname, service) {
if (err) {
this.reject(dnsException(err, 'getnameinfo', this.host));
this.reject(new DNSException(err, 'getnameinfo', this.host));
return;
}
@ -243,7 +243,7 @@ function createLookupServicePromise(hostname, port) {
const err = getnameinfo(req, hostname, port);
if (err)
reject(dnsException(err, 'getnameinfo', hostname));
reject(new DNSException(err, 'getnameinfo', hostname));
else if (hasObserver('dns')) {
startPerf(req, kPerfHooksDnsLookupServiceContext, {
type: 'dns',
@ -272,7 +272,7 @@ function lookupService(address, port) {
function onresolve(err, result, ttls) {
if (err) {
this.reject(dnsException(err, this.bindingName, this.hostname));
this.reject(new DNSException(err, this.bindingName, this.hostname));
return;
}
@ -300,7 +300,7 @@ function createResolverPromise(resolver, bindingName, hostname, ttl) {
const err = resolver._handle[bindingName](req, hostname);
if (err)
reject(dnsException(err, bindingName, hostname));
reject(new DNSException(err, bindingName, hostname));
else if (hasObserver('dns')) {
startPerf(req, kPerfHooksDnsLookupResolveContext, {
type: 'dns',

View file

@ -86,8 +86,7 @@ const kTypes = [
const MainContextError = Error;
const overrideStackTrace = new SafeWeakMap();
const kNoOverride = Symbol('kNoOverride');
let userStackTraceLimit;
const nodeInternalPrefix = '__node_internal_';
const prepareStackTrace = (globalThis, error, trace) => {
// API for node internals to override error stack formatting
// without interfering with userland code.
@ -97,21 +96,6 @@ const prepareStackTrace = (globalThis, error, trace) => {
return f(error, trace);
}
const firstFrame = trace[0]?.getFunctionName();
if (firstFrame && StringPrototypeStartsWith(firstFrame, nodeInternalPrefix)) {
for (let l = trace.length - 1; l >= 0; l--) {
const fn = trace[l]?.getFunctionName();
if (fn && StringPrototypeStartsWith(fn, nodeInternalPrefix)) {
ArrayPrototypeSplice(trace, 0, l + 1);
break;
}
}
// `userStackTraceLimit` is the user value for `Error.stackTraceLimit`,
// it is updated at every new exception in `captureLargerStackTrace`.
if (trace.length > userStackTraceLimit)
ArrayPrototypeSplice(trace, userStackTraceLimit);
}
const globalOverride =
maybeOverridePrepareStackTrace(globalThis, error, trace);
if (globalOverride !== kNoOverride) return globalOverride;
@ -151,30 +135,51 @@ const maybeOverridePrepareStackTrace = (globalThis, error, trace) => {
return kNoOverride;
};
const aggregateTwoErrors = hideStackFrames((innerError, outerError) => {
const aggregateTwoErrors = (innerError, outerError) => {
if (innerError && outerError && innerError !== outerError) {
if (ArrayIsArray(outerError.errors)) {
// If `outerError` is already an `AggregateError`.
ArrayPrototypePush(outerError.errors, innerError);
return outerError;
}
// eslint-disable-next-line no-restricted-syntax
const err = new AggregateError(new SafeArrayIterator([
outerError,
innerError,
]), outerError.message);
let err;
if (isErrorStackTraceLimitWritable()) {
const limit = Error.stackTraceLimit;
Error.stackTraceLimit = 0;
// eslint-disable-next-line no-restricted-syntax
err = new AggregateError(new SafeArrayIterator([
outerError,
innerError,
]), outerError.message);
Error.stackTraceLimit = limit;
ErrorCaptureStackTrace(err, aggregateTwoErrors);
} else {
// eslint-disable-next-line no-restricted-syntax
err = new AggregateError(new SafeArrayIterator([
outerError,
innerError,
]), outerError.message);
}
err.code = outerError.code;
return err;
}
return innerError || outerError;
});
};
const aggregateErrors = hideStackFrames((errors, message, code) => {
// eslint-disable-next-line no-restricted-syntax
const err = new AggregateError(new SafeArrayIterator(errors), message);
err.code = errors[0]?.code;
return err;
});
class NodeAggregateError extends AggregateError {
constructor(errors, message) {
super(new SafeArrayIterator(errors), message);
this.code = errors[0]?.code;
}
get [kIsNodeError]() {
return true;
}
get ['constructor']() {
return AggregateError;
}
}
const assert = require('internal/assert');
@ -242,11 +247,7 @@ function inspectWithNoCustomRetry(obj, options) {
// and may have .path and .dest.
class SystemError extends Error {
constructor(key, context) {
const limit = Error.stackTraceLimit;
if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = 0;
super();
// Reset the limit and setting the name property.
if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = limit;
const prefix = getMessage(key, [], this);
let message = `${prefix}: ${context.syscall} returned ` +
`${context.code} (${context.message})`;
@ -256,8 +257,6 @@ class SystemError extends Error {
if (context.dest !== undefined)
message += ` => ${context.dest}`;
captureLargerStackTrace(this);
this.code = key;
ObjectDefineProperties(this, {
@ -372,6 +371,33 @@ function makeSystemErrorWithCode(key) {
};
}
// This is a special error type that is only used for the E function.
class HideStackFramesError extends Error {
}
function makeNodeErrorForHideStackFrame(Base, clazz) {
class HideStackFramesError extends Base {
constructor(...args) {
if (isErrorStackTraceLimitWritable()) {
const limit = Error.stackTraceLimit;
Error.stackTraceLimit = 0;
super(...args);
Error.stackTraceLimit = limit;
} else {
super(...args);
}
}
// This is a workaround for wpt tests that expect that the error
// constructor has a `name` property of the base class.
get ['constructor']() {
return clazz;
}
}
return HideStackFramesError;
}
function makeNodeErrorWithCode(Base, key) {
const msg = messages.get(key);
const expectedLength = typeof msg !== 'string' ? -1 : getExpectedArgumentLength(msg);
@ -479,11 +505,16 @@ function makeNodeErrorWithCode(Base, key) {
* @returns {T}
*/
function hideStackFrames(fn) {
// We rename the functions that will be hidden to cut off the stacktrace
// at the outermost one
const hidden = nodeInternalPrefix + fn.name;
ObjectDefineProperty(fn, 'name', { __proto__: null, value: hidden });
return fn;
function wrappedFn(...args) {
try {
return ReflectApply(fn, this, args);
} catch (error) {
Error.stackTraceLimit && ErrorCaptureStackTrace(error, wrappedFn);
throw error;
}
}
wrappedFn.withoutStackTrace = fn;
return wrappedFn;
}
// Utility function for registering the error codes. Only used here. Exported
@ -492,18 +523,33 @@ function E(sym, val, def, ...otherClasses) {
// Special case for SystemError that formats the error message differently
// The SystemErrors only have SystemError as their base classes.
messages.set(sym, val);
if (def === SystemError) {
def = makeSystemErrorWithCode(sym);
} else {
def = makeNodeErrorWithCode(def, sym);
}
const ErrClass = def === SystemError ?
makeSystemErrorWithCode(sym) :
makeNodeErrorWithCode(def, sym);
if (otherClasses.length !== 0) {
otherClasses.forEach((clazz) => {
def[clazz.name] = makeNodeErrorWithCode(clazz, sym);
});
if (otherClasses.includes(HideStackFramesError)) {
if (otherClasses.length !== 1) {
otherClasses.forEach((clazz) => {
if (clazz !== HideStackFramesError) {
ErrClass[clazz.name] = makeNodeErrorWithCode(clazz, sym);
ErrClass[clazz.name].HideStackFramesError = makeNodeErrorForHideStackFrame(ErrClass[clazz.name], clazz);
}
});
}
} else {
otherClasses.forEach((clazz) => {
ErrClass[clazz.name] = makeNodeErrorWithCode(clazz, sym);
});
}
}
codes[sym] = def;
if (otherClasses.includes(HideStackFramesError)) {
ErrClass.HideStackFramesError = makeNodeErrorForHideStackFrame(ErrClass, def);
}
codes[sym] = ErrClass;
}
function getExpectedArgumentLength(msg) {
@ -553,84 +599,67 @@ function uvErrmapGet(name) {
return MapPrototypeGet(uvBinding.errmap, name);
}
const captureLargerStackTrace = hideStackFrames(
function captureLargerStackTrace(err) {
const stackTraceLimitIsWritable = isErrorStackTraceLimitWritable();
if (stackTraceLimitIsWritable) {
userStackTraceLimit = Error.stackTraceLimit;
Error.stackTraceLimit = Infinity;
}
ErrorCaptureStackTrace(err);
// Reset the limit
if (stackTraceLimitIsWritable) Error.stackTraceLimit = userStackTraceLimit;
return err;
});
/**
* This creates an error compatible with errors produced in the C++
* function UVException using a context object with data assembled in C++.
* The goal is to migrate them to ERR_* errors later when compatibility is
* not a concern.
* @param {object} ctx
* @returns {Error}
*/
const uvException = hideStackFrames(function uvException(ctx) {
const { 0: code, 1: uvmsg } = uvErrmapGet(ctx.errno) || uvUnmappedError;
let message = `${code}: ${ctx.message || uvmsg}, ${ctx.syscall}`;
class UVException extends Error {
/**
* @param {object} ctx
*/
constructor(ctx) {
const { 0: code, 1: uvmsg } = uvErrmapGet(ctx.errno) || uvUnmappedError;
let message = `${code}: ${ctx.message || uvmsg}, ${ctx.syscall}`;
let path;
let dest;
if (ctx.path) {
path = ctx.path.toString();
message += ` '${path}'`;
}
if (ctx.dest) {
dest = ctx.dest.toString();
message += ` -> '${dest}'`;
}
// Reducing the limit improves the performance significantly. We do not lose
// the stack frames due to the `captureStackTrace()` function that is called
// later.
const tmpLimit = Error.stackTraceLimit;
if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = 0;
// Pass the message to the constructor instead of setting it on the object
// to make sure it is the same as the one created in C++
// eslint-disable-next-line no-restricted-syntax
const err = new Error(message);
if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = tmpLimit;
for (const prop of ObjectKeys(ctx)) {
if (prop === 'message' || prop === 'path' || prop === 'dest') {
continue;
let path;
let dest;
if (ctx.path) {
path = ctx.path.toString();
message += ` '${path}'`;
}
if (ctx.dest) {
dest = ctx.dest.toString();
message += ` -> '${dest}'`;
}
super(message);
for (const prop of ObjectKeys(ctx)) {
if (prop === 'message' || prop === 'path' || prop === 'dest') {
continue;
}
this[prop] = ctx[prop];
}
this.code = code;
if (path) {
this.path = path;
}
if (dest) {
this.dest = dest;
}
err[prop] = ctx[prop];
}
err.code = code;
if (path) {
err.path = path;
get ['constructor']() {
return Error;
}
if (dest) {
err.dest = dest;
}
return captureLargerStackTrace(err);
});
}
/**
* This creates an error compatible with errors produced in the C++
* This function should replace the deprecated
* `exceptionWithHostPort()` function.
* @param {number} err - A libuv error number
* @param {string} syscall
* @param {string} address
* @param {number} [port]
* @returns {Error}
*/
const uvExceptionWithHostPort = hideStackFrames(
function uvExceptionWithHostPort(err, syscall, address, port) {
class UVExceptionWithHostPort extends Error {
/**
* @param {number} err - A libuv error number
* @param {string} syscall
* @param {string} address
* @param {number} [port]
*/
constructor(err, syscall, address, port) {
const { 0: code, 1: uvmsg } = uvErrmapGet(err) || uvUnmappedError;
const message = `${syscall} ${code}: ${uvmsg}`;
let details = '';
@ -641,34 +670,32 @@ const uvExceptionWithHostPort = hideStackFrames(
details = ` ${address}`;
}
// Reducing the limit improves the performance significantly. We do not
// lose the stack frames due to the `captureStackTrace()` function that
// is called later.
const tmpLimit = Error.stackTraceLimit;
if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = 0;
// eslint-disable-next-line no-restricted-syntax
const ex = new Error(`${message}${details}`);
if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = tmpLimit;
ex.code = code;
ex.errno = err;
ex.syscall = syscall;
ex.address = address;
if (port) {
ex.port = port;
}
super(`${message}${details}`);
return captureLargerStackTrace(ex);
});
this.code = code;
this.errno = err;
this.syscall = syscall;
this.address = address;
if (port) {
this.port = port;
}
}
get ['constructor']() {
return Error;
}
}
/**
* This used to be util._errnoException().
* @param {number} err - A libuv error number
* @param {string} syscall
* @param {string} [original]
* @returns {Error}
*/
const errnoException = hideStackFrames(
function errnoException(err, syscall, original) {
class ErrnoException extends Error {
/**
* @param {number} err - A libuv error number
* @param {string} syscall
* @param {string} [original] err
*/
constructor(err, syscall, original) {
// TODO(joyeecheung): We have to use the type-checked
// getSystemErrorName(err) to guard against invalid arguments from users.
// This can be replaced with [ code ] = errmap.get(err) when this method
@ -678,20 +705,20 @@ const errnoException = hideStackFrames(
const message = original ?
`${syscall} ${code} ${original}` : `${syscall} ${code}`;
const tmpLimit = Error.stackTraceLimit;
if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = 0;
// eslint-disable-next-line no-restricted-syntax
const ex = new Error(message);
if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = tmpLimit;
ex.errno = err;
ex.code = code;
ex.syscall = syscall;
super(message);
return captureLargerStackTrace(ex);
});
this.errno = err;
this.code = code;
this.syscall = syscall;
}
get ['constructor']() {
return Error;
}
}
/**
* Deprecated, new function is `uvExceptionWithHostPort()`
* Deprecated, new Error is `UVExceptionWithHostPort()`
* New function added the error description directly
* from C++. this method for backwards compatibility
* @param {number} err - A libuv error number
@ -701,8 +728,8 @@ const errnoException = hideStackFrames(
* @param {string} [additional]
* @returns {Error}
*/
const exceptionWithHostPort = hideStackFrames(
function exceptionWithHostPort(err, syscall, address, port, additional) {
class ExceptionWithHostPort extends Error {
constructor(err, syscall, address, port, additional) {
// TODO(joyeecheung): We have to use the type-checked
// getSystemErrorName(err) to guard against invalid arguments from users.
// This can be replaced with [ code ] = errmap.get(err) when this method
@ -719,78 +746,75 @@ const exceptionWithHostPort = hideStackFrames(
details += ` - Local (${additional})`;
}
// Reducing the limit improves the performance significantly. We do not
// lose the stack frames due to the `captureStackTrace()` function that
// is called later.
const tmpLimit = Error.stackTraceLimit;
if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = 0;
// eslint-disable-next-line no-restricted-syntax
const ex = new Error(`${syscall} ${code}${details}`);
if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = tmpLimit;
ex.errno = err;
ex.code = code;
ex.syscall = syscall;
ex.address = address;
super(`${syscall} ${code}${details}`);
this.errno = err;
this.code = code;
this.syscall = syscall;
this.address = address;
if (port) {
ex.port = port;
}
return captureLargerStackTrace(ex);
});
/**
* @param {number|string} code - A libuv error number or a c-ares error code
* @param {string} syscall
* @param {string} [hostname]
* @returns {Error}
*/
const dnsException = hideStackFrames(function(code, syscall, hostname) {
let errno;
// If `code` is of type number, it is a libuv error number, else it is a
// c-ares error code.
// TODO(joyeecheung): translate c-ares error codes into numeric ones and
// make them available in a property that's not error.errno (since they
// can be in conflict with libuv error codes). Also make sure
// util.getSystemErrorName() can understand them when an being informed that
// the number is a c-ares error code.
if (typeof code === 'number') {
errno = code;
// ENOTFOUND is not a proper POSIX error, but this error has been in place
// long enough that it's not practical to remove it.
if (code === lazyUv().UV_EAI_NODATA || code === lazyUv().UV_EAI_NONAME) {
code = 'ENOTFOUND'; // Fabricated error name.
} else {
code = lazyInternalUtil().getSystemErrorName(code);
this.port = port;
}
}
const message = `${syscall} ${code}${hostname ? ` ${hostname}` : ''}`;
// Reducing the limit improves the performance significantly. We do not lose
// the stack frames due to the `captureStackTrace()` function that is called
// later.
const tmpLimit = Error.stackTraceLimit;
if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = 0;
// eslint-disable-next-line no-restricted-syntax
const ex = new Error(message);
if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = tmpLimit;
ex.errno = errno;
ex.code = code;
ex.syscall = syscall;
if (hostname) {
ex.hostname = hostname;
get ['constructor']() {
return Error;
}
}
class DNSException extends Error {
/**
* @param {number|string} code - A libuv error number or a c-ares error code
* @param {string} syscall
* @param {string} [hostname]
*/
constructor(code, syscall, hostname) {
let errno;
// If `code` is of type number, it is a libuv error number, else it is a
// c-ares error code.
// TODO(joyeecheung): translate c-ares error codes into numeric ones and
// make them available in a property that's not error.errno (since they
// can be in conflict with libuv error codes). Also make sure
// util.getSystemErrorName() can understand them when an being informed that
// the number is a c-ares error code.
if (typeof code === 'number') {
errno = code;
// ENOTFOUND is not a proper POSIX error, but this error has been in place
// long enough that it's not practical to remove it.
if (code === lazyUv().UV_EAI_NODATA || code === lazyUv().UV_EAI_NONAME) {
code = 'ENOTFOUND'; // Fabricated error name.
} else {
code = lazyInternalUtil().getSystemErrorName(code);
}
}
super(`${syscall} ${code}${hostname ? ` ${hostname}` : ''}`);
this.errno = errno;
this.code = code;
this.syscall = syscall;
if (hostname) {
this.hostname = hostname;
}
}
return captureLargerStackTrace(ex);
});
get ['constructor']() {
return Error;
}
}
function connResetException(msg) {
// eslint-disable-next-line no-restricted-syntax
const ex = new Error(msg);
ex.code = 'ECONNRESET';
return ex;
class ConnResetException extends Error {
constructor(msg) {
super(msg);
this.code = 'ECONNRESET';
}
get ['constructor']() {
return Error;
}
}
let maxStack_ErrorName;
let maxStack_ErrorMessage;
/**
* Returns true if `err.name` and `err.message` are equal to engine-specific
* values indicating max call stack size has been exceeded.
@ -1011,16 +1035,15 @@ function formatList(array, type = 'and') {
module.exports = {
AbortError,
aggregateTwoErrors,
aggregateErrors,
captureLargerStackTrace,
NodeAggregateError,
codes,
connResetException,
dnsException,
ConnResetException,
DNSException,
// This is exported only to facilitate testing.
determineSpecificType,
E,
errnoException,
exceptionWithHostPort,
ErrnoException,
ExceptionWithHostPort,
fatalExceptionStackEnhancers,
formatList,
genericNodeError,
@ -1039,8 +1062,8 @@ module.exports = {
setArrowMessage,
SystemError,
uvErrmapGet,
uvException,
uvExceptionWithHostPort,
UVException,
UVExceptionWithHostPort,
};
// To declare an error message, use the E(sym, val, def) function above. The sym
@ -1147,7 +1170,7 @@ E('ERR_EVENT_RECURSION', 'The event "%s" is already being dispatched', Error);
E('ERR_FALSY_VALUE_REJECTION', function(reason) {
this.reason = reason;
return 'Promise was rejected with falsy value';
}, Error);
}, Error, HideStackFramesError);
E('ERR_FEATURE_UNAVAILABLE_ON_PLATFORM',
'The feature %s is unavailable on the current platform' +
', which is being used to run Node.js',
@ -1163,7 +1186,7 @@ E('ERR_FS_CP_SOCKET', 'Cannot copy a socket file', SystemError);
E('ERR_FS_CP_SYMLINK_TO_SUBDIRECTORY',
'Cannot overwrite symlink in subdirectory of self', SystemError);
E('ERR_FS_CP_UNKNOWN', 'Cannot copy an unknown file type', SystemError);
E('ERR_FS_EISDIR', 'Path is a directory', SystemError);
E('ERR_FS_EISDIR', 'Path is a directory', SystemError, HideStackFramesError);
E('ERR_FS_FILE_TOO_LARGE', 'File size (%s) is greater than 2 GiB', RangeError);
E('ERR_FS_INVALID_SYMLINK_TYPE',
'Symlink type must be one of "dir", "file", or "junction". Received "%s"',
@ -1190,7 +1213,7 @@ E('ERR_HTTP2_INFO_STATUS_NOT_ALLOWED',
E('ERR_HTTP2_INVALID_CONNECTION_HEADERS',
'HTTP/1 Connection specific headers are forbidden: "%s"', TypeError);
E('ERR_HTTP2_INVALID_HEADER_VALUE',
'Invalid value "%s" for header "%s"', TypeError);
'Invalid value "%s" for header "%s"', TypeError, HideStackFramesError);
E('ERR_HTTP2_INVALID_INFO_STATUS',
'Invalid informational status code: %s', RangeError);
E('ERR_HTTP2_INVALID_ORIGIN',
@ -1198,7 +1221,7 @@ E('ERR_HTTP2_INVALID_ORIGIN',
E('ERR_HTTP2_INVALID_PACKED_SETTINGS_LENGTH',
'Packed settings length must be a multiple of six', RangeError);
E('ERR_HTTP2_INVALID_PSEUDOHEADER',
'"%s" is an invalid pseudoheader or is used incorrectly', TypeError);
'"%s" is an invalid pseudoheader or is used incorrectly', TypeError, HideStackFramesError);
E('ERR_HTTP2_INVALID_SESSION', 'The session has been destroyed', Error);
E('ERR_HTTP2_INVALID_SETTING_VALUE',
// Using default arguments here is important so the arguments are not counted
@ -1210,7 +1233,7 @@ E('ERR_HTTP2_INVALID_SETTING_VALUE',
this.max = max;
}
return `Invalid value for setting "${name}": ${actual}`;
}, TypeError, RangeError);
}, TypeError, RangeError, HideStackFramesError);
E('ERR_HTTP2_INVALID_STREAM', 'The stream has been destroyed', Error);
E('ERR_HTTP2_MAX_PENDING_SETTINGS_ACK',
'Maximum number of pending settings acknowledgements', Error);
@ -1230,7 +1253,7 @@ E('ERR_HTTP2_PAYLOAD_FORBIDDEN',
E('ERR_HTTP2_PING_CANCEL', 'HTTP2 ping cancelled', Error);
E('ERR_HTTP2_PING_LENGTH', 'HTTP2 ping payload must be 8 bytes', RangeError);
E('ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED',
'Cannot set HTTP/2 pseudo-headers', TypeError);
'Cannot set HTTP/2 pseudo-headers', TypeError, HideStackFramesError);
E('ERR_HTTP2_PUSH_DISABLED', 'HTTP/2 client has disabled push streams', Error);
E('ERR_HTTP2_SEND_FILE', 'Directories cannot be sent', Error);
E('ERR_HTTP2_SEND_FILE_NOSEEK',
@ -1270,7 +1293,7 @@ E('ERR_HTTP_CONTENT_LENGTH_MISMATCH',
E('ERR_HTTP_HEADERS_SENT',
'Cannot %s headers after they are sent to the client', Error);
E('ERR_HTTP_INVALID_HEADER_VALUE',
'Invalid value "%s" for header "%s"', TypeError);
'Invalid value "%s" for header "%s"', TypeError, HideStackFramesError);
E('ERR_HTTP_INVALID_STATUS_CODE', 'Invalid status code: %s', RangeError);
E('ERR_HTTP_REQUEST_TIMEOUT', 'Request timeout', Error);
E('ERR_HTTP_SOCKET_ASSIGNED',
@ -1287,7 +1310,7 @@ E('ERR_IMPORT_ATTRIBUTE_TYPE_INCOMPATIBLE',
E('ERR_IMPORT_ATTRIBUTE_UNSUPPORTED',
'Import attribute "%s" with value "%s" is not supported', TypeError);
E('ERR_INCOMPATIBLE_OPTION_PAIR',
'Option "%s" cannot be used in combination with option "%s"', TypeError);
'Option "%s" cannot be used in combination with option "%s"', TypeError, HideStackFramesError);
E('ERR_INPUT_TYPE_NOT_ALLOWED', '--input-type can only be used with string ' +
'input via --eval, --print, or STDIN', Error);
E('ERR_INSPECTOR_ALREADY_ACTIVATED',
@ -1383,7 +1406,7 @@ E('ERR_INVALID_ARG_TYPE',
msg += `. Received ${determineSpecificType(actual)}`;
return msg;
}, TypeError);
}, TypeError, HideStackFramesError);
E('ERR_INVALID_ARG_VALUE', (name, value, reason = 'is invalid') => {
let inspected = lazyInternalUtilInspect().inspect(value);
if (inspected.length > 128) {
@ -1391,7 +1414,7 @@ E('ERR_INVALID_ARG_VALUE', (name, value, reason = 'is invalid') => {
}
const type = StringPrototypeIncludes(name, '.') ? 'property' : 'argument';
return `The ${type} '${name}' ${reason}. Received ${inspected}`;
}, TypeError, RangeError);
}, TypeError, RangeError, HideStackFramesError);
E('ERR_INVALID_ASYNC_ID', 'Invalid %s value: %s', RangeError);
E('ERR_INVALID_BUFFER_SIZE',
'Buffer size must be a multiple of %s', RangeError);
@ -1404,7 +1427,7 @@ E('ERR_INVALID_CHAR',
msg += ` ["${field}"]`;
}
return msg;
}, TypeError);
}, TypeError, HideStackFramesError);
E('ERR_INVALID_CURSOR_POS',
'Cannot set cursor row without setting its column', TypeError);
E('ERR_INVALID_FD',
@ -1414,7 +1437,7 @@ E('ERR_INVALID_FILE_URL_HOST',
'File URL host must be "localhost" or empty on %s', TypeError);
E('ERR_INVALID_FILE_URL_PATH', 'File URL path %s', TypeError);
E('ERR_INVALID_HANDLE_TYPE', 'This handle type cannot be sent', TypeError);
E('ERR_INVALID_HTTP_TOKEN', '%s must be a valid HTTP token ["%s"]', TypeError);
E('ERR_INVALID_HTTP_TOKEN', '%s must be a valid HTTP token ["%s"]', TypeError, HideStackFramesError);
E('ERR_INVALID_IP_ADDRESS', 'Invalid IP address: %s', TypeError);
E('ERR_INVALID_MIME_SYNTAX', (production, str, invalidIndex) => {
const msg = invalidIndex !== -1 ? ` at ${invalidIndex}` : '';
@ -1603,7 +1626,7 @@ E('ERR_OUT_OF_RANGE',
}
msg += ` It must be ${range}. Received ${received}`;
return msg;
}, RangeError);
}, RangeError, HideStackFramesError);
E('ERR_PACKAGE_IMPORT_NOT_DEFINED', (specifier, packagePath, base) => {
return `Package import specifier "${specifier}" is not defined${packagePath ?
` in package ${packagePath}package.json` : ''} imported from ${base}`;
@ -1669,7 +1692,7 @@ E('ERR_SOCKET_BAD_PORT', (name, port, allowZero = true) => {
"The 'allowZero' argument must be of type boolean.");
const operator = allowZero ? '>=' : '>';
return `${name} should be ${operator} 0 and < 65536. Received ${determineSpecificType(port)}.`;
}, RangeError);
}, RangeError, HideStackFramesError);
E('ERR_SOCKET_BAD_TYPE',
'Bad socket type specified. Valid types are: udp4, udp6', TypeError);
E('ERR_SOCKET_BUFFER_SIZE',
@ -1700,7 +1723,7 @@ E('ERR_STREAM_UNSHIFT_AFTER_END_EVENT',
E('ERR_STREAM_WRAP', 'Stream has StringDecoder set or is in objectMode', Error);
E('ERR_STREAM_WRITE_AFTER_END', 'write after end', Error);
E('ERR_SYNTHETIC', 'JavaScript Callstack', Error);
E('ERR_SYSTEM_ERROR', 'A system error occurred', SystemError);
E('ERR_SYSTEM_ERROR', 'A system error occurred', SystemError, HideStackFramesError);
E('ERR_TAP_LEXER_ERROR', function(errorMsg) {
hideInternalStackFrames(this);
return errorMsg;
@ -1794,7 +1817,7 @@ E('ERR_UNKNOWN_ENCODING', 'Unknown encoding: %s', TypeError);
E('ERR_UNKNOWN_FILE_EXTENSION', 'Unknown file extension "%s" for %s', TypeError);
E('ERR_UNKNOWN_MODULE_FORMAT', 'Unknown module format: %s for URL %s',
RangeError);
E('ERR_UNKNOWN_SIGNAL', 'Unknown signal: %s', TypeError);
E('ERR_UNKNOWN_SIGNAL', 'Unknown signal: %s', TypeError, HideStackFramesError);
E('ERR_UNSUPPORTED_DIR_IMPORT', function(path, base, exactUrl) {
lazyInternalUtil().setOwnProperty(this, 'url', exactUrl);
return `Directory import '${path}' is not supported ` +

View file

@ -38,7 +38,7 @@ const {
ERR_OUT_OF_RANGE,
},
hideStackFrames,
uvException,
UVException,
} = require('internal/errors');
const {
isArrayBufferView,
@ -348,7 +348,7 @@ function getOptions(options, defaultOptions = kEmptyObject) {
*/
function handleErrorFromBinding(ctx) {
if (ctx.errno !== undefined) { // libuv error numbers
const err = uvException(ctx);
const err = new UVException(ctx);
ErrorCaptureStackTrace(err, handleErrorFromBinding);
throw err;
}
@ -361,30 +361,6 @@ function handleErrorFromBinding(ctx) {
}
}
// Check if the path contains null types if it is a string nor Uint8Array,
// otherwise return silently.
const nullCheck = hideStackFrames((path, propName, throwError = true) => {
const pathIsString = typeof path === 'string';
const pathIsUint8Array = isUint8Array(path);
// We can only perform meaningful checks on strings and Uint8Arrays.
if ((!pathIsString && !pathIsUint8Array) ||
(pathIsString && !StringPrototypeIncludes(path, '\u0000')) ||
(pathIsUint8Array && !TypedArrayPrototypeIncludes(path, 0))) {
return;
}
const err = new ERR_INVALID_ARG_VALUE(
propName,
path,
'must be a string, Uint8Array, or URL without null bytes',
);
if (throwError) {
throw err;
}
return err;
});
function preprocessSymlinkDestination(path, type, linkPath) {
if (!isWindows) {
// No preprocessing is needed on Unix.
@ -664,14 +640,14 @@ function toUnixTimestamp(time, name = 'time') {
const validateOffsetLengthRead = hideStackFrames(
(offset, length, bufferLength) => {
if (offset < 0) {
throw new ERR_OUT_OF_RANGE('offset', '>= 0', offset);
throw new ERR_OUT_OF_RANGE.HideStackFramesError('offset', '>= 0', offset);
}
if (length < 0) {
throw new ERR_OUT_OF_RANGE('length', '>= 0', length);
throw new ERR_OUT_OF_RANGE.HideStackFramesError('length', '>= 0', length);
}
if (offset + length > bufferLength) {
throw new ERR_OUT_OF_RANGE('length',
`<= ${bufferLength - offset}`, length);
throw new ERR_OUT_OF_RANGE.HideStackFramesError('length',
`<= ${bufferLength - offset}`, length);
}
},
);
@ -679,31 +655,41 @@ const validateOffsetLengthRead = hideStackFrames(
const validateOffsetLengthWrite = hideStackFrames(
(offset, length, byteLength) => {
if (offset > byteLength) {
throw new ERR_OUT_OF_RANGE('offset', `<= ${byteLength}`, offset);
throw new ERR_OUT_OF_RANGE.HideStackFramesError('offset', `<= ${byteLength}`, offset);
}
if (length > byteLength - offset) {
throw new ERR_OUT_OF_RANGE('length', `<= ${byteLength - offset}`, length);
throw new ERR_OUT_OF_RANGE.HideStackFramesError('length', `<= ${byteLength - offset}`, length);
}
if (length < 0) {
throw new ERR_OUT_OF_RANGE('length', '>= 0', length);
throw new ERR_OUT_OF_RANGE.HideStackFramesError('length', '>= 0', length);
}
validateInt32(length, 'length', 0);
validateInt32.withoutStackTrace(length, 'length', 0);
},
);
const validatePath = hideStackFrames((path, propName = 'path') => {
if (typeof path !== 'string' && !isUint8Array(path)) {
throw new ERR_INVALID_ARG_TYPE(propName, ['string', 'Buffer', 'URL'], path);
throw new ERR_INVALID_ARG_TYPE.HideStackFramesError(propName, ['string', 'Buffer', 'URL'], path);
}
const err = nullCheck(path, propName, false);
const pathIsString = typeof path === 'string';
const pathIsUint8Array = isUint8Array(path);
if (err !== undefined) {
throw err;
// We can only perform meaningful checks on strings and Uint8Arrays.
if ((!pathIsString && !pathIsUint8Array) ||
(pathIsString && !StringPrototypeIncludes(path, '\u0000')) ||
(pathIsUint8Array && !TypedArrayPrototypeIncludes(path, 0))) {
return;
}
throw new ERR_INVALID_ARG_VALUE.HideStackFramesError(
propName,
path,
'must be a string, Uint8Array, or URL without null bytes',
);
});
// TODO(rafaelgss): implement the path.resolve on C++ side
@ -742,11 +728,11 @@ const getValidatedFd = hideStackFrames((fd, propName = 'fd') => {
const validateBufferArray = hideStackFrames((buffers, propName = 'buffers') => {
if (!ArrayIsArray(buffers))
throw new ERR_INVALID_ARG_TYPE(propName, 'ArrayBufferView[]', buffers);
throw new ERR_INVALID_ARG_TYPE.HideStackFramesError(propName, 'ArrayBufferView[]', buffers);
for (let i = 0; i < buffers.length; i++) {
if (!isArrayBufferView(buffers[i]))
throw new ERR_INVALID_ARG_TYPE(propName, 'ArrayBufferView[]', buffers);
throw new ERR_INVALID_ARG_TYPE.HideStackFramesError(propName, 'ArrayBufferView[]', buffers);
}
return buffers;
@ -802,7 +788,7 @@ const validateCpOptions = hideStackFrames((options) => {
validateBoolean(options.verbatimSymlinks, 'options.verbatimSymlinks');
options.mode = getValidMode(options.mode, 'copyFile');
if (options.dereference === true && options.verbatimSymlinks === true) {
throw new ERR_INCOMPATIBLE_OPTION_PAIR('dereference', 'verbatimSymlinks');
throw new ERR_INCOMPATIBLE_OPTION_PAIR.HideStackFramesError('dereference', 'verbatimSymlinks');
}
if (options.filter !== undefined) {
validateFunction(options.filter, 'options.filter');
@ -827,21 +813,23 @@ const validateRmOptions = hideStackFrames((path, options, expectDir, cb) => {
}
if (stats.isDirectory() && !options.recursive) {
return cb(new ERR_FS_EISDIR({
const err = new ERR_FS_EISDIR.HideStackFramesError({
code: 'EISDIR',
message: 'is a directory',
path,
syscall: 'rm',
errno: EISDIR,
}));
});
return cb(err);
}
return cb(null, options);
});
});
const validateRmOptionsSync = hideStackFrames((path, options, expectDir) => {
options = validateRmdirOptions(options, defaultRmOptions);
validateBoolean(options.force, 'options.force');
options = validateRmdirOptions.withoutStackTrace(options, defaultRmOptions);
validateBoolean.withoutStackTrace(options.force, 'options.force');
if (!options.force || expectDir || !options.recursive) {
const isDirectory = lazyLoadFs()
@ -852,7 +840,7 @@ const validateRmOptionsSync = hideStackFrames((path, options, expectDir) => {
}
if (isDirectory && !options.recursive) {
throw new ERR_FS_EISDIR({
throw new ERR_FS_EISDIR.HideStackFramesError({
code: 'EISDIR',
message: 'is a directory',
path,
@ -882,13 +870,13 @@ const validateRmdirOptions = hideStackFrames(
(options, defaults = defaultRmdirOptions) => {
if (options === undefined)
return defaults;
validateObject(options, 'options');
validateObject.withoutStackTrace(options, 'options');
options = { ...defaults, ...options };
validateBoolean(options.recursive, 'options.recursive');
validateInt32(options.retryDelay, 'options.retryDelay', 0);
validateUint32(options.maxRetries, 'options.maxRetries');
validateBoolean.withoutStackTrace(options.recursive, 'options.recursive');
validateInt32.withoutStackTrace(options.retryDelay, 'options.retryDelay', 0);
validateUint32.withoutStackTrace(options.maxRetries, 'options.maxRetries');
return options;
});
@ -907,13 +895,13 @@ const getValidMode = hideStackFrames((mode, type) => {
if (mode == null) {
return def;
}
validateInteger(mode, 'mode', min, max);
validateInteger.withoutStackTrace(mode, 'mode', min, max);
return mode;
});
const validateStringAfterArrayBufferView = hideStackFrames((buffer, name) => {
if (typeof buffer !== 'string') {
throw new ERR_INVALID_ARG_TYPE(
throw new ERR_INVALID_ARG_TYPE.HideStackFramesError(
name,
['string', 'Buffer', 'TypedArray', 'DataView'],
buffer,
@ -923,16 +911,16 @@ const validateStringAfterArrayBufferView = hideStackFrames((buffer, name) => {
const validatePosition = hideStackFrames((position, name, length) => {
if (typeof position === 'number') {
validateInteger(position, name, -1);
validateInteger.withoutStackTrace(position, name, -1);
} else if (typeof position === 'bigint') {
const maxPosition = 2n ** 63n - 1n - BigInt(length);
if (!(position >= -1n && position <= maxPosition)) {
throw new ERR_OUT_OF_RANGE(name,
`>= -1 && <= ${maxPosition}`,
position);
throw new ERR_OUT_OF_RANGE.HideStackFramesError(name,
`>= -1 && <= ${maxPosition}`,
position);
}
} else {
throw new ERR_INVALID_ARG_TYPE(name, ['integer', 'bigint'], position);
throw new ERR_INVALID_ARG_TYPE.HideStackFramesError(name, ['integer', 'bigint'], position);
}
});
@ -956,7 +944,6 @@ module.exports = {
getValidatedPath,
getValidMode,
handleErrorFromBinding,
nullCheck,
possiblyTransformPath,
preprocessSymlinkDestination,
realpathCacheKey: Symbol('realpathCacheKey'),

View file

@ -9,7 +9,7 @@ const {
const {
AbortError,
uvException,
UVException,
codes: {
ERR_INVALID_ARG_VALUE,
},
@ -119,7 +119,7 @@ StatWatcher.prototype[kFSStatWatcherStart] = function(filename,
validateUint32(interval, 'interval');
const err = this._handle.start(toNamespacedPath(filename), interval);
if (err) {
const error = uvException({
const error = new UVException({
errno: err,
syscall: 'watch',
path: filename,
@ -204,7 +204,7 @@ function FSWatcher() {
this._handle.close();
this._handle = null; // Make the handle garbage collectable.
}
const error = uvException({
const error = new UVException({
errno: status,
syscall: 'watch',
path: filename,
@ -244,7 +244,7 @@ FSWatcher.prototype[kFSWatchStart] = function(filename,
recursive,
encoding);
if (err) {
const error = uvException({
const error = new UVException({
errno: err,
syscall: 'watch',
path: filename,
@ -338,7 +338,7 @@ async function* watch(filename, options = kEmptyObject) {
}
handle.onchange = (status, eventType, filename) => {
if (status < 0) {
const error = uvException({
const error = new UVException({
errno: status,
syscall: 'watch',
path: filename,
@ -354,7 +354,7 @@ async function* watch(filename, options = kEmptyObject) {
const err = handle.start(path, persistent, recursive, encoding);
if (err) {
const error = uvException({
const error = new UVException({
errno: err,
syscall: 'watch',
path: filename,

View file

@ -89,13 +89,13 @@ const assertValidHeader = hideStackFrames((name, value) => {
if (name === '' ||
typeof name !== 'string' ||
StringPrototypeIncludes(name, ' ')) {
throw new ERR_INVALID_HTTP_TOKEN('Header name', name);
throw new ERR_INVALID_HTTP_TOKEN.HideStackFramesError('Header name', name);
}
if (isPseudoHeader(name)) {
throw new ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED();
throw new ERR_HTTP2_PSEUDOHEADER_NOT_ALLOWED.HideStackFramesError();
}
if (value === undefined || value === null) {
throw new ERR_HTTP2_INVALID_HEADER_VALUE(value, name);
throw new ERR_HTTP2_INVALID_HEADER_VALUE.HideStackFramesError(value, name);
}
if (!isConnectionHeaderAllowed(name, value)) {
connectionHeaderMessageWarn();

View file

@ -766,25 +766,25 @@ const setAndValidatePriorityOptions = hideStackFrames((options) => {
if (options.weight === undefined) {
options.weight = NGHTTP2_DEFAULT_WEIGHT;
} else {
validateNumber(options.weight, 'options.weight');
validateNumber.withoutStackTrace(options.weight, 'options.weight');
}
if (options.parent === undefined) {
options.parent = 0;
} else {
validateNumber(options.parent, 'options.parent', 0);
validateNumber.withoutStackTrace(options.parent, 'options.parent', 0);
}
if (options.exclusive === undefined) {
options.exclusive = false;
} else {
validateBoolean(options.exclusive, 'options.exclusive');
validateBoolean.withoutStackTrace(options.exclusive, 'options.exclusive');
}
if (options.silent === undefined) {
options.silent = false;
} else {
validateBoolean(options.silent, 'options.silent');
validateBoolean.withoutStackTrace(options.silent, 'options.silent');
}
});
@ -946,33 +946,33 @@ function pingCallback(cb) {
// All settings are optional and may be left undefined
const validateSettings = hideStackFrames((settings) => {
if (settings === undefined) return;
assertWithinRange('headerTableSize',
settings.headerTableSize,
0, kMaxInt);
assertWithinRange('initialWindowSize',
settings.initialWindowSize,
0, kMaxInt);
assertWithinRange('maxFrameSize',
settings.maxFrameSize,
16384, kMaxFrameSize);
assertWithinRange('maxConcurrentStreams',
settings.maxConcurrentStreams,
0, kMaxStreams);
assertWithinRange('maxHeaderListSize',
settings.maxHeaderListSize,
0, kMaxInt);
assertWithinRange('maxHeaderSize',
settings.maxHeaderSize,
0, kMaxInt);
assertWithinRange.withoutStackTrace('headerTableSize',
settings.headerTableSize,
0, kMaxInt);
assertWithinRange.withoutStackTrace('initialWindowSize',
settings.initialWindowSize,
0, kMaxInt);
assertWithinRange.withoutStackTrace('maxFrameSize',
settings.maxFrameSize,
16384, kMaxFrameSize);
assertWithinRange.withoutStackTrace('maxConcurrentStreams',
settings.maxConcurrentStreams,
0, kMaxStreams);
assertWithinRange.withoutStackTrace('maxHeaderListSize',
settings.maxHeaderListSize,
0, kMaxInt);
assertWithinRange.withoutStackTrace('maxHeaderSize',
settings.maxHeaderSize,
0, kMaxInt);
if (settings.enablePush !== undefined &&
typeof settings.enablePush !== 'boolean') {
throw new ERR_HTTP2_INVALID_SETTING_VALUE('enablePush',
settings.enablePush);
throw new ERR_HTTP2_INVALID_SETTING_VALUE.HideStackFramesError('enablePush',
settings.enablePush);
}
if (settings.enableConnectProtocol !== undefined &&
typeof settings.enableConnectProtocol !== 'boolean') {
throw new ERR_HTTP2_INVALID_SETTING_VALUE('enableConnectProtocol',
settings.enableConnectProtocol);
throw new ERR_HTTP2_INVALID_SETTING_VALUE.HideStackFramesError('enableConnectProtocol',
settings.enableConnectProtocol);
}
});

View file

@ -8,7 +8,6 @@ const {
Error,
MathMax,
Number,
ObjectDefineProperty,
ObjectKeys,
SafeSet,
String,
@ -23,12 +22,11 @@ const {
codes: {
ERR_HTTP2_HEADER_SINGLE_VALUE,
ERR_HTTP2_INVALID_CONNECTION_HEADERS,
ERR_HTTP2_INVALID_PSEUDOHEADER,
ERR_HTTP2_INVALID_PSEUDOHEADER: { HideStackFramesError: ERR_HTTP2_INVALID_PSEUDOHEADER },
ERR_HTTP2_INVALID_SETTING_VALUE,
ERR_INVALID_ARG_TYPE,
ERR_INVALID_HTTP_TOKEN,
},
captureLargerStackTrace,
getMessage,
hideStackFrames,
kIsNodeError,
@ -552,14 +550,10 @@ class NghttpError extends Error {
binding.nghttp2ErrorString(integerCode));
this.code = customErrorCode || 'ERR_HTTP2_ERROR';
this.errno = integerCode;
captureLargerStackTrace(this);
ObjectDefineProperty(this, kIsNodeError, {
__proto__: null,
value: true,
enumerable: false,
writable: false,
configurable: true,
});
}
get [kIsNodeError]() {
return true;
}
toString() {
@ -572,7 +566,7 @@ const assertIsObject = hideStackFrames((value, name, types) => {
(value === null ||
typeof value !== 'object' ||
ArrayIsArray(value))) {
throw new ERR_INVALID_ARG_TYPE(name, types || 'Object', value);
throw new ERR_INVALID_ARG_TYPE.HideStackFramesError(name, types || 'Object', value);
}
});
@ -580,7 +574,7 @@ const assertWithinRange = hideStackFrames(
(name, value, min = 0, max = Infinity) => {
if (value !== undefined &&
(typeof value !== 'number' || value < min || value > max)) {
throw new ERR_HTTP2_INVALID_SETTING_VALUE.RangeError(
throw new ERR_HTTP2_INVALID_SETTING_VALUE.RangeError.HideStackFramesError(
name, value, min, max);
}
},

View file

@ -58,7 +58,7 @@ function makeSyncWrite(fd) {
const ctx = {};
writeBuffer(fd, chunk, 0, chunk.length, null, undefined, ctx);
if (ctx.errno !== undefined) {
const ex = errors.uvException(ctx);
const ex = new errors.UVException(ctx);
ex.errno = ctx.errno;
return cb(ex);
}

View file

@ -32,7 +32,7 @@ const {
} = primordials;
const {
errnoException,
ErrnoException,
codes: {
ERR_ASSERTION,
ERR_INVALID_ARG_TYPE,
@ -231,7 +231,7 @@ function wrapProcessMethods(binding) {
}
if (err)
throw errnoException(err, 'kill');
throw new ErrnoException(err, 'kill');
return true;
}

View file

@ -6,7 +6,7 @@ const {
} = primordials;
const {
errnoException,
ErrnoException,
} = require('internal/errors');
const { signals } = internalBinding('constants').os;
@ -33,7 +33,7 @@ function startListeningIfSignal(type) {
const err = wrap.start(signum);
if (err) {
wrap.close();
throw errnoException(err, 'uv_signal_start');
throw new ErrnoException(err, 'uv_signal_start');
}
signalWraps.set(type, wrap);

View file

@ -17,7 +17,7 @@ const {
} = internalBinding('stream_wrap');
const { UV_EOF } = internalBinding('uv');
const {
errnoException,
ErrnoException,
} = require('internal/errors');
const { owner_symbol } = require('internal/async_hooks').symbols;
const {
@ -91,7 +91,7 @@ function onWriteComplete(status) {
// TODO (ronag): This should be moved before if(stream.destroyed)
// in order to avoid swallowing error.
if (status < 0) {
const ex = errnoException(status, 'write', this.error);
const ex = new ErrnoException(status, 'write', this.error);
if (typeof this.callback === 'function')
this.callback(ex);
else
@ -157,7 +157,7 @@ function afterWriteDispatched(req, err, cb) {
req.async = !!streamBaseState[kLastWriteWasAsync];
if (err !== 0)
return cb(errnoException(err, 'write', req.error));
return cb(new ErrnoException(err, 'write', req.error));
if (!req.async && typeof req.callback === 'function') {
req.callback();
@ -194,7 +194,7 @@ function onStreamRead(arrayBuffer) {
if (!stream.destroyed) {
const err = handle.readStop();
if (err)
stream.destroy(errnoException(err, 'read'));
stream.destroy(new ErrnoException(err, 'read'));
}
}
@ -214,7 +214,7 @@ function onStreamRead(arrayBuffer) {
if (nread !== UV_EOF) {
// CallJSOnreadMethod expects the return value to be a buffer.
// Ref: https://github.com/nodejs/node/pull/34375
stream.destroy(errnoException(nread, 'read'));
stream.destroy(new ErrnoException(nread, 'read'));
return;
}

View file

@ -8,6 +8,7 @@ const {
ArrayPrototypeSlice,
ArrayPrototypeSort,
Error,
ErrorCaptureStackTrace,
FunctionPrototypeCall,
ObjectDefineProperties,
ObjectDefineProperty,
@ -44,11 +45,11 @@ const {
} = primordials;
const {
hideStackFrames,
codes: {
ERR_NO_CRYPTO,
ERR_UNKNOWN_SIGNAL,
},
isErrorStackTraceLimitWritable,
uvErrmapGet,
overrideStackTrace,
} = require('internal/errors');
@ -693,10 +694,19 @@ const lazyDOMExceptionClass = () => {
return _DOMException;
};
const lazyDOMException = hideStackFrames((message, name) => {
const lazyDOMException = (message, name) => {
_DOMException ??= internalBinding('messaging').DOMException;
if (isErrorStackTraceLimitWritable()) {
const limit = Error.stackTraceLimit;
Error.stackTraceLimit = 0;
const ex = new _DOMException(message, name);
Error.stackTraceLimit = limit;
ErrorCaptureStackTrace(ex, lazyDOMException);
return ex;
}
return new _DOMException(message, name);
});
};
const kEnumerableProperty = { __proto__: null };
kEnumerableProperty.enumerable = true;

View file

@ -22,11 +22,11 @@ const {
const {
hideStackFrames,
codes: {
ERR_SOCKET_BAD_PORT,
ERR_INVALID_ARG_TYPE,
ERR_INVALID_ARG_VALUE,
ERR_OUT_OF_RANGE,
ERR_UNKNOWN_SIGNAL,
ERR_SOCKET_BAD_PORT: { HideStackFramesError: ERR_SOCKET_BAD_PORT },
ERR_INVALID_ARG_TYPE: { HideStackFramesError: ERR_INVALID_ARG_TYPE },
ERR_INVALID_ARG_VALUE: { HideStackFramesError: ERR_INVALID_ARG_VALUE },
ERR_OUT_OF_RANGE: { HideStackFramesError: ERR_OUT_OF_RANGE },
ERR_UNKNOWN_SIGNAL: { HideStackFramesError: ERR_UNKNOWN_SIGNAL },
},
} = require('internal/errors');
const { normalizeEncoding } = require('internal/util');
@ -157,10 +157,10 @@ const validateUint32 = hideStackFrames((value, name, positive = false) => {
*/
/** @type {validateString} */
function validateString(value, name) {
const validateString = hideStackFrames((value, name) => {
if (typeof value !== 'string')
throw new ERR_INVALID_ARG_TYPE(name, 'string', value);
}
});
/**
* @callback validateNumber
@ -172,7 +172,7 @@ function validateString(value, name) {
*/
/** @type {validateNumber} */
function validateNumber(value, name, min = undefined, max) {
const validateNumber = hideStackFrames((value, name, min = undefined, max) => {
if (typeof value !== 'number')
throw new ERR_INVALID_ARG_TYPE(name, 'number', value);
@ -183,7 +183,7 @@ function validateNumber(value, name, min = undefined, max) {
`${min != null ? `>= ${min}` : ''}${min != null && max != null ? ' && ' : ''}${max != null ? `<= ${max}` : ''}`,
value);
}
}
});
/**
* @callback validateOneOf
@ -213,10 +213,10 @@ const validateOneOf = hideStackFrames((value, name, oneOf) => {
*/
/** @type {validateBoolean} */
function validateBoolean(value, name) {
const validateBoolean = hideStackFrames((value, name) => {
if (typeof value !== 'boolean')
throw new ERR_INVALID_ARG_TYPE(name, 'boolean', value);
}
});
const kValidateObjectNone = 0;
const kValidateObjectAllowNullable = 1 << 0;
@ -309,7 +309,7 @@ const validateArray = hideStackFrames((value, name, minLength = 0) => {
*/
/** @type {validateStringArray} */
function validateStringArray(value, name) {
const validateStringArray = hideStackFrames((value, name) => {
validateArray(value, name);
for (let i = 0; i < value.length; ++i) {
// Don't use validateString here for performance reasons, as
@ -318,7 +318,7 @@ function validateStringArray(value, name) {
throw new ERR_INVALID_ARG_TYPE(`${name}[${i}]`, 'string', value[i]);
}
}
}
});
/**
* @callback validateBooleanArray
@ -328,7 +328,7 @@ function validateStringArray(value, name) {
*/
/** @type {validateBooleanArray} */
function validateBooleanArray(value, name) {
const validateBooleanArray = hideStackFrames((value, name) => {
validateArray(value, name);
for (let i = 0; i < value.length; ++i) {
// Don't use validateBoolean here for performance reasons, as
@ -337,7 +337,7 @@ function validateBooleanArray(value, name) {
throw new ERR_INVALID_ARG_TYPE(`${name}[${i}]`, 'boolean', value[i]);
}
}
}
});
/**
* @callback validateAbortSignalArray
@ -364,7 +364,7 @@ function validateAbortSignalArray(value, name) {
* @param {string} [name='signal']
* @returns {asserts signal is keyof signals}
*/
function validateSignalName(signal, name = 'signal') {
const validateSignalName = hideStackFrames((signal, name = 'signal') => {
validateString(signal, name);
if (signals[signal] === undefined) {
@ -375,7 +375,7 @@ function validateSignalName(signal, name = 'signal') {
throw new ERR_UNKNOWN_SIGNAL(signal);
}
}
});
/**
* @callback validateBuffer
@ -397,7 +397,7 @@ const validateBuffer = hideStackFrames((buffer, name = 'buffer') => {
* @param {string} data
* @param {string} encoding
*/
function validateEncoding(data, encoding) {
const validateEncoding = hideStackFrames((data, encoding) => {
const normalizedEncoding = normalizeEncoding(encoding);
const length = data.length;
@ -405,7 +405,7 @@ function validateEncoding(data, encoding) {
throw new ERR_INVALID_ARG_VALUE('encoding', encoding,
`is invalid for data of length ${length}`);
}
}
});
/**
* Check that the port number is not NaN when coerced to a number,
@ -415,7 +415,7 @@ function validateEncoding(data, encoding) {
* @param {boolean} [allowZero=true]
* @returns {number}
*/
function validatePort(port, name = 'Port', allowZero = true) {
const validatePort = hideStackFrames((port, name = 'Port', allowZero = true) => {
if ((typeof port !== 'number' && typeof port !== 'string') ||
(typeof port === 'string' && StringPrototypeTrim(port).length === 0) ||
+port !== (+port >>> 0) ||
@ -424,7 +424,7 @@ function validatePort(port, name = 'Port', allowZero = true) {
throw new ERR_SOCKET_BAD_PORT(name, port, allowZero);
}
return port | 0;
}
});
/**
* @callback validateAbortSignal
@ -507,7 +507,7 @@ const linkValueRegExp = /^(?:<[^>]*>)(?:\s*;\s*[^;"\s]+(?:=(")?[^;"\s]*\1)?)*$/;
* @param {any} value
* @param {string} name
*/
function validateLinkHeaderFormat(value, name) {
const validateLinkHeaderFormat = hideStackFrames((value, name) => {
if (
typeof value === 'undefined' ||
!RegExpPrototypeExec(linkValueRegExp, value)
@ -518,7 +518,7 @@ function validateLinkHeaderFormat(value, name) {
'must be an array or string of format "</styles.css>; rel=preload; as=style"',
);
}
}
});
const validateInternalField = hideStackFrames((object, fieldKey, className) => {
if (typeof object !== 'object' || object === null || !ObjectPrototypeHasOwnProperty(object, fieldKey)) {
@ -530,9 +530,9 @@ const validateInternalField = hideStackFrames((object, fieldKey, className) => {
* @param {any} hints
* @return {string}
*/
function validateLinkHeaderValue(hints) {
const validateLinkHeaderValue = hideStackFrames((hints) => {
if (typeof hints === 'string') {
validateLinkHeaderFormat(hints, 'hints');
validateLinkHeaderFormat.withoutStackTrace(hints, 'hints');
return hints;
} else if (ArrayIsArray(hints)) {
const hintsLength = hints.length;
@ -544,7 +544,7 @@ function validateLinkHeaderValue(hints) {
for (let i = 0; i < hintsLength; i++) {
const link = hints[i];
validateLinkHeaderFormat(link, 'hints');
validateLinkHeaderFormat.withoutStackTrace(link, 'hints');
result += link;
if (i !== hintsLength - 1) {
@ -560,7 +560,7 @@ function validateLinkHeaderValue(hints) {
hints,
'must be an array or string of format "</styles.css>; rel=preload; as=style"',
);
}
});
module.exports = {
isInt32,

View file

@ -46,7 +46,7 @@ const {
} = require('buffer');
const {
errnoException,
ErrnoException,
codes: {
ERR_INVALID_ARG_TYPE,
ERR_INVALID_ARG_VALUE,
@ -856,7 +856,7 @@ function newWritableStreamFromStreamBase(streamBase, strategy) {
function onWriteComplete(status) {
if (status < 0) {
const error = errnoException(status, 'write', this.error);
const error = new ErrnoException(status, 'write', this.error);
this.promise.reject(error);
this.controller.error(error);
return;
@ -879,7 +879,7 @@ function newWritableStreamFromStreamBase(streamBase, strategy) {
}
if (ret !== 0)
promise.reject(errnoException(ret, 'write', req));
promise.reject(new ErrnoException(ret, 'write', req));
else if (!req.async)
promise.resolve();

View file

@ -106,11 +106,11 @@ const {
ERR_SOCKET_CLOSED_BEFORE_CONNECTION,
ERR_MISSING_ARGS,
},
aggregateErrors,
errnoException,
exceptionWithHostPort,
ErrnoException,
ExceptionWithHostPort,
genericNodeError,
uvExceptionWithHostPort,
NodeAggregateError,
UVExceptionWithHostPort,
} = require('internal/errors');
const { isUint8Array } = require('internal/util/types');
const { queueMicrotask } = require('internal/process/task_queues');
@ -425,7 +425,7 @@ function Socket(options) {
// which cannot be opened. This is difficult to test as most
// un-openable fds will throw on `createHandle`
if (err)
throw errnoException(err, 'open');
throw new ErrnoException(err, 'open');
this[async_id_symbol] = this._handle.getAsyncId();
@ -434,7 +434,7 @@ function Socket(options) {
// Make stdout and stderr blocking on Windows
err = this._handle.setBlocking(true);
if (err)
throw errnoException(err, 'setBlocking');
throw new ErrnoException(err, 'setBlocking');
this._writev = null;
this._write = makeSyncWrite(fd);
@ -533,7 +533,7 @@ Socket.prototype._final = function(cb) {
if (err === 1 || err === UV_ENOTCONN) // synchronous finish
return cb();
else if (err !== 0)
return cb(errnoException(err, 'shutdown'));
return cb(new ErrnoException(err, 'shutdown'));
};
function afterShutdown() {
@ -698,7 +698,7 @@ function tryReadStart(socket) {
socket._handle.reading = true;
const err = socket._handle.readStart();
if (err)
socket.destroy(errnoException(err, 'read'));
socket.destroy(new ErrnoException(err, 'read'));
}
// Just call handle.readStart until we have enough in the buffer
@ -747,7 +747,7 @@ Socket.prototype.pause = function() {
if (!this.destroyed) {
const err = this._handle.readStop();
if (err)
this.destroy(errnoException(err, 'read'));
this.destroy(new ErrnoException(err, 'read'));
}
}
return stream.Duplex.prototype.pause.call(this);
@ -816,7 +816,7 @@ Socket.prototype._destroy = function(exception, cb) {
this.emit('close', isException);
});
if (err)
this.emit('error', errnoException(err, 'reset'));
this.emit('error', new ErrnoException(err, 'reset'));
} else if (this._closeAfterHandlingError) {
// Enqueue closing the socket as a microtask, so that the socket can be
// accessible when an `error` event is handled in the `next tick queue`.
@ -1051,7 +1051,7 @@ function internalConnect(
err = checkBindError(err, localPort, self._handle);
if (err) {
const ex = exceptionWithHostPort(err, 'bind', localAddress, localPort);
const ex = new ExceptionWithHostPort(err, 'bind', localAddress, localPort);
self.destroy(ex);
return;
}
@ -1087,7 +1087,7 @@ function internalConnect(
details = sockname.address + ':' + sockname.port;
}
const ex = exceptionWithHostPort(err, 'connect', address, port, details);
const ex = new ExceptionWithHostPort(err, 'connect', address, port, details);
self.destroy(ex);
} else if ((addressType === 6 || addressType === 4) && hasObserver('net')) {
startPerf(self, kPerfHooksNetConnectContext, { type: 'net', name: 'connect', detail: { host: address, port } });
@ -1111,7 +1111,7 @@ function internalConnectMultiple(context, canceled) {
return;
}
self.destroy(aggregateErrors(context.errors));
self.destroy(new NodeAggregateError(context.errors));
return;
}
@ -1142,7 +1142,7 @@ function internalConnectMultiple(context, canceled) {
err = checkBindError(err, localPort, self._handle);
if (err) {
ArrayPrototypePush(context.errors, exceptionWithHostPort(err, 'bind', localAddress, localPort));
ArrayPrototypePush(context.errors, new ExceptionWithHostPort(err, 'bind', localAddress, localPort));
internalConnectMultiple(context);
return;
}
@ -1173,7 +1173,7 @@ function internalConnectMultiple(context, canceled) {
details = sockname.address + ':' + sockname.port;
}
ArrayPrototypePush(context.errors, exceptionWithHostPort(err, 'connect', address, port, details));
ArrayPrototypePush(context.errors, new ExceptionWithHostPort(err, 'connect', address, port, details));
internalConnectMultiple(context);
return;
}
@ -1592,11 +1592,11 @@ function afterConnect(status, handle, req, readable, writable) {
if (req.localAddress && req.localPort) {
details = req.localAddress + ':' + req.localPort;
}
const ex = exceptionWithHostPort(status,
'connect',
req.address,
req.port,
details);
const ex = new ExceptionWithHostPort(status,
'connect',
req.address,
req.port,
details);
if (details) {
ex.localAddress = req.localAddress;
ex.localPort = req.localPort;
@ -1631,11 +1631,11 @@ function createConnectionError(req, status) {
details = req.localAddress + ':' + req.localPort;
}
const ex = exceptionWithHostPort(status,
'connect',
req.address,
req.port,
details);
const ex = new ExceptionWithHostPort(status,
'connect',
req.address,
req.port,
details);
if (details) {
ex.localAddress = req.localAddress;
ex.localPort = req.localPort;
@ -1852,7 +1852,7 @@ function setupListenHandle(address, port, addressType, backlog, fd, flags) {
rval = createServerHandle(address, port, addressType, fd, flags);
if (typeof rval === 'number') {
const error = uvExceptionWithHostPort(rval, 'listen', address, port);
const error = new UVExceptionWithHostPort(rval, 'listen', address, port);
process.nextTick(emitErrorNT, this, error);
return;
}
@ -1869,7 +1869,7 @@ function setupListenHandle(address, port, addressType, backlog, fd, flags) {
const err = this._handle.listen(backlog || 511);
if (err) {
const ex = uvExceptionWithHostPort(err, 'listen', address, port);
const ex = new UVExceptionWithHostPort(err, 'listen', address, port);
this._handle.close();
this._handle = null;
defaultTriggerAsyncIdScope(this[async_id_symbol],
@ -1937,7 +1937,7 @@ function listenInCluster(server, address, port, addressType,
err = checkBindError(err, port, handle);
if (err) {
const ex = exceptionWithHostPort(err, 'bind', address, port);
const ex = new ExceptionWithHostPort(err, 'bind', address, port);
return server.emit('error', ex);
}
@ -2045,7 +2045,7 @@ Server.prototype.listen = function(...args) {
if (err) {
this._handle.close();
this._handle = null;
throw errnoException(err, 'uv_pipe_chmod');
throw new ErrnoException(err, 'uv_pipe_chmod');
}
}
return this;
@ -2086,7 +2086,7 @@ Server.prototype.address = function() {
const out = {};
const err = this._handle.getsockname(out);
if (err) {
throw errnoException(err, 'address');
throw new ErrnoException(err, 'address');
}
return out;
} else if (this._pipeName) {
@ -2102,7 +2102,7 @@ function onconnection(err, clientHandle) {
debug('onconnection');
if (err) {
self.emit('error', errnoException(err, 'accept'));
self.emit('error', new ErrnoException(err, 'accept'));
return;
}

View file

@ -65,7 +65,7 @@ function getCheckedFunction(fn) {
const ctx = {};
const ret = fn(ctx);
if (ret === undefined) {
throw new ERR_SYSTEM_ERROR(ctx);
throw new ERR_SYSTEM_ERROR.HideStackFramesError(ctx);
}
return ret;
});

View file

@ -74,7 +74,7 @@ ReadStream.prototype.setRawMode = function(flag) {
flag = !!flag;
const err = this._handle?.setRawMode(flag);
if (err) {
this.emit('error', errors.errnoException(err, 'setRawMode'));
this.emit('error', new errors.ErrnoException(err, 'setRawMode'));
return this;
}
this.isRaw = flag;
@ -129,7 +129,7 @@ WriteStream.prototype._refreshSize = function() {
const winSize = new Array(2);
const err = this._handle.getWindowSize(winSize);
if (err) {
this.emit('error', errors.errnoException(err, 'getWindowSize'));
this.emit('error', new errors.ErrnoException(err, 'getWindowSize'));
return;
}
const { 0: newCols, 1: newRows } = winSize;

View file

@ -32,6 +32,7 @@ const {
DatePrototypeGetMonth,
DatePrototypeGetSeconds,
Error,
ErrorCaptureStackTrace,
FunctionPrototypeBind,
NumberIsSafeInteger,
ObjectDefineProperties,
@ -51,9 +52,9 @@ const {
ERR_INVALID_ARG_TYPE,
ERR_OUT_OF_RANGE,
},
errnoException,
exceptionWithHostPort,
hideStackFrames,
isErrorStackTraceLimitWritable,
ErrnoException,
ExceptionWithHostPort,
} = require('internal/errors');
const {
format,
@ -278,16 +279,17 @@ function _extend(target, source) {
return target;
}
const callbackifyOnRejected = hideStackFrames((reason, cb) => {
const callbackifyOnRejected = (reason, cb) => {
// `!reason` guard inspired by bluebird (Ref: https://goo.gl/t5IS6M).
// Because `null` is a special error value in callbacks which means "no error
// occurred", we error-wrap so the callback consumer can distinguish between
// "the promise rejected with null" or "the promise fulfilled with undefined".
if (!reason) {
reason = new ERR_FALSY_VALUE_REJECTION(reason);
reason = new ERR_FALSY_VALUE_REJECTION.HideStackFramesError(reason);
ErrorCaptureStackTrace(reason, callbackifyOnRejected);
}
return cb(reason);
});
};
/**
* @template {(...args: any[]) => Promise<any>} T
@ -345,10 +347,34 @@ function getSystemErrorName(err) {
return internalErrorName(err);
}
function _errnoException(...args) {
if (isErrorStackTraceLimitWritable()) {
const limit = Error.stackTraceLimit;
Error.stackTraceLimit = 0;
const e = new ErrnoException(...args);
Error.stackTraceLimit = limit;
ErrorCaptureStackTrace(e, _exceptionWithHostPort);
return e;
}
return new ErrnoException(...args);
}
function _exceptionWithHostPort(...args) {
if (isErrorStackTraceLimitWritable()) {
const limit = Error.stackTraceLimit;
Error.stackTraceLimit = 0;
const e = new ExceptionWithHostPort(...args);
Error.stackTraceLimit = limit;
ErrorCaptureStackTrace(e, _exceptionWithHostPort);
return e;
}
return new ExceptionWithHostPort(...args);
}
// Keep the `exports =` so that various functions can still be monkeypatched
module.exports = {
_errnoException: errnoException,
_exceptionWithHostPort: exceptionWithHostPort,
_errnoException,
_exceptionWithHostPort,
_extend,
callbackify,
debug: debuglog,

View file

@ -211,10 +211,10 @@ const checkFiniteNumber = hideStackFrames((number, name) => {
return false;
}
validateNumber(number, name);
validateNumber.withoutStackTrace(number, name);
// Infinite numbers
throw new ERR_OUT_OF_RANGE(name, 'a finite number', number);
throw new ERR_OUT_OF_RANGE.HideStackFramesError(name, 'a finite number', number);
});
// 1. Returns def for number when it's undefined or NaN
@ -223,12 +223,12 @@ const checkFiniteNumber = hideStackFrames((number, name) => {
// 4. Throws ERR_OUT_OF_RANGE for infinite numbers or numbers > upper or < lower
const checkRangesOrGetDefault = hideStackFrames(
(number, name, lower, upper, def) => {
if (!checkFiniteNumber(number, name)) {
if (!checkFiniteNumber.withoutStackTrace(number, name)) {
return def;
}
if (number < lower || number > upper) {
throw new ERR_OUT_OF_RANGE(name,
`>= ${lower} and <= ${upper}`, number);
throw new ERR_OUT_OF_RANGE.HideStackFramesError(name,
`>= ${lower} and <= ${upper}`, number);
}
return number;
},

View file

@ -2,7 +2,8 @@
throw aggregateTwoErrors(err, originalError);
^
[AggregateError: original] {
AggregateError: original
at Object.<anonymous> (*error_aggregateTwoErrors.js:*:*) {
code: 'ERR0',
[errors]: [
Error: original

View file

@ -11,6 +11,8 @@ const errors = require('internal/errors');
const { internalBinding } = require('internal/test/binding');
const { UV_EAI_MEMORY } = internalBinding('uv');
const memoryError = errors.dnsException(UV_EAI_MEMORY, 'fhqwhgads');
const memoryError = new errors.DNSException(UV_EAI_MEMORY, 'fhqwhgads');
assert.strictEqual(memoryError.code, 'EAI_MEMORY');
const stack = memoryError.stack.split('\n');
assert.match(stack[1], /^ {4}at Object/);

View file

@ -57,3 +57,15 @@ assert.strictEqual(aggregateTwoErrors(null, null), null);
assert.strictEqual(chainedError.code, err0.code);
assert.deepStrictEqual(chainedError.errors, [err0, err1]);
}
{
const err0 = new Error('original');
const err1 = new Error('second error');
err0.code = 'ERR0';
err1.code = 'ERR1';
const chainedError = aggregateTwoErrors(null, aggregateTwoErrors(err1, err0));
const stack = chainedError.stack.split('\n');
assert.match(stack[1], /^ {4}at Object/);
}

View file

@ -0,0 +1,242 @@
// Flags: --expose-internals
'use strict';
require('../common');
const { hideStackFrames, codes } = require('internal/errors');
const { validateInteger } = require('internal/validators');
const assert = require('assert');
{
// Test that the a built-in error has the correct name and message.
function a() {
b();
}
function b() {
c();
}
const c = hideStackFrames(function() {
throw new Error('test');
});
try {
a();
} catch (e) {
assert.strictEqual(e.name, 'Error');
assert.strictEqual(e.message, 'test');
}
}
{
// Test that validator errors have the correct name and message.
try {
validateInteger('2', 'test');
} catch (e) {
assert.strictEqual(e.name, 'TypeError');
assert.strictEqual(e.message, 'The "test" argument must be of type number. Received type string (\'2\')');
}
}
{
// Test that validator fn is not in the stack trace.
function a(value) {
validateInteger(value, 'test');
}
try {
a('2');
} catch (e) {
assert.strictEqual(Error.stackTraceLimit, 10);
const stack = e.stack.split('\n');
assert.doesNotMatch(stack[1], /validateInteger/);
assert.match(stack[1], /at a/);
}
}
{
// Test that the stack trace is hidden for normal unnamed functions.
function a() {
b();
}
function b() {
c();
}
const c = hideStackFrames(function() {
throw new Error('test');
});
try {
a();
} catch (e) {
assert.strictEqual(Error.stackTraceLimit, 10);
const stack = e.stack.split('\n');
assert.doesNotMatch(stack[1], /at c/);
assert.match(stack[1], /at b/);
assert.strictEqual(Error.stackTraceLimit, 10);
}
}
{
// Test that the stack trace is hidden for normal functions.
function a() {
b();
}
function b() {
c();
}
const c = hideStackFrames(function c() {
throw new Error('test');
});
try {
a();
} catch (e) {
assert.strictEqual(Error.stackTraceLimit, 10);
const stack = e.stack.split('\n');
assert.doesNotMatch(stack[1], /at c/);
assert.match(stack[1], /at b/);
assert.strictEqual(Error.stackTraceLimit, 10);
}
}
{
// Test that the stack trace is hidden for arrow functions.
function a() {
b();
}
function b() {
c();
}
const c = hideStackFrames(() => {
throw new Error('test');
});
try {
a();
} catch (e) {
assert.strictEqual(Error.stackTraceLimit, 10);
const stack = e.stack.split('\n');
assert.doesNotMatch(stack[1], /at c/);
assert.match(stack[1], /at b/);
assert.strictEqual(Error.stackTraceLimit, 10);
}
}
{
// Creating a new Error object without stack trace, then throwing it
// should get a stack trace by hideStackFrames.
function a() {
b();
}
function b() {
c();
}
const c = hideStackFrames(function() {
throw new Error('test');
});
try {
a();
} catch (e) {
assert.strictEqual(Error.stackTraceLimit, 10);
const stack = e.stack.split('\n');
assert.doesNotMatch(stack[1], /at c/);
assert.match(stack[1], /at b/);
assert.strictEqual(Error.stackTraceLimit, 10);
}
}
{
const ERR_ACCESS_DENIED = codes.ERR_ACCESS_DENIED;
// Creating a new Error object without stack trace, then throwing it
// should get a stack trace by hideStackFrames.
function a() {
b();
}
function b() {
c();
}
const c = hideStackFrames(function() {
throw new ERR_ACCESS_DENIED.NoStackError('test');
});
try {
a();
} catch (e) {
assert.strictEqual(Error.stackTraceLimit, 10);
const stack = e.stack.split('\n');
assert.doesNotMatch(stack[1], /at c/);
assert.match(stack[1], /at b/);
assert.strictEqual(Error.stackTraceLimit, 10);
}
}
{
// Creating a new Error object with stack trace, then throwing it
// should get a stack trace by hideStackFrames.
function a() {
b();
}
const b = hideStackFrames(function b() {
c();
});
const c = hideStackFrames(function() {
throw new Error('test');
});
try {
a();
} catch (e) {
assert.strictEqual(Error.stackTraceLimit, 10);
const stack = e.stack.split('\n');
assert.match(stack[1], /at a/);
assert.strictEqual(Error.stackTraceLimit, 10);
}
}
{
// Binding passes the value of this to the wrapped function.
let called = false;
function a() {
b.bind({ key: 'value' })();
}
const b = hideStackFrames(function b() {
assert.strictEqual(this.key, 'value');
called = true;
});
a();
assert.strictEqual(called, true);
}
{
// Binding passes the value of this to the withoutStackTrace function.
let called = false;
function a() {
b.withoutStackTrace.bind({ key: 'value' })();
}
const b = hideStackFrames(function b() {
assert.strictEqual(this.key, 'value');
called = true;
});
a();
assert.strictEqual(called, true);
}

View file

@ -225,6 +225,7 @@ const values = [
const errLines = stderr.trim().split(/[\r\n]+/);
const errLine = errLines.find((l) => /^Error/.exec(l));
assert.strictEqual(errLine, `Error: ${fixture}`);
assert.strictEqual(errLines.length, 7);
})
);
}
@ -279,3 +280,20 @@ const values = [
});
});
}
{
// Test Promise factory
function promiseFn(value) {
return Promise.reject(value);
}
const cbPromiseFn = callbackify(promiseFn);
cbPromiseFn(null, (err) => {
assert.strictEqual(err.message, 'Promise was rejected with falsy value');
assert.strictEqual(err.code, 'ERR_FALSY_VALUE_REJECTION');
assert.strictEqual(err.reason, null);
const stack = err.stack.split(/[\r\n]+/);
assert.match(stack[1], /at process\.processTicksAndRejections/);
});
}

View file

@ -2,10 +2,10 @@
'use strict';
require('../common');
const assert = require('assert');
const { uvException, uvExceptionWithHostPort } = require('internal/errors');
const { UVException, UVExceptionWithHostPort } = require('internal/errors');
{
const exception = uvException({ errno: 100, syscall: 'open' });
const exception = new UVException({ errno: 100, syscall: 'open' });
assert.strictEqual(exception.message, 'UNKNOWN: unknown error, open');
assert.strictEqual(exception.errno, 100);
@ -14,7 +14,7 @@ const { uvException, uvExceptionWithHostPort } = require('internal/errors');
}
{
const exception = uvExceptionWithHostPort(100, 'listen', '127.0.0.1', 80);
const exception = new UVExceptionWithHostPort(100, 'listen', '127.0.0.1', 80);
assert.strictEqual(exception.message,
'listen UNKNOWN: unknown error 127.0.0.1:80');