diff --git a/lib/internal/fs/promises.js b/lib/internal/fs/promises.js index 5a61f58aae27..79d2e63cdc8b 100644 --- a/lib/internal/fs/promises.js +++ b/lib/internal/fs/promises.js @@ -1420,6 +1420,7 @@ async function read(handle, bufferOrParams, offset, length, position) { } length ??= buffer.byteLength - offset; + length |= 0; if (position == null) { position = -1; diff --git a/test/parallel/test-fs-promises-file-handle-read.js b/test/parallel/test-fs-promises-file-handle-read.js index 423f1778bf63..2974c9d4d575 100644 --- a/test/parallel/test-fs-promises-file-handle-read.js +++ b/test/parallel/test-fs-promises-file-handle-read.js @@ -112,6 +112,27 @@ async function validateReadLength(len) { } } +async function validateReadLengthCoercedFromString() { + // Align with fs.read / fs.readSync (`length |= 0`). A non-number length + // must not reach node::fs::Read (CHECK args[3]->IsInt32()). + const buf = Buffer.alloc(4); + const filePath = fixtures.path('x.txt'); + const fileHandle = await open(filePath, 'r'); + try { + const { bytesRead } = await fileHandle.read(buf, 0, '1', 0); + assert.strictEqual(bytesRead, 1); + const { bytesRead: bytesReadOptions } = await fileHandle.read({ + buffer: buf, + offset: 0, + length: '1', + position: 0, + }); + assert.strictEqual(bytesReadOptions, 1); + } finally { + await fileHandle.close(); + } +} + async function validateReadWithNoOptions(byte) { const buf = Buffer.alloc(byte); const filePath = fixtures.path('x.txt'); @@ -144,6 +165,7 @@ async function validateReadWithNoOptions(byte) { await validateReadWithPositionZero(); await validateReadLength(0); await validateReadLength(1); + await validateReadLengthCoercedFromString(); await validateReadWithNoOptions(0); await validateReadWithNoOptions(1); })().then(common.mustCall());