Skip to content

Commit de1c243

Browse files
committed
fs: validate position argument before length === 0 early return
1 parent 68d7b6f commit de1c243

File tree

5 files changed

+84
-19
lines changed

5 files changed

+84
-19
lines changed

lib/fs.js

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,12 @@ function read(fd, buffer, offsetOrOptions, length, position, callback) {
640640

641641
length |= 0;
642642

643+
if (position == null) {
644+
position = -1;
645+
} else {
646+
validatePosition(position, 'position', length);
647+
}
648+
643649
if (length === 0) {
644650
return process.nextTick(function tick() {
645651
callback(null, 0, buffer);
@@ -653,12 +659,6 @@ function read(fd, buffer, offsetOrOptions, length, position, callback) {
653659

654660
validateOffsetLengthRead(offset, length, buffer.byteLength);
655661

656-
if (position == null) {
657-
position = -1;
658-
} else {
659-
validatePosition(position, 'position', length);
660-
}
661-
662662
function wrapper(err, bytesRead) {
663663
// Retain a reference to buffer so that it can't be GC'ed too soon.
664664
callback(err, bytesRead || 0, buffer);
@@ -711,6 +711,12 @@ function readSync(fd, buffer, offsetOrOptions, length, position) {
711711

712712
length |= 0;
713713

714+
if (position == null) {
715+
position = -1;
716+
} else {
717+
validatePosition(position, 'position', length);
718+
}
719+
714720
if (length === 0) {
715721
return 0;
716722
}
@@ -722,12 +728,6 @@ function readSync(fd, buffer, offsetOrOptions, length, position) {
722728

723729
validateOffsetLengthRead(offset, length, buffer.byteLength);
724730

725-
if (position == null) {
726-
position = -1;
727-
} else {
728-
validatePosition(position, 'position', length);
729-
}
730-
731731
return binding.read(fd, buffer, offset, length, position);
732732
}
733733

lib/internal/fs/promises.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,12 @@ async function read(handle, bufferOrParams, offset, length, position) {
674674

675675
length ??= buffer.byteLength - offset;
676676

677+
if (position == null) {
678+
position = -1;
679+
} else {
680+
validatePosition(position, 'position', length);
681+
}
682+
677683
if (length === 0)
678684
return { __proto__: null, bytesRead: length, buffer };
679685

@@ -684,12 +690,6 @@ async function read(handle, bufferOrParams, offset, length, position) {
684690

685691
validateOffsetLengthRead(offset, length, buffer.byteLength);
686692

687-
if (position == null) {
688-
position = -1;
689-
} else {
690-
validatePosition(position, 'position', length);
691-
}
692-
693693
const bytesRead = (await PromisePrototypeThen(
694694
binding.read(handle.fd, buffer, offset, length, position, kUsePromises),
695695
undefined,

test/parallel/test-fs-read-position-validation.mjs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,26 @@ async function testInvalid(code, position) {
9191
await testInvalid('ERR_INVALID_ARG_TYPE', badTypeValue);
9292
}
9393
}
94+
95+
{
96+
const emptyBuffer = Buffer.alloc(0);
97+
await new Promise((resolve, reject) => {
98+
fs.open(filepath, 'r', common.mustSucceed((fd) => {
99+
try {
100+
assert.throws(
101+
() => fs.read(fd, emptyBuffer, 0, 0, { not: 'a number' }, common.mustNotCall()),
102+
{ code: 'ERR_INVALID_ARG_TYPE' }
103+
);
104+
assert.throws(
105+
() => fs.read(fd, { buffer: emptyBuffer, offset: 0, length: 0, position: 'string' }, common.mustNotCall()),
106+
{ code: 'ERR_INVALID_ARG_TYPE' }
107+
);
108+
resolve();
109+
} catch (err) {
110+
reject(err);
111+
} finally {
112+
fs.close(fd, common.mustSucceed());
113+
}
114+
}));
115+
});
116+
}

test/parallel/test-fs-read-promises-position-validation.mjs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,30 @@ async function testInvalid(code, position) {
7979
for (const badTypeValue of [
8080
false, true, '1', Symbol(1), {}, [], () => {}, Promise.resolve(1),
8181
]) {
82-
testInvalid('ERR_INVALID_ARG_TYPE', badTypeValue);
82+
await testInvalid('ERR_INVALID_ARG_TYPE', badTypeValue);
83+
}
84+
}
85+
86+
{
87+
const emptyBuffer = Buffer.alloc(0);
88+
let fh;
89+
try {
90+
fh = await fs.promises.open(filepath, 'r');
91+
await assert.rejects(
92+
fh.read(emptyBuffer, 0, 0, { not: 'a number' }),
93+
{ code: 'ERR_INVALID_ARG_TYPE' }
94+
);
95+
} finally {
96+
await fh?.close();
97+
}
98+
99+
try {
100+
fh = await fs.promises.open(filepath, 'r');
101+
await assert.rejects(
102+
fh.read({ buffer: emptyBuffer, offset: 0, length: 0, position: 'string' }),
103+
{ code: 'ERR_INVALID_ARG_TYPE' }
104+
);
105+
} finally {
106+
await fh?.close();
83107
}
84108
}

test/parallel/test-fs-readSync-position-validation.mjs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,21 @@ function testInvalid(code, position) {
7777
testInvalid('ERR_INVALID_ARG_TYPE', badTypeValue);
7878
}
7979
}
80+
81+
{
82+
const emptyBuffer = Buffer.alloc(0);
83+
let fdSync;
84+
try {
85+
fdSync = fs.openSync(filepath, 'r');
86+
assert.throws(
87+
() => fs.readSync(fdSync, emptyBuffer, 0, 0, { not: 'a number' }),
88+
{ code: 'ERR_INVALID_ARG_TYPE' }
89+
);
90+
assert.throws(
91+
() => fs.readSync(fdSync, emptyBuffer, { offset: 0, length: 0, position: 'string' }),
92+
{ code: 'ERR_INVALID_ARG_TYPE' }
93+
);
94+
} finally {
95+
if (fdSync) fs.closeSync(fdSync);
96+
}
97+
}

0 commit comments

Comments
 (0)