errors: validate input arguments

This makes sure the input arguments get validated so implementation
errors will be caught early. It also improves a couple of error
messages by providing more detailed information and fixes errors
detected by the new functionality. Besides that a error type got
simplified and tests got refactored.

PR-URL: https://github.com/nodejs/node/pull/19924
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
Ruben Bridgewater 2018-04-11 03:10:22 +02:00
parent d5495e859c
commit dca7fb2225
No known key found for this signature in database
GPG Key ID: F07496B3EB3C1762
18 changed files with 215 additions and 178 deletions

View File

@ -920,7 +920,7 @@ Buffer.prototype.write = function write(string, offset, length, encoding) {
length = remaining; length = remaining;
if (string.length > 0 && (length < 0 || offset < 0)) if (string.length > 0 && (length < 0 || offset < 0))
throw new ERR_BUFFER_OUT_OF_BOUNDS('length', true); throw new ERR_BUFFER_OUT_OF_BOUNDS();
} else { } else {
// if someone is still calling the obsolete form of write(), tell them. // if someone is still calling the obsolete form of write(), tell them.
// we don't want eg buf.write("foo", "utf8", 10) to silently turn into // we don't want eg buf.write("foo", "utf8", 10) to silently turn into

View File

@ -1019,7 +1019,7 @@ fs.fchmod = function(fd, mode, callback) {
validateUint32(mode, 'mode'); validateUint32(mode, 'mode');
// Values for mode < 0 are already checked via the validateUint32 function // Values for mode < 0 are already checked via the validateUint32 function
if (mode > 0o777) if (mode > 0o777)
throw new ERR_OUT_OF_RANGE('mode'); throw new ERR_OUT_OF_RANGE('mode', undefined, mode);
const req = new FSReqWrap(); const req = new FSReqWrap();
req.oncomplete = makeCallback(callback); req.oncomplete = makeCallback(callback);
@ -1032,7 +1032,7 @@ fs.fchmodSync = function(fd, mode) {
validateUint32(mode, 'mode'); validateUint32(mode, 'mode');
// Values for mode < 0 are already checked via the validateUint32 function // Values for mode < 0 are already checked via the validateUint32 function
if (mode > 0o777) if (mode > 0o777)
throw new ERR_OUT_OF_RANGE('mode'); throw new ERR_OUT_OF_RANGE('mode', undefined, mode);
const ctx = {}; const ctx = {};
binding.fchmod(fd, mode, undefined, ctx); binding.fchmod(fd, mode, undefined, ctx);
handleErrorFromBinding(ctx); handleErrorFromBinding(ctx);

View File

@ -373,7 +373,7 @@ async function fchmod(handle, mode) {
validateFileHandle(handle); validateFileHandle(handle);
validateUint32(mode, 'mode'); validateUint32(mode, 'mode');
if (mode > 0o777) if (mode > 0o777)
throw new ERR_OUT_OF_RANGE('mode'); throw new ERR_OUT_OF_RANGE('mode', undefined, mode);
return binding.fchmod(handle.fd, mode, kUsePromises); return binding.fchmod(handle.fd, mode, kUsePromises);
} }

View File

@ -50,7 +50,7 @@ function boundsError(value, length, type) {
} }
if (length < 0) if (length < 0)
throw new ERR_BUFFER_OUT_OF_BOUNDS(null, true); throw new ERR_BUFFER_OUT_OF_BOUNDS();
throw new ERR_OUT_OF_RANGE(type || 'offset', throw new ERR_OUT_OF_RANGE(type || 'offset',
`>= ${type ? 1 : 0} and <= ${length}`, `>= ${type ? 1 : 0} and <= ${length}`,

View File

@ -64,11 +64,8 @@ function _pbkdf2(password, salt, iterations, keylen, digest, callback) {
if (typeof keylen !== 'number') if (typeof keylen !== 'number')
throw new ERR_INVALID_ARG_TYPE('keylen', 'number', keylen); throw new ERR_INVALID_ARG_TYPE('keylen', 'number', keylen);
if (keylen < 0 || if (keylen < 0 || !Number.isInteger(keylen) || keylen > INT_MAX)
!Number.isFinite(keylen) || throw new ERR_OUT_OF_RANGE('keylen', `>= 0 && <= ${INT_MAX}`, keylen);
keylen > INT_MAX) {
throw new ERR_OUT_OF_RANGE('keylen');
}
const encoding = getDefaultEncoding(); const encoding = getDefaultEncoding();

View File

@ -416,20 +416,30 @@ function internalAssert(condition, message) {
} }
} }
function message(key, args) { function message(key, args = []) {
const msg = messages.get(key); const msg = messages.get(key);
internalAssert(msg, `An invalid error message key was used: ${key}.`);
let fmt;
if (util === undefined) util = require('util'); if (util === undefined) util = require('util');
if (typeof msg === 'function') { if (typeof msg === 'function') {
fmt = msg; internalAssert(
} else { msg.length <= args.length, // Default options do not count.
fmt = util.format; `Code: ${key}; The provided arguments length (${args.length}) does not ` +
if (args === undefined || args.length === 0) `match the required ones (${msg.length}).`
return msg; );
args.unshift(msg); return msg.apply(null, args);
} }
return String(fmt.apply(null, args));
const expectedLength = (msg.match(/%[dfijoOs]/g) || []).length;
internalAssert(
expectedLength === args.length,
`Code: ${key}; The provided arguments length (${args.length}) does not ` +
`match the required ones (${expectedLength}).`
);
if (args.length === 0)
return msg;
args.unshift(msg);
return util.format.apply(null, args);
} }
/** /**
@ -740,7 +750,7 @@ E('ERR_HTTP2_INVALID_SETTING_VALUE',
'Invalid value for setting "%s": %s', TypeError, RangeError); 'Invalid value for setting "%s": %s', TypeError, RangeError);
E('ERR_HTTP2_INVALID_STREAM', 'The stream has been destroyed', Error); E('ERR_HTTP2_INVALID_STREAM', 'The stream has been destroyed', Error);
E('ERR_HTTP2_MAX_PENDING_SETTINGS_ACK', E('ERR_HTTP2_MAX_PENDING_SETTINGS_ACK',
'Maximum number of pending settings acknowledgements (%s)', Error); 'Maximum number of pending settings acknowledgements', Error);
E('ERR_HTTP2_NO_SOCKET_MANIPULATION', E('ERR_HTTP2_NO_SOCKET_MANIPULATION',
'HTTP/2 sockets should not be directly manipulated (e.g. read and written)', 'HTTP/2 sockets should not be directly manipulated (e.g. read and written)',
Error); Error);
@ -793,7 +803,7 @@ E('ERR_INVALID_ARG_VALUE', (name, value, reason = 'is invalid') => {
}, TypeError, RangeError); }, TypeError, RangeError);
E('ERR_INVALID_ARRAY_LENGTH', E('ERR_INVALID_ARRAY_LENGTH',
(name, len, actual) => { (name, len, actual) => {
internalAssert(typeof actual === 'number', 'actual must be a number'); internalAssert(typeof actual === 'number', 'actual must be of type number');
return `The array "${name}" (length ${actual}) must be of length ${len}.`; return `The array "${name}" (length ${actual}) must be of length ${len}.`;
}, TypeError); }, TypeError);
E('ERR_INVALID_ASYNC_ID', 'Invalid %s value: %s', RangeError); E('ERR_INVALID_ASYNC_ID', 'Invalid %s value: %s', RangeError);
@ -925,7 +935,9 @@ E('ERR_UNCAUGHT_EXCEPTION_CAPTURE_ALREADY_SET',
Error); Error);
E('ERR_UNESCAPED_CHARACTERS', '%s contains unescaped characters', TypeError); E('ERR_UNESCAPED_CHARACTERS', '%s contains unescaped characters', TypeError);
E('ERR_UNHANDLED_ERROR', E('ERR_UNHANDLED_ERROR',
(err) => { // Using a default argument here is important so the argument is not counted
// towards `Function#length`.
(err = undefined) => {
const msg = 'Unhandled error.'; const msg = 'Unhandled error.';
if (err === undefined) return msg; if (err === undefined) return msg;
return `${msg} (${err})`; return `${msg} (${err})`;
@ -960,7 +972,6 @@ E('ERR_VM_MODULE_STATUS', 'Module status %s', Error);
E('ERR_ZLIB_INITIALIZATION_FAILED', 'Initialization failed', Error); E('ERR_ZLIB_INITIALIZATION_FAILED', 'Initialization failed', Error);
function invalidArgType(name, expected, actual) { function invalidArgType(name, expected, actual) {
internalAssert(arguments.length === 3, 'Exactly 3 arguments are required');
internalAssert(typeof name === 'string', 'name must be a string'); internalAssert(typeof name === 'string', 'name must be a string');
// determiner: 'must be' or 'must not be' // determiner: 'must be' or 'must not be'
@ -1007,8 +1018,7 @@ function missingArgs(...args) {
} }
function oneOf(expected, thing) { function oneOf(expected, thing) {
internalAssert(expected, 'expected is required'); internalAssert(typeof thing === 'string', '`thing` has to be of type string');
internalAssert(typeof thing === 'string', 'thing is required');
if (Array.isArray(expected)) { if (Array.isArray(expected)) {
const len = expected.length; const len = expected.length;
internalAssert(len > 0, internalAssert(len > 0,
@ -1027,17 +1037,20 @@ function oneOf(expected, thing) {
} }
} }
function bufferOutOfBounds(name, isWriting) { // Using a default argument here is important so the argument is not counted
if (isWriting) { // towards `Function#length`.
return 'Attempt to write outside buffer bounds'; function bufferOutOfBounds(name = undefined) {
} else { if (name) {
return `"${name}" is outside of buffer bounds`; return `"${name}" is outside of buffer bounds`;
} }
return 'Attempt to write outside buffer bounds';
} }
function invalidChar(name, field) { // Using a default argument here is important so the argument is not counted
// towards `Function#length`.
function invalidChar(name, field = undefined) {
let msg = `Invalid character in ${name}`; let msg = `Invalid character in ${name}`;
if (field) { if (field !== undefined) {
msg += ` ["${field}"]`; msg += ` ["${field}"]`;
} }
return msg; return msg;
@ -1045,7 +1058,7 @@ function invalidChar(name, field) {
function outOfRange(name, range, value) { function outOfRange(name, range, value) {
let msg = `The value of "${name}" is out of range.`; let msg = `The value of "${name}" is out of range.`;
if (range) msg += ` It must be ${range}.`; if (range !== undefined) msg += ` It must be ${range}.`;
if (value !== undefined) msg += ` Received ${value}`; msg += ` Received ${value}`;
return msg; return msg;
} }

View File

@ -368,9 +368,10 @@ function validateOffsetLengthRead(offset, length, bufferLength) {
let err; let err;
if (offset < 0 || offset >= bufferLength) { if (offset < 0 || offset >= bufferLength) {
err = new ERR_OUT_OF_RANGE('offset'); err = new ERR_OUT_OF_RANGE('offset', `>= 0 && <= ${bufferLength}`, offset);
} else if (length < 0 || offset + length > bufferLength) { } else if (length < 0 || offset + length > bufferLength) {
err = new ERR_OUT_OF_RANGE('length'); err = new ERR_OUT_OF_RANGE('length',
`>= 0 && <= ${bufferLength - offset}`, length);
} }
if (err !== undefined) { if (err !== undefined) {
@ -383,9 +384,12 @@ function validateOffsetLengthWrite(offset, length, byteLength) {
let err; let err;
if (offset > byteLength) { if (offset > byteLength) {
err = new ERR_OUT_OF_RANGE('offset'); err = new ERR_OUT_OF_RANGE('offset', `<= ${byteLength}`, offset);
} else if (offset + length > byteLength || offset + length > kMaxLength) { } else {
err = new ERR_OUT_OF_RANGE('length'); const max = byteLength > kMaxLength ? kMaxLength : byteLength;
if (length > max - offset) {
err = new ERR_OUT_OF_RANGE('length', `<= ${max - offset}`, length);
}
} }
if (err !== undefined) { if (err !== undefined) {

View File

@ -1312,8 +1312,10 @@ class ServerHttp2Session extends Http2Session {
if (origin === 'null') if (origin === 'null')
throw new ERR_HTTP2_ALTSVC_INVALID_ORIGIN(); throw new ERR_HTTP2_ALTSVC_INVALID_ORIGIN();
} else if (typeof originOrStream === 'number') { } else if (typeof originOrStream === 'number') {
if (originOrStream >>> 0 !== originOrStream || originOrStream === 0) if (originOrStream >>> 0 !== originOrStream || originOrStream === 0) {
throw new ERR_OUT_OF_RANGE('originOrStream'); throw new ERR_OUT_OF_RANGE('originOrStream',
`> 0 && < ${2 ** 32}`, originOrStream);
}
stream = originOrStream; stream = originOrStream;
} else if (originOrStream !== undefined) { } else if (originOrStream !== undefined) {
// Allow origin to be passed a URL or object with origin property // Allow origin to be passed a URL or object with origin property
@ -1764,7 +1766,7 @@ class Http2Stream extends Duplex {
if (typeof code !== 'number') if (typeof code !== 'number')
throw new ERR_INVALID_ARG_TYPE('code', 'number', code); throw new ERR_INVALID_ARG_TYPE('code', 'number', code);
if (code < 0 || code > kMaxInt) if (code < 0 || code > kMaxInt)
throw new ERR_OUT_OF_RANGE('code'); throw new ERR_OUT_OF_RANGE('code', `>= 0 && <= ${kMaxInt}`, code);
if (callback !== undefined && typeof callback !== 'function') if (callback !== undefined && typeof callback !== 'function')
throw new ERR_INVALID_CALLBACK(); throw new ERR_INVALID_CALLBACK();

View File

@ -1,6 +1,6 @@
'use strict'; 'use strict';
const common = require('../common'); require('../common');
const assert = require('assert'); const assert = require('assert');
const LENGTH = 16; const LENGTH = 16;
@ -58,14 +58,14 @@ assert.throws(function() {
buf[0] = 9; buf[0] = 9;
assert.strictEqual(ab[1], 9); assert.strictEqual(ab[1], 9);
common.expectsError(() => Buffer.from(ab.buffer, 6), { assert.throws(() => Buffer.from(ab.buffer, 6), {
code: 'ERR_BUFFER_OUT_OF_BOUNDS', code: 'ERR_BUFFER_OUT_OF_BOUNDS',
type: RangeError, name: 'RangeError [ERR_BUFFER_OUT_OF_BOUNDS]',
message: '"offset" is outside of buffer bounds' message: '"offset" is outside of buffer bounds'
}); });
common.expectsError(() => Buffer.from(ab.buffer, 3, 6), { assert.throws(() => Buffer.from(ab.buffer, 3, 6), {
code: 'ERR_BUFFER_OUT_OF_BOUNDS', code: 'ERR_BUFFER_OUT_OF_BOUNDS',
type: RangeError, name: 'RangeError [ERR_BUFFER_OUT_OF_BOUNDS]',
message: '"length" is outside of buffer bounds' message: '"length" is outside of buffer bounds'
}); });
} }
@ -86,14 +86,14 @@ assert.throws(function() {
buf[0] = 9; buf[0] = 9;
assert.strictEqual(ab[1], 9); assert.strictEqual(ab[1], 9);
common.expectsError(() => Buffer(ab.buffer, 6), { assert.throws(() => Buffer(ab.buffer, 6), {
code: 'ERR_BUFFER_OUT_OF_BOUNDS', code: 'ERR_BUFFER_OUT_OF_BOUNDS',
type: RangeError, name: 'RangeError [ERR_BUFFER_OUT_OF_BOUNDS]',
message: '"offset" is outside of buffer bounds' message: '"offset" is outside of buffer bounds'
}); });
common.expectsError(() => Buffer(ab.buffer, 3, 6), { assert.throws(() => Buffer(ab.buffer, 3, 6), {
code: 'ERR_BUFFER_OUT_OF_BOUNDS', code: 'ERR_BUFFER_OUT_OF_BOUNDS',
type: RangeError, name: 'RangeError [ERR_BUFFER_OUT_OF_BOUNDS]',
message: '"length" is outside of buffer bounds' message: '"length" is outside of buffer bounds'
}); });
} }
@ -111,11 +111,11 @@ assert.throws(function() {
assert.deepStrictEqual(Buffer.from(ab, [1]), Buffer.from(ab, 1)); assert.deepStrictEqual(Buffer.from(ab, [1]), Buffer.from(ab, 1));
// If byteOffset is Infinity, throw. // If byteOffset is Infinity, throw.
common.expectsError(() => { assert.throws(() => {
Buffer.from(ab, Infinity); Buffer.from(ab, Infinity);
}, { }, {
code: 'ERR_BUFFER_OUT_OF_BOUNDS', code: 'ERR_BUFFER_OUT_OF_BOUNDS',
type: RangeError, name: 'RangeError [ERR_BUFFER_OUT_OF_BOUNDS]',
message: '"offset" is outside of buffer bounds' message: '"offset" is outside of buffer bounds'
}); });
} }
@ -133,11 +133,11 @@ assert.throws(function() {
assert.deepStrictEqual(Buffer.from(ab, 0, [1]), Buffer.from(ab, 0, 1)); assert.deepStrictEqual(Buffer.from(ab, 0, [1]), Buffer.from(ab, 0, 1));
// If length is Infinity, throw. // If length is Infinity, throw.
common.expectsError(() => { assert.throws(() => {
Buffer.from(ab, 0, Infinity); Buffer.from(ab, 0, Infinity);
}, { }, {
code: 'ERR_BUFFER_OUT_OF_BOUNDS', code: 'ERR_BUFFER_OUT_OF_BOUNDS',
type: RangeError, name: 'RangeError [ERR_BUFFER_OUT_OF_BOUNDS]',
message: '"length" is outside of buffer bounds' message: '"length" is outside of buffer bounds'
}); });
} }

View File

@ -31,18 +31,26 @@ const n = fork(fixtures.path('child-process-spawn-node.js'), args);
assert.strictEqual(n.channel, n._channel); assert.strictEqual(n.channel, n._channel);
assert.deepStrictEqual(args, ['foo', 'bar']); assert.deepStrictEqual(args, ['foo', 'bar']);
n.on('message', function(m) { n.on('message', (m) => {
console.log('PARENT got message:', m); console.log('PARENT got message:', m);
assert.ok(m.foo); assert.ok(m.foo);
}); });
// https://github.com/joyent/node/issues/2355 - JSON.stringify(undefined) // https://github.com/joyent/node/issues/2355 - JSON.stringify(undefined)
// returns "undefined" but JSON.parse() cannot parse that... // returns "undefined" but JSON.parse() cannot parse that...
assert.throws(function() { n.send(undefined); }, TypeError); assert.throws(() => n.send(undefined), {
assert.throws(function() { n.send(); }, TypeError); name: 'TypeError [ERR_MISSING_ARGS]',
message: 'The "message" argument must be specified',
code: 'ERR_MISSING_ARGS'
});
assert.throws(() => n.send(), {
name: 'TypeError [ERR_MISSING_ARGS]',
message: 'The "message" argument must be specified',
code: 'ERR_MISSING_ARGS'
});
n.send({ hello: 'world' }); n.send({ hello: 'world' });
n.on('exit', common.mustCall(function(c) { n.on('exit', common.mustCall((c) => {
assert.strictEqual(c, 0); assert.strictEqual(c, 0);
})); }));

View File

@ -57,45 +57,46 @@ function ondone(err, key) {
} }
// Error path should not leak memory (check with valgrind). // Error path should not leak memory (check with valgrind).
common.expectsError( assert.throws(
() => crypto.pbkdf2('password', 'salt', 1, 20, null), () => crypto.pbkdf2('password', 'salt', 1, 20, null),
{ {
code: 'ERR_INVALID_CALLBACK', code: 'ERR_INVALID_CALLBACK',
type: TypeError name: 'TypeError [ERR_INVALID_CALLBACK]'
} }
); );
common.expectsError( assert.throws(
() => crypto.pbkdf2Sync('password', 'salt', -1, 20, null), () => crypto.pbkdf2Sync('password', 'salt', -1, 20, null),
{ {
code: 'ERR_OUT_OF_RANGE', code: 'ERR_OUT_OF_RANGE',
type: RangeError, name: 'RangeError [ERR_OUT_OF_RANGE]',
message: 'The value of "iterations" is out of range. ' + message: 'The value of "iterations" is out of range. ' +
'It must be a non-negative number. Received -1' 'It must be a non-negative number. Received -1'
} }
); );
['str', null, undefined, [], {}].forEach((notNumber) => { ['str', null, undefined, [], {}].forEach((notNumber) => {
common.expectsError( assert.throws(
() => { () => {
crypto.pbkdf2Sync('password', 'salt', 1, notNumber, 'sha256'); crypto.pbkdf2Sync('password', 'salt', 1, notNumber, 'sha256');
}, { }, {
code: 'ERR_INVALID_ARG_TYPE', code: 'ERR_INVALID_ARG_TYPE',
type: TypeError, name: 'TypeError [ERR_INVALID_ARG_TYPE]',
message: 'The "keylen" argument must be of type number. ' + message: 'The "keylen" argument must be of type number. ' +
`Received type ${typeof notNumber}` `Received type ${typeof notNumber}`
}); });
}); });
[Infinity, -Infinity, NaN, -1, 4073741824, INT_MAX + 1].forEach((i) => { [Infinity, -Infinity, NaN, -1, 4073741824, INT_MAX + 1].forEach((input) => {
common.expectsError( assert.throws(
() => { () => {
crypto.pbkdf2('password', 'salt', 1, i, 'sha256', crypto.pbkdf2('password', 'salt', 1, input, 'sha256',
common.mustNotCall()); common.mustNotCall());
}, { }, {
code: 'ERR_OUT_OF_RANGE', code: 'ERR_OUT_OF_RANGE',
type: RangeError, name: 'RangeError [ERR_OUT_OF_RANGE]',
message: 'The value of "keylen" is out of range.' message: 'The value of "keylen" is out of range. It ' +
`must be >= 0 && <= 2147483647. Received ${input}`
}); });
}); });
@ -103,58 +104,58 @@ common.expectsError(
// https://github.com/nodejs/node/issues/8571 // https://github.com/nodejs/node/issues/8571
crypto.pbkdf2('', '', 1, 32, 'sha256', common.mustCall(assert.ifError)); crypto.pbkdf2('', '', 1, 32, 'sha256', common.mustCall(assert.ifError));
common.expectsError( assert.throws(
() => crypto.pbkdf2('password', 'salt', 8, 8, common.mustNotCall()), () => crypto.pbkdf2('password', 'salt', 8, 8, common.mustNotCall()),
{ {
code: 'ERR_INVALID_ARG_TYPE', code: 'ERR_INVALID_ARG_TYPE',
type: TypeError, name: 'TypeError [ERR_INVALID_ARG_TYPE]',
message: 'The "digest" argument must be one of type string or null. ' + message: 'The "digest" argument must be one of type string or null. ' +
'Received type undefined' 'Received type undefined'
}); });
common.expectsError( assert.throws(
() => crypto.pbkdf2Sync('password', 'salt', 8, 8), () => crypto.pbkdf2Sync('password', 'salt', 8, 8),
{ {
code: 'ERR_INVALID_ARG_TYPE', code: 'ERR_INVALID_ARG_TYPE',
type: TypeError, name: 'TypeError [ERR_INVALID_ARG_TYPE]',
message: 'The "digest" argument must be one of type string or null. ' + message: 'The "digest" argument must be one of type string or null. ' +
'Received type undefined' 'Received type undefined'
}); });
[1, {}, [], true, undefined, null].forEach((input) => { [1, {}, [], true, undefined, null].forEach((input) => {
const msgPart2 = `Buffer, or TypedArray. Received type ${typeof input}`; const msgPart2 = `Buffer, or TypedArray. Received type ${typeof input}`;
common.expectsError( assert.throws(
() => crypto.pbkdf2(input, 'salt', 8, 8, 'sha256', common.mustNotCall()), () => crypto.pbkdf2(input, 'salt', 8, 8, 'sha256', common.mustNotCall()),
{ {
code: 'ERR_INVALID_ARG_TYPE', code: 'ERR_INVALID_ARG_TYPE',
type: TypeError, name: 'TypeError [ERR_INVALID_ARG_TYPE]',
message: `The "password" argument must be one of type string, ${msgPart2}` message: `The "password" argument must be one of type string, ${msgPart2}`
} }
); );
common.expectsError( assert.throws(
() => crypto.pbkdf2('pass', input, 8, 8, 'sha256', common.mustNotCall()), () => crypto.pbkdf2('pass', input, 8, 8, 'sha256', common.mustNotCall()),
{ {
code: 'ERR_INVALID_ARG_TYPE', code: 'ERR_INVALID_ARG_TYPE',
type: TypeError, name: 'TypeError [ERR_INVALID_ARG_TYPE]',
message: `The "salt" argument must be one of type string, ${msgPart2}` message: `The "salt" argument must be one of type string, ${msgPart2}`
} }
); );
common.expectsError( assert.throws(
() => crypto.pbkdf2Sync(input, 'salt', 8, 8, 'sha256'), () => crypto.pbkdf2Sync(input, 'salt', 8, 8, 'sha256'),
{ {
code: 'ERR_INVALID_ARG_TYPE', code: 'ERR_INVALID_ARG_TYPE',
type: TypeError, name: 'TypeError [ERR_INVALID_ARG_TYPE]',
message: `The "password" argument must be one of type string, ${msgPart2}` message: `The "password" argument must be one of type string, ${msgPart2}`
} }
); );
common.expectsError( assert.throws(
() => crypto.pbkdf2Sync('pass', input, 8, 8, 'sha256'), () => crypto.pbkdf2Sync('pass', input, 8, 8, 'sha256'),
{ {
code: 'ERR_INVALID_ARG_TYPE', code: 'ERR_INVALID_ARG_TYPE',
type: TypeError, name: 'TypeError [ERR_INVALID_ARG_TYPE]',
message: `The "salt" argument must be one of type string, ${msgPart2}` message: `The "salt" argument must be one of type string, ${msgPart2}`
} }
); );
@ -162,20 +163,20 @@ common.expectsError(
['test', {}, [], true, undefined, null].forEach((i) => { ['test', {}, [], true, undefined, null].forEach((i) => {
const received = `Received type ${typeof i}`; const received = `Received type ${typeof i}`;
common.expectsError( assert.throws(
() => crypto.pbkdf2('pass', 'salt', i, 8, 'sha256', common.mustNotCall()), () => crypto.pbkdf2('pass', 'salt', i, 8, 'sha256', common.mustNotCall()),
{ {
code: 'ERR_INVALID_ARG_TYPE', code: 'ERR_INVALID_ARG_TYPE',
type: TypeError, name: 'TypeError [ERR_INVALID_ARG_TYPE]',
message: `The "iterations" argument must be of type number. ${received}` message: `The "iterations" argument must be of type number. ${received}`
} }
); );
common.expectsError( assert.throws(
() => crypto.pbkdf2Sync('pass', 'salt', i, 8, 'sha256'), () => crypto.pbkdf2Sync('pass', 'salt', i, 8, 'sha256'),
{ {
code: 'ERR_INVALID_ARG_TYPE', code: 'ERR_INVALID_ARG_TYPE',
type: TypeError, name: 'TypeError [ERR_INVALID_ARG_TYPE]',
message: `The "iterations" argument must be of type number. ${received}` message: `The "iterations" argument must be of type number. ${received}`
} }
); );
@ -204,20 +205,20 @@ crypto.pbkdf2Sync('pass', new Float32Array(10), 8, 8, 'sha256');
crypto.pbkdf2Sync(new Float64Array(10), 'salt', 8, 8, 'sha256'); crypto.pbkdf2Sync(new Float64Array(10), 'salt', 8, 8, 'sha256');
crypto.pbkdf2Sync('pass', new Float64Array(10), 8, 8, 'sha256'); crypto.pbkdf2Sync('pass', new Float64Array(10), 8, 8, 'sha256');
common.expectsError( assert.throws(
() => crypto.pbkdf2('pass', 'salt', 8, 8, 'md55', common.mustNotCall()), () => crypto.pbkdf2('pass', 'salt', 8, 8, 'md55', common.mustNotCall()),
{ {
code: 'ERR_CRYPTO_INVALID_DIGEST', code: 'ERR_CRYPTO_INVALID_DIGEST',
type: TypeError, name: 'TypeError [ERR_CRYPTO_INVALID_DIGEST]',
message: 'Invalid digest: md55' message: 'Invalid digest: md55'
} }
); );
common.expectsError( assert.throws(
() => crypto.pbkdf2Sync('pass', 'salt', 8, 8, 'md55'), () => crypto.pbkdf2Sync('pass', 'salt', 8, 8, 'md55'),
{ {
code: 'ERR_CRYPTO_INVALID_DIGEST', code: 'ERR_CRYPTO_INVALID_DIGEST',
type: TypeError, name: 'TypeError [ERR_CRYPTO_INVALID_DIGEST]',
message: 'Invalid digest: md55' message: 'Invalid digest: md55'
} }
); );

View File

@ -1,19 +1,17 @@
// Flags: --expose-internals // Flags: --expose-internals
'use strict'; 'use strict';
const common = require('../common'); require('../common');
const assert = require('assert'); const assert = require('assert');
const errors = require('internal/errors'); const errors = require('internal/errors');
const { AssertionError } = require('assert');
const { E, SystemError } = errors; const { E, SystemError } = errors;
common.expectsError( assert.throws(
() => { throw new errors.SystemError(); }, () => { throw new errors.SystemError(); },
{ {
code: 'ERR_ASSERTION', name: 'TypeError',
type: AssertionError, message: 'Cannot read property \'match\' of undefined'
message: 'An invalid error message key was used: undefined.'
} }
); );
@ -29,11 +27,11 @@ const { ERR_TEST } = errors.codes;
dest: '/str2' dest: '/str2'
}; };
common.expectsError( assert.throws(
() => { throw new ERR_TEST(ctx); }, () => { throw new ERR_TEST(ctx); },
{ {
code: 'ERR_TEST', code: 'ERR_TEST',
type: SystemError, name: 'SystemError [ERR_TEST]',
message: 'custom message: syscall_test returned ETEST (code message)' + message: 'custom message: syscall_test returned ETEST (code message)' +
' /str => /str2', ' /str => /str2',
info: ctx info: ctx
@ -49,11 +47,11 @@ const { ERR_TEST } = errors.codes;
path: Buffer.from('/buf'), path: Buffer.from('/buf'),
dest: '/str2' dest: '/str2'
}; };
common.expectsError( assert.throws(
() => { throw new ERR_TEST(ctx); }, () => { throw new ERR_TEST(ctx); },
{ {
code: 'ERR_TEST', code: 'ERR_TEST',
type: SystemError, name: 'SystemError [ERR_TEST]',
message: 'custom message: syscall_test returned ETEST (code message)' + message: 'custom message: syscall_test returned ETEST (code message)' +
' /buf => /str2', ' /buf => /str2',
info: ctx info: ctx
@ -69,11 +67,11 @@ const { ERR_TEST } = errors.codes;
path: Buffer.from('/buf'), path: Buffer.from('/buf'),
dest: Buffer.from('/buf2') dest: Buffer.from('/buf2')
}; };
common.expectsError( assert.throws(
() => { throw new ERR_TEST(ctx); }, () => { throw new ERR_TEST(ctx); },
{ {
code: 'ERR_TEST', code: 'ERR_TEST',
type: SystemError, name: 'SystemError [ERR_TEST]',
message: 'custom message: syscall_test returned ETEST (code message)' + message: 'custom message: syscall_test returned ETEST (code message)' +
' /buf => /buf2', ' /buf => /buf2',
info: ctx info: ctx

View File

@ -70,19 +70,19 @@ fs.fchmodSync(1, modeUpperBoundaryValue);
// umask of 0o777 is equal to 775 // umask of 0o777 is equal to 775
const modeOutsideUpperBoundValue = 776; const modeOutsideUpperBoundValue = 776;
common.expectsError( assert.throws(
() => fs.fchmod(1, modeOutsideUpperBoundValue), () => fs.fchmod(1, modeOutsideUpperBoundValue),
{ {
code: 'ERR_OUT_OF_RANGE', code: 'ERR_OUT_OF_RANGE',
type: RangeError, name: 'RangeError [ERR_OUT_OF_RANGE]',
message: 'The value of "mode" is out of range.' message: 'The value of "mode" is out of range. Received 776'
} }
); );
common.expectsError( assert.throws(
() => fs.fchmodSync(1, modeOutsideUpperBoundValue), () => fs.fchmodSync(1, modeOutsideUpperBoundValue),
{ {
code: 'ERR_OUT_OF_RANGE', code: 'ERR_OUT_OF_RANGE',
type: RangeError, name: 'RangeError [ERR_OUT_OF_RANGE]',
message: 'The value of "mode" is out of range.' message: 'The value of "mode" is out of range. Received 776'
} }
); );

View File

@ -1,6 +1,7 @@
'use strict'; 'use strict';
const common = require('../common'); const common = require('../common');
const fs = require('fs'); const fs = require('fs');
const assert = require('assert');
const fixtures = require('../common/fixtures'); const fixtures = require('../common/fixtures');
const filepath = fixtures.path('x.txt'); const filepath = fixtures.path('x.txt');
@ -9,18 +10,18 @@ const expected = 'xyz\n';
// Error must be thrown with string // Error must be thrown with string
common.expectsError( assert.throws(
() => fs.read(fd, expected.length, 0, 'utf-8', common.mustNotCall()), () => fs.read(fd, expected.length, 0, 'utf-8', common.mustNotCall()),
{ {
code: 'ERR_INVALID_ARG_TYPE', code: 'ERR_INVALID_ARG_TYPE',
type: TypeError, name: 'TypeError [ERR_INVALID_ARG_TYPE]',
message: 'The "buffer" argument must be one of type Buffer or Uint8Array.' + message: 'The "buffer" argument must be one of type Buffer or Uint8Array.' +
' Received type number' ' Received type number'
} }
); );
[true, null, undefined, () => {}, {}].forEach((value) => { [true, null, undefined, () => {}, {}].forEach((value) => {
common.expectsError(() => { assert.throws(() => {
fs.read(value, fs.read(value,
Buffer.allocUnsafe(expected.length), Buffer.allocUnsafe(expected.length),
0, 0,
@ -29,45 +30,53 @@ common.expectsError(
common.mustNotCall()); common.mustNotCall());
}, { }, {
code: 'ERR_INVALID_ARG_TYPE', code: 'ERR_INVALID_ARG_TYPE',
type: TypeError, name: 'TypeError [ERR_INVALID_ARG_TYPE]',
message: 'The "fd" argument must be of type number. ' + message: 'The "fd" argument must be of type number. ' +
`Received type ${typeof value}` `Received type ${typeof value}`
}); });
}); });
common.expectsError(() => { assert.throws(() => {
fs.read(fd, fs.read(fd,
Buffer.allocUnsafe(expected.length), Buffer.allocUnsafe(expected.length),
-1, -1,
expected.length, expected.length,
0, 0,
common.mustNotCall()); common.mustNotCall());
}, { code: 'ERR_OUT_OF_RANGE', type: RangeError, }, {
message: 'The value of "offset" is out of range.' }); code: 'ERR_OUT_OF_RANGE',
name: 'RangeError [ERR_OUT_OF_RANGE]',
message: 'The value of "offset" is out of range. It must be >= 0 && <= 4. ' +
'Received -1'
});
common.expectsError(() => { assert.throws(() => {
fs.read(fd, fs.read(fd,
Buffer.allocUnsafe(expected.length), Buffer.allocUnsafe(expected.length),
0, 0,
-1, -1,
0, 0,
common.mustNotCall()); common.mustNotCall());
}, { code: 'ERR_OUT_OF_RANGE', type: RangeError, }, {
message: 'The value of "length" is out of range.' }); code: 'ERR_OUT_OF_RANGE',
name: 'RangeError [ERR_OUT_OF_RANGE]',
message: 'The value of "length" is out of range. ' +
'It must be >= 0 && <= 4. Received -1'
});
common.expectsError( assert.throws(
() => fs.readSync(fd, expected.length, 0, 'utf-8'), () => fs.readSync(fd, expected.length, 0, 'utf-8'),
{ {
code: 'ERR_INVALID_ARG_TYPE', code: 'ERR_INVALID_ARG_TYPE',
type: TypeError, name: 'TypeError [ERR_INVALID_ARG_TYPE]',
message: 'The "buffer" argument must be one of type Buffer or Uint8Array.' + message: 'The "buffer" argument must be one of type Buffer or Uint8Array.' +
' Received type number' ' Received type number'
} }
); );
[true, null, undefined, () => {}, {}].forEach((value) => { [true, null, undefined, () => {}, {}].forEach((value) => {
common.expectsError(() => { assert.throws(() => {
fs.readSync(value, fs.readSync(value,
Buffer.allocUnsafe(expected.length), Buffer.allocUnsafe(expected.length),
0, 0,
@ -75,26 +84,34 @@ common.expectsError(
0); 0);
}, { }, {
code: 'ERR_INVALID_ARG_TYPE', code: 'ERR_INVALID_ARG_TYPE',
type: TypeError, name: 'TypeError [ERR_INVALID_ARG_TYPE]',
message: 'The "fd" argument must be of type number. ' + message: 'The "fd" argument must be of type number. ' +
`Received type ${typeof value}` `Received type ${typeof value}`
}); });
}); });
common.expectsError(() => { assert.throws(() => {
fs.readSync(fd, fs.readSync(fd,
Buffer.allocUnsafe(expected.length), Buffer.allocUnsafe(expected.length),
-1, -1,
expected.length, expected.length,
0); 0);
}, { code: 'ERR_OUT_OF_RANGE', type: RangeError, }, {
message: 'The value of "offset" is out of range.' }); code: 'ERR_OUT_OF_RANGE',
name: 'RangeError [ERR_OUT_OF_RANGE]',
message: 'The value of "offset" is out of range. ' +
'It must be >= 0 && <= 4. Received -1'
});
common.expectsError(() => { assert.throws(() => {
fs.readSync(fd, fs.readSync(fd,
Buffer.allocUnsafe(expected.length), Buffer.allocUnsafe(expected.length),
0, 0,
-1, -1,
0); 0);
}, { code: 'ERR_OUT_OF_RANGE', type: RangeError, }, {
message: 'The value of "length" is out of range.' }); code: 'ERR_OUT_OF_RANGE',
name: 'RangeError [ERR_OUT_OF_RANGE]',
message: 'The value of "length" is out of range. ' +
'It must be >= 0 && <= 4. Received -1'
});

View File

@ -28,43 +28,46 @@ server.on('session', common.mustCall((session) => {
session.altsvc('h2=":8000"', 3); session.altsvc('h2=":8000"', 3);
// Will error because the numeric stream id is out of valid range // Will error because the numeric stream id is out of valid range
[0, -1, 1.1, 0xFFFFFFFF + 1, Infinity, -Infinity].forEach((i) => { [0, -1, 1.1, 0xFFFFFFFF + 1, Infinity, -Infinity].forEach((input) => {
common.expectsError( assert.throws(
() => session.altsvc('h2=":8000"', i), () => session.altsvc('h2=":8000"', input),
{ {
code: 'ERR_OUT_OF_RANGE', code: 'ERR_OUT_OF_RANGE',
type: RangeError name: 'RangeError [ERR_OUT_OF_RANGE]',
message: 'The value of "originOrStream" is out of ' +
`range. It must be > 0 && < 4294967296. Received ${input}`
} }
); );
}); });
// First argument must be a string // First argument must be a string
[0, {}, [], null, Infinity].forEach((i) => { [0, {}, [], null, Infinity].forEach((input) => {
common.expectsError( assert.throws(
() => session.altsvc(i), () => session.altsvc(input),
{ {
code: 'ERR_INVALID_ARG_TYPE', code: 'ERR_INVALID_ARG_TYPE',
type: TypeError name: 'TypeError [ERR_INVALID_ARG_TYPE]'
} }
); );
}); });
['\u0001', 'h2="\uff20"', '👀'].forEach((i) => { ['\u0001', 'h2="\uff20"', '👀'].forEach((input) => {
common.expectsError( assert.throws(
() => session.altsvc(i), () => session.altsvc(input),
{ {
code: 'ERR_INVALID_CHAR', code: 'ERR_INVALID_CHAR',
type: TypeError name: 'TypeError [ERR_INVALID_CHAR]',
message: 'Invalid character in alt'
} }
); );
}); });
[{}, [], true].forEach((i) => { [{}, [], true].forEach((input) => {
common.expectsError( assert.throws(
() => session.altsvc('clear', i), () => session.altsvc('clear', input),
{ {
code: 'ERR_INVALID_ARG_TYPE', code: 'ERR_INVALID_ARG_TYPE',
type: TypeError name: 'TypeError [ERR_INVALID_ARG_TYPE]'
} }
); );
}); });
@ -74,25 +77,27 @@ server.on('session', common.mustCall((session) => {
new URL('abc:'), new URL('abc:'),
{ origin: 'null' }, { origin: 'null' },
{ origin: '' } { origin: '' }
].forEach((i) => { ].forEach((input) => {
common.expectsError( assert.throws(
() => session.altsvc('h2=":8000', i), () => session.altsvc('h2=":8000', input),
{ {
code: 'ERR_HTTP2_ALTSVC_INVALID_ORIGIN', code: 'ERR_HTTP2_ALTSVC_INVALID_ORIGIN',
type: TypeError name: 'TypeError [ERR_HTTP2_ALTSVC_INVALID_ORIGIN]',
message: 'HTTP/2 ALTSVC frames require a valid origin'
} }
); );
}); });
// arguments + origin are too long for an ALTSVC frame // arguments + origin are too long for an ALTSVC frame
common.expectsError( assert.throws(
() => { () => {
session.altsvc('h2=":8000"', session.altsvc('h2=":8000"',
`http://example.${'a'.repeat(17000)}.org:8000`); `http://example.${'a'.repeat(17000)}.org:8000`);
}, },
{ {
code: 'ERR_HTTP2_ALTSVC_LENGTH', code: 'ERR_HTTP2_ALTSVC_LENGTH',
type: TypeError name: 'TypeError [ERR_HTTP2_ALTSVC_LENGTH]',
message: 'HTTP/2 ALTSVC frames are limited to 16382 bytes'
} }
); );
})); }));

View File

@ -18,12 +18,13 @@ server.listen(0, common.mustCall(() => {
const req = client.request(); const req = client.request();
const closeCode = 1; const closeCode = 1;
common.expectsError( assert.throws(
() => req.close(2 ** 32), () => req.close(2 ** 32),
{ {
type: RangeError, name: 'RangeError [ERR_OUT_OF_RANGE]',
code: 'ERR_OUT_OF_RANGE', code: 'ERR_OUT_OF_RANGE',
message: 'The value of "code" is out of range.' message: 'The value of "code" is out of range. It must be ' +
'>= 0 && <= 4294967295. Received 4294967296'
} }
); );
assert.strictEqual(req.closed, false); assert.strictEqual(req.closed, false);

View File

@ -42,11 +42,13 @@ errors.E('TEST_ERROR_2', (a, b) => `${a} ${b}`, Error);
} }
{ {
const err = new errors.codes.TEST_ERROR_1(); assert.throws(
assert(err instanceof Error); () => new errors.codes.TEST_ERROR_1(),
assert.strictEqual(err.name, 'Error [TEST_ERROR_1]'); {
assert.strictEqual(err.message, 'Error for testing purposes: %s'); message: 'Code: TEST_ERROR_1; The provided arguments ' +
assert.strictEqual(err.code, 'TEST_ERROR_1'); 'length (0) does not match the required ones (1).'
}
);
} }
// Tests for common.expectsError // Tests for common.expectsError
@ -156,16 +158,6 @@ assert.strictEqual(
'Method must be a valid HTTP token ["foo"]' 'Method must be a valid HTTP token ["foo"]'
); );
assert.strictEqual(
errors.message('ERR_OUT_OF_RANGE', ['A']),
'The value of "A" is out of range.'
);
assert.strictEqual(
errors.message('ERR_OUT_OF_RANGE', ['A', 'some values']),
'The value of "A" is out of range. It must be some values.'
);
assert.strictEqual( assert.strictEqual(
errors.message('ERR_OUT_OF_RANGE', ['A', 'some values', 'B']), errors.message('ERR_OUT_OF_RANGE', ['A', 'some values', 'B']),
'The value of "A" is out of range. It must be some values. Received B' 'The value of "A" is out of range. It must be some values. Received B'

View File

@ -1,16 +1,15 @@
'use strict'; 'use strict';
// Flags: --expose-internals
const common = require('../common'); const common = require('../common');
const tty = require('tty'); const tty = require('tty');
const { SystemError } = require('internal/errors');
const uv = process.binding('uv'); const uv = process.binding('uv');
const assert = require('assert');
common.expectsError( assert.throws(
() => new tty.WriteStream(-1), () => new tty.WriteStream(-1),
{ {
code: 'ERR_INVALID_FD', code: 'ERR_INVALID_FD',
type: RangeError, name: 'RangeError [ERR_INVALID_FD]',
message: '"fd" must be a positive integer: -1' message: '"fd" must be a positive integer: -1'
} }
); );
@ -27,37 +26,37 @@ common.expectsError(
'EBADF (bad file descriptor)' : 'EINVAL (invalid argument)'; 'EBADF (bad file descriptor)' : 'EINVAL (invalid argument)';
const message = `TTY initialization failed: uv_tty_init returned ${suffix}`; const message = `TTY initialization failed: uv_tty_init returned ${suffix}`;
common.expectsError( assert.throws(
() => { () => {
common.runWithInvalidFD((fd) => { common.runWithInvalidFD((fd) => {
new tty.WriteStream(fd); new tty.WriteStream(fd);
}); });
}, { }, {
code: 'ERR_TTY_INIT_FAILED', code: 'ERR_TTY_INIT_FAILED',
type: SystemError, name: 'SystemError [ERR_TTY_INIT_FAILED]',
message, message,
info info
} }
); );
common.expectsError( assert.throws(
() => { () => {
common.runWithInvalidFD((fd) => { common.runWithInvalidFD((fd) => {
new tty.ReadStream(fd); new tty.ReadStream(fd);
}); });
}, { }, {
code: 'ERR_TTY_INIT_FAILED', code: 'ERR_TTY_INIT_FAILED',
type: SystemError, name: 'SystemError [ERR_TTY_INIT_FAILED]',
message, message,
info info
}); });
} }
common.expectsError( assert.throws(
() => new tty.ReadStream(-1), () => new tty.ReadStream(-1),
{ {
code: 'ERR_INVALID_FD', code: 'ERR_INVALID_FD',
type: RangeError, name: 'RangeError [ERR_INVALID_FD]',
message: '"fd" must be a positive integer: -1' message: '"fd" must be a positive integer: -1'
} }
); );