lib: introduce internal/validators
Create a file to centralize argument validators that are used in multiple internal modules. Move validateInt32 and validateUint32 to this file. PR-URL: https://github.com/nodejs/node/pull/19973 Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
d5e363b77e
commit
e836128703
16
lib/fs.js
16
lib/fs.js
@ -51,7 +51,6 @@ const internalUtil = require('internal/util');
|
|||||||
const {
|
const {
|
||||||
copyObject,
|
copyObject,
|
||||||
getOptions,
|
getOptions,
|
||||||
isUint32,
|
|
||||||
modeNum,
|
modeNum,
|
||||||
nullCheck,
|
nullCheck,
|
||||||
preprocessSymlinkDestination,
|
preprocessSymlinkDestination,
|
||||||
@ -61,16 +60,19 @@ const {
|
|||||||
stringToSymlinkType,
|
stringToSymlinkType,
|
||||||
toUnixTimestamp,
|
toUnixTimestamp,
|
||||||
validateBuffer,
|
validateBuffer,
|
||||||
validateLen,
|
|
||||||
validateOffsetLengthRead,
|
validateOffsetLengthRead,
|
||||||
validateOffsetLengthWrite,
|
validateOffsetLengthWrite,
|
||||||
validatePath,
|
validatePath
|
||||||
validateUint32
|
|
||||||
} = internalFS;
|
} = internalFS;
|
||||||
const {
|
const {
|
||||||
CHAR_FORWARD_SLASH,
|
CHAR_FORWARD_SLASH,
|
||||||
CHAR_BACKWARD_SLASH,
|
CHAR_BACKWARD_SLASH,
|
||||||
} = require('internal/constants');
|
} = require('internal/constants');
|
||||||
|
const {
|
||||||
|
isUint32,
|
||||||
|
validateInt32,
|
||||||
|
validateUint32
|
||||||
|
} = require('internal/validators');
|
||||||
|
|
||||||
Object.defineProperty(exports, 'constants', {
|
Object.defineProperty(exports, 'constants', {
|
||||||
configurable: false,
|
configurable: false,
|
||||||
@ -755,8 +757,8 @@ fs.ftruncate = function(fd, len = 0, callback) {
|
|||||||
// TODO(BridgeAR): This does not seem right.
|
// TODO(BridgeAR): This does not seem right.
|
||||||
// There does not seem to be any validation before and if there is any, it
|
// There does not seem to be any validation before and if there is any, it
|
||||||
// should work similar to validateUint32 or not have a upper cap at all.
|
// should work similar to validateUint32 or not have a upper cap at all.
|
||||||
// This applies to all usage of `validateLen`.
|
// This applies to all usage of `validateInt32(len, 'len')`.
|
||||||
validateLen(len);
|
validateInt32(len, 'len');
|
||||||
len = Math.max(0, len);
|
len = Math.max(0, len);
|
||||||
const req = new FSReqWrap();
|
const req = new FSReqWrap();
|
||||||
req.oncomplete = makeCallback(callback);
|
req.oncomplete = makeCallback(callback);
|
||||||
@ -765,7 +767,7 @@ fs.ftruncate = function(fd, len = 0, callback) {
|
|||||||
|
|
||||||
fs.ftruncateSync = function(fd, len = 0) {
|
fs.ftruncateSync = function(fd, len = 0) {
|
||||||
validateUint32(fd, 'fd');
|
validateUint32(fd, 'fd');
|
||||||
validateLen(len);
|
validateInt32(len, 'len');
|
||||||
len = Math.max(0, len);
|
len = Math.max(0, len);
|
||||||
const ctx = {};
|
const ctx = {};
|
||||||
binding.ftruncate(fd, len, undefined, ctx);
|
binding.ftruncate(fd, len, undefined, ctx);
|
||||||
|
@ -24,7 +24,6 @@ const {
|
|||||||
copyObject,
|
copyObject,
|
||||||
getOptions,
|
getOptions,
|
||||||
getStatsFromBinding,
|
getStatsFromBinding,
|
||||||
isUint32,
|
|
||||||
modeNum,
|
modeNum,
|
||||||
nullCheck,
|
nullCheck,
|
||||||
preprocessSymlinkDestination,
|
preprocessSymlinkDestination,
|
||||||
@ -32,12 +31,15 @@ const {
|
|||||||
stringToSymlinkType,
|
stringToSymlinkType,
|
||||||
toUnixTimestamp,
|
toUnixTimestamp,
|
||||||
validateBuffer,
|
validateBuffer,
|
||||||
validateLen,
|
|
||||||
validateOffsetLengthRead,
|
validateOffsetLengthRead,
|
||||||
validateOffsetLengthWrite,
|
validateOffsetLengthWrite,
|
||||||
validatePath,
|
validatePath
|
||||||
validateUint32
|
|
||||||
} = require('internal/fs');
|
} = require('internal/fs');
|
||||||
|
const {
|
||||||
|
isUint32,
|
||||||
|
validateInt32,
|
||||||
|
validateUint32
|
||||||
|
} = require('internal/validators');
|
||||||
const pathModule = require('path');
|
const pathModule = require('path');
|
||||||
|
|
||||||
const kHandle = Symbol('handle');
|
const kHandle = Symbol('handle');
|
||||||
@ -275,7 +277,7 @@ async function truncate(path, len = 0) {
|
|||||||
|
|
||||||
async function ftruncate(handle, len = 0) {
|
async function ftruncate(handle, len = 0) {
|
||||||
validateFileHandle(handle);
|
validateFileHandle(handle);
|
||||||
validateLen(len);
|
validateInt32(len, 'len');
|
||||||
len = Math.max(0, len);
|
len = Math.max(0, len);
|
||||||
return binding.ftruncate(handle.fd, len, kUsePromises);
|
return binding.ftruncate(handle.fd, len, kUsePromises);
|
||||||
}
|
}
|
||||||
|
@ -70,9 +70,6 @@ function getOptions(options, defaultOptions) {
|
|||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isInt32(n) { return n === (n | 0); }
|
|
||||||
function isUint32(n) { return n === (n >>> 0); }
|
|
||||||
|
|
||||||
function modeNum(m, def) {
|
function modeNum(m, def) {
|
||||||
if (typeof m === 'number')
|
if (typeof m === 'number')
|
||||||
return m;
|
return m;
|
||||||
@ -341,26 +338,6 @@ function validateBuffer(buffer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateLen(len) {
|
|
||||||
let err;
|
|
||||||
|
|
||||||
if (!isInt32(len)) {
|
|
||||||
if (typeof len !== 'number') {
|
|
||||||
err = new ERR_INVALID_ARG_TYPE('len', 'number', len);
|
|
||||||
} else if (!Number.isInteger(len)) {
|
|
||||||
err = new ERR_OUT_OF_RANGE('len', 'an integer', len);
|
|
||||||
} else {
|
|
||||||
// 2 ** 31 === 2147483648
|
|
||||||
err = new ERR_OUT_OF_RANGE('len', '> -2147483649 && < 2147483648', len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err !== undefined) {
|
|
||||||
Error.captureStackTrace(err, validateLen);
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function validateOffsetLengthRead(offset, length, bufferLength) {
|
function validateOffsetLengthRead(offset, length, bufferLength) {
|
||||||
let err;
|
let err;
|
||||||
|
|
||||||
@ -410,28 +387,10 @@ function validatePath(path, propName = 'path') {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateUint32(value, propName) {
|
|
||||||
if (!isUint32(value)) {
|
|
||||||
let err;
|
|
||||||
if (typeof value !== 'number') {
|
|
||||||
err = new ERR_INVALID_ARG_TYPE(propName, 'number', value);
|
|
||||||
} else if (!Number.isInteger(value)) {
|
|
||||||
err = new ERR_OUT_OF_RANGE(propName, 'an integer', value);
|
|
||||||
} else {
|
|
||||||
// 2 ** 32 === 4294967296
|
|
||||||
err = new ERR_OUT_OF_RANGE(propName, '>= 0 && < 4294967296', value);
|
|
||||||
}
|
|
||||||
Error.captureStackTrace(err, validateUint32);
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
assertEncoding,
|
assertEncoding,
|
||||||
copyObject,
|
copyObject,
|
||||||
getOptions,
|
getOptions,
|
||||||
isInt32,
|
|
||||||
isUint32,
|
|
||||||
modeNum,
|
modeNum,
|
||||||
nullCheck,
|
nullCheck,
|
||||||
preprocessSymlinkDestination,
|
preprocessSymlinkDestination,
|
||||||
@ -443,9 +402,7 @@ module.exports = {
|
|||||||
SyncWriteStream,
|
SyncWriteStream,
|
||||||
toUnixTimestamp,
|
toUnixTimestamp,
|
||||||
validateBuffer,
|
validateBuffer,
|
||||||
validateLen,
|
|
||||||
validateOffsetLengthRead,
|
validateOffsetLengthRead,
|
||||||
validateOffsetLengthWrite,
|
validateOffsetLengthWrite,
|
||||||
validatePath,
|
validatePath
|
||||||
validateUint32
|
|
||||||
};
|
};
|
||||||
|
58
lib/internal/validators.js
Normal file
58
lib/internal/validators.js
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const {
|
||||||
|
ERR_INVALID_ARG_TYPE,
|
||||||
|
ERR_OUT_OF_RANGE
|
||||||
|
} = require('internal/errors').codes;
|
||||||
|
|
||||||
|
function isInt32(value) {
|
||||||
|
return value === (value | 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isUint32(value) {
|
||||||
|
return value === (value >>> 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateInt32(value, name) {
|
||||||
|
if (!isInt32(value)) {
|
||||||
|
let err;
|
||||||
|
if (typeof value !== 'number') {
|
||||||
|
err = new ERR_INVALID_ARG_TYPE(name, 'number', value);
|
||||||
|
} else if (!Number.isInteger(value)) {
|
||||||
|
err = new ERR_OUT_OF_RANGE(name, 'an integer', value);
|
||||||
|
} else {
|
||||||
|
// 2 ** 31 === 2147483648
|
||||||
|
err = new ERR_OUT_OF_RANGE(name, '> -2147483649 && < 2147483648', value);
|
||||||
|
}
|
||||||
|
Error.captureStackTrace(err, validateInt32);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateUint32(value, name, positive) {
|
||||||
|
if (!isUint32(value)) {
|
||||||
|
let err;
|
||||||
|
if (typeof value !== 'number') {
|
||||||
|
err = new ERR_INVALID_ARG_TYPE(name, 'number', value);
|
||||||
|
} else if (!Number.isInteger(value)) {
|
||||||
|
err = new ERR_OUT_OF_RANGE(name, 'an integer', value);
|
||||||
|
} else {
|
||||||
|
const min = positive ? 1 : 0;
|
||||||
|
// 2 ** 32 === 4294967296
|
||||||
|
err = new ERR_OUT_OF_RANGE(name, `>= ${min} && < 4294967296`, value);
|
||||||
|
}
|
||||||
|
Error.captureStackTrace(err, validateUint32);
|
||||||
|
throw err;
|
||||||
|
} else if (positive && value === 0) {
|
||||||
|
const err = new ERR_OUT_OF_RANGE(name, '>= 1 && < 4294967296', value);
|
||||||
|
Error.captureStackTrace(err, validateUint32);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
isInt32,
|
||||||
|
isUint32,
|
||||||
|
validateInt32,
|
||||||
|
validateUint32
|
||||||
|
};
|
@ -6,7 +6,6 @@ const { URL } = require('internal/url');
|
|||||||
const { isContext } = process.binding('contextify');
|
const { isContext } = process.binding('contextify');
|
||||||
const {
|
const {
|
||||||
ERR_INVALID_ARG_TYPE,
|
ERR_INVALID_ARG_TYPE,
|
||||||
ERR_OUT_OF_RANGE,
|
|
||||||
ERR_VM_MODULE_ALREADY_LINKED,
|
ERR_VM_MODULE_ALREADY_LINKED,
|
||||||
ERR_VM_MODULE_DIFFERENT_CONTEXT,
|
ERR_VM_MODULE_DIFFERENT_CONTEXT,
|
||||||
ERR_VM_MODULE_LINKING_ERRORED,
|
ERR_VM_MODULE_LINKING_ERRORED,
|
||||||
@ -19,6 +18,7 @@ const {
|
|||||||
customInspectSymbol,
|
customInspectSymbol,
|
||||||
} = require('internal/util');
|
} = require('internal/util');
|
||||||
const { SafePromise } = require('internal/safe_globals');
|
const { SafePromise } = require('internal/safe_globals');
|
||||||
|
const { validateInt32, validateUint32 } = require('internal/validators');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
ModuleWrap,
|
ModuleWrap,
|
||||||
@ -92,8 +92,8 @@ class Module {
|
|||||||
perContextModuleId.set(context, 1);
|
perContextModuleId.set(context, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
validateInteger(lineOffset, 'options.lineOffset');
|
validateInt32(lineOffset, 'options.lineOffset');
|
||||||
validateInteger(columnOffset, 'options.columnOffset');
|
validateInt32(columnOffset, 'options.columnOffset');
|
||||||
|
|
||||||
if (initializeImportMeta !== undefined) {
|
if (initializeImportMeta !== undefined) {
|
||||||
if (typeof initializeImportMeta === 'function') {
|
if (typeof initializeImportMeta === 'function') {
|
||||||
@ -203,9 +203,8 @@ class Module {
|
|||||||
let timeout = options.timeout;
|
let timeout = options.timeout;
|
||||||
if (timeout === undefined) {
|
if (timeout === undefined) {
|
||||||
timeout = -1;
|
timeout = -1;
|
||||||
} else if (!Number.isInteger(timeout) || timeout <= 0) {
|
} else {
|
||||||
throw new ERR_INVALID_ARG_TYPE('options.timeout', 'a positive integer',
|
validateUint32(timeout, 'options.timeout', true);
|
||||||
timeout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const { breakOnSigint = false } = options;
|
const { breakOnSigint = false } = options;
|
||||||
@ -243,15 +242,6 @@ class Module {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateInteger(prop, propName) {
|
|
||||||
if (!Number.isInteger(prop)) {
|
|
||||||
throw new ERR_INVALID_ARG_TYPE(propName, 'integer', prop);
|
|
||||||
}
|
|
||||||
if ((prop >> 0) !== prop) {
|
|
||||||
throw new ERR_OUT_OF_RANGE(propName, '32-bit integer', prop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
Module,
|
Module,
|
||||||
initImportMetaMap,
|
initImportMetaMap,
|
||||||
|
24
lib/vm.js
24
lib/vm.js
@ -28,11 +28,9 @@ const {
|
|||||||
isContext: _isContext,
|
isContext: _isContext,
|
||||||
} = process.binding('contextify');
|
} = process.binding('contextify');
|
||||||
|
|
||||||
const {
|
const { ERR_INVALID_ARG_TYPE } = require('internal/errors').codes;
|
||||||
ERR_INVALID_ARG_TYPE,
|
|
||||||
ERR_OUT_OF_RANGE
|
|
||||||
} = require('internal/errors').codes;
|
|
||||||
const { isUint8Array } = require('internal/util/types');
|
const { isUint8Array } = require('internal/util/types');
|
||||||
|
const { validateInt32, validateUint32 } = require('internal/validators');
|
||||||
|
|
||||||
class Script extends ContextifyScript {
|
class Script extends ContextifyScript {
|
||||||
constructor(code, options = {}) {
|
constructor(code, options = {}) {
|
||||||
@ -56,8 +54,8 @@ class Script extends ContextifyScript {
|
|||||||
if (typeof filename !== 'string') {
|
if (typeof filename !== 'string') {
|
||||||
throw new ERR_INVALID_ARG_TYPE('options.filename', 'string', filename);
|
throw new ERR_INVALID_ARG_TYPE('options.filename', 'string', filename);
|
||||||
}
|
}
|
||||||
validateInteger(lineOffset, 'options.lineOffset');
|
validateInt32(lineOffset, 'options.lineOffset');
|
||||||
validateInteger(columnOffset, 'options.columnOffset');
|
validateInt32(columnOffset, 'options.columnOffset');
|
||||||
if (cachedData !== undefined && !isUint8Array(cachedData)) {
|
if (cachedData !== undefined && !isUint8Array(cachedData)) {
|
||||||
throw new ERR_INVALID_ARG_TYPE('options.cachedData',
|
throw new ERR_INVALID_ARG_TYPE('options.cachedData',
|
||||||
['Buffer', 'Uint8Array'], cachedData);
|
['Buffer', 'Uint8Array'], cachedData);
|
||||||
@ -119,15 +117,6 @@ function validateContext(sandbox) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateInteger(prop, propName) {
|
|
||||||
if (!Number.isInteger(prop)) {
|
|
||||||
throw new ERR_INVALID_ARG_TYPE(propName, 'integer', prop);
|
|
||||||
}
|
|
||||||
if ((prop >> 0) !== prop) {
|
|
||||||
throw new ERR_OUT_OF_RANGE(propName, '32-bit integer', prop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function validateString(prop, propName) {
|
function validateString(prop, propName) {
|
||||||
if (prop !== undefined && typeof prop !== 'string')
|
if (prop !== undefined && typeof prop !== 'string')
|
||||||
throw new ERR_INVALID_ARG_TYPE(propName, 'string', prop);
|
throw new ERR_INVALID_ARG_TYPE(propName, 'string', prop);
|
||||||
@ -151,9 +140,8 @@ function getRunInContextArgs(options = {}) {
|
|||||||
let timeout = options.timeout;
|
let timeout = options.timeout;
|
||||||
if (timeout === undefined) {
|
if (timeout === undefined) {
|
||||||
timeout = -1;
|
timeout = -1;
|
||||||
} else if (!Number.isInteger(timeout) || timeout <= 0) {
|
} else {
|
||||||
throw new ERR_INVALID_ARG_TYPE('options.timeout', 'a positive integer',
|
validateUint32(timeout, 'options.timeout', true);
|
||||||
timeout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
1
node.gyp
1
node.gyp
@ -146,6 +146,7 @@
|
|||||||
'lib/internal/v8.js',
|
'lib/internal/v8.js',
|
||||||
'lib/internal/v8_prof_polyfill.js',
|
'lib/internal/v8_prof_polyfill.js',
|
||||||
'lib/internal/v8_prof_processor.js',
|
'lib/internal/v8_prof_processor.js',
|
||||||
|
'lib/internal/validators.js',
|
||||||
'lib/internal/stream_base_commons.js',
|
'lib/internal/stream_base_commons.js',
|
||||||
'lib/internal/vm/module.js',
|
'lib/internal/vm/module.js',
|
||||||
'lib/internal/streams/lazy_transform.js',
|
'lib/internal/streams/lazy_transform.js',
|
||||||
|
@ -17,7 +17,7 @@ common.expectsError(() => {
|
|||||||
new vm.Script('void 0', 42);
|
new vm.Script('void 0', 42);
|
||||||
}, invalidArgType);
|
}, invalidArgType);
|
||||||
|
|
||||||
[null, {}, [1], 'bad', true, 0.1].forEach((value) => {
|
[null, {}, [1], 'bad', true].forEach((value) => {
|
||||||
common.expectsError(() => {
|
common.expectsError(() => {
|
||||||
new vm.Script('void 0', { lineOffset: value });
|
new vm.Script('void 0', { lineOffset: value });
|
||||||
}, invalidArgType);
|
}, invalidArgType);
|
||||||
@ -27,6 +27,16 @@ common.expectsError(() => {
|
|||||||
}, invalidArgType);
|
}, invalidArgType);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
[0.1, 2 ** 32].forEach((value) => {
|
||||||
|
common.expectsError(() => {
|
||||||
|
new vm.Script('void 0', { lineOffset: value });
|
||||||
|
}, outOfRange);
|
||||||
|
|
||||||
|
common.expectsError(() => {
|
||||||
|
new vm.Script('void 0', { columnOffset: value });
|
||||||
|
}, outOfRange);
|
||||||
|
});
|
||||||
|
|
||||||
common.expectsError(() => {
|
common.expectsError(() => {
|
||||||
new vm.Script('void 0', { lineOffset: Number.MAX_SAFE_INTEGER });
|
new vm.Script('void 0', { lineOffset: Number.MAX_SAFE_INTEGER });
|
||||||
}, outOfRange);
|
}, outOfRange);
|
||||||
@ -53,26 +63,31 @@ common.expectsError(() => {
|
|||||||
const script = new vm.Script('void 0');
|
const script = new vm.Script('void 0');
|
||||||
const sandbox = vm.createContext();
|
const sandbox = vm.createContext();
|
||||||
|
|
||||||
function assertErrors(options) {
|
function assertErrors(options, errCheck) {
|
||||||
common.expectsError(() => {
|
common.expectsError(() => {
|
||||||
script.runInThisContext(options);
|
script.runInThisContext(options);
|
||||||
}, invalidArgType);
|
}, errCheck);
|
||||||
|
|
||||||
common.expectsError(() => {
|
common.expectsError(() => {
|
||||||
script.runInContext(sandbox, options);
|
script.runInContext(sandbox, options);
|
||||||
}, invalidArgType);
|
}, errCheck);
|
||||||
|
|
||||||
common.expectsError(() => {
|
common.expectsError(() => {
|
||||||
script.runInNewContext({}, options);
|
script.runInNewContext({}, options);
|
||||||
}, invalidArgType);
|
}, errCheck);
|
||||||
}
|
}
|
||||||
|
|
||||||
[null, 'bad', 42].forEach(assertErrors);
|
[null, 'bad', 42].forEach((value) => {
|
||||||
[{}, [1], 'bad', null, -1, 0, NaN].forEach((value) => {
|
assertErrors(value, invalidArgType);
|
||||||
assertErrors({ timeout: value });
|
});
|
||||||
|
[{}, [1], 'bad', null].forEach((value) => {
|
||||||
|
assertErrors({ timeout: value }, invalidArgType);
|
||||||
|
});
|
||||||
|
[-1, 0, NaN].forEach((value) => {
|
||||||
|
assertErrors({ timeout: value }, outOfRange);
|
||||||
});
|
});
|
||||||
[{}, [1], 'bad', 1, null].forEach((value) => {
|
[{}, [1], 'bad', 1, null].forEach((value) => {
|
||||||
assertErrors({ displayErrors: value });
|
assertErrors({ displayErrors: value }, invalidArgType);
|
||||||
assertErrors({ breakOnSigint: value });
|
assertErrors({ breakOnSigint: value }, invalidArgType);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user