Skip to content

Commit 5e3b4d6

Browse files
zbjornsonTrott
authored andcommitted
fs: allow int64 offset in fs.write/writeSync/fd.write
Ref #26563 PR-URL: #26572 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Ujjwal Sharma <usharma1998@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com>
1 parent a3c0014 commit 5e3b4d6

File tree

6 files changed

+45
-27
lines changed

6 files changed

+45
-27
lines changed

lib/fs.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -541,8 +541,11 @@ function write(fd, buffer, offset, length, position, callback) {
541541

542542
if (isArrayBufferView(buffer)) {
543543
callback = maybeCallback(callback || position || length || offset);
544-
if (typeof offset !== 'number')
544+
if (offset == null || typeof offset === 'function') {
545545
offset = 0;
546+
} else {
547+
validateSafeInteger(offset, 'offset');
548+
}
546549
if (typeof length !== 'number')
547550
length = buffer.length - offset;
548551
if (typeof position !== 'number')
@@ -580,8 +583,11 @@ function writeSync(fd, buffer, offset, length, position) {
580583
if (isArrayBufferView(buffer)) {
581584
if (position === undefined)
582585
position = null;
583-
if (typeof offset !== 'number')
586+
if (offset == null) {
584587
offset = 0;
588+
} else {
589+
validateSafeInteger(offset, 'offset');
590+
}
585591
if (typeof length !== 'number')
586592
length = buffer.byteLength - offset;
587593
validateOffsetLengthWrite(offset, length, buffer.byteLength);

lib/internal/fs/promises.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -240,8 +240,11 @@ async function write(handle, buffer, offset, length, position) {
240240
return { bytesWritten: 0, buffer };
241241

242242
if (isUint8Array(buffer)) {
243-
if (typeof offset !== 'number')
243+
if (offset == null) {
244244
offset = 0;
245+
} else {
246+
validateSafeInteger(offset, 'offset');
247+
}
245248
if (typeof length !== 'number')
246249
length = buffer.length - offset;
247250
if (typeof position !== 'number')

lib/internal/fs/utils.js

+3-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
const { Object, Reflect } = primordials;
44

5-
const { Buffer, kMaxLength } = require('buffer');
5+
const { Buffer } = require('buffer');
66
const {
77
codes: {
88
ERR_FS_INVALID_SYMLINK_TYPE,
@@ -476,9 +476,8 @@ const validateOffsetLengthWrite = hideStackFrames(
476476
throw new ERR_OUT_OF_RANGE('offset', `<= ${byteLength}`, offset);
477477
}
478478

479-
const max = byteLength > kMaxLength ? kMaxLength : byteLength;
480-
if (length > max - offset) {
481-
throw new ERR_OUT_OF_RANGE('length', `<= ${max - offset}`, length);
479+
if (length > byteLength - offset) {
480+
throw new ERR_OUT_OF_RANGE('length', `<= ${byteLength - offset}`, length);
482481
}
483482
}
484483
);

src/node_file.cc

+6-4
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ constexpr char kPathSeparator = '/';
8888
const char* const kPathSeparator = "\\/";
8989
#endif
9090

91-
#define GET_OFFSET(a) ((a)->IsNumber() ? (a).As<Integer>()->Value() : -1)
91+
#define GET_OFFSET(a) (IsSafeJsInt(a) ? (a).As<Integer>()->Value() : -1)
9292
#define TRACE_NAME(name) "fs.sync." #name
9393
#define GET_TRACE_ENABLED \
9494
(*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED \
@@ -1669,9 +1669,11 @@ static void WriteBuffer(const FunctionCallbackInfo<Value>& args) {
16691669
char* buffer_data = Buffer::Data(buffer_obj);
16701670
size_t buffer_length = Buffer::Length(buffer_obj);
16711671

1672-
CHECK(args[2]->IsInt32());
1673-
const size_t off = static_cast<size_t>(args[2].As<Int32>()->Value());
1674-
CHECK_LE(off, buffer_length);
1672+
CHECK(IsSafeJsInt(args[2]));
1673+
const int64_t off_64 = args[2].As<Integer>()->Value();
1674+
CHECK_GE(off_64, 0);
1675+
CHECK_LE(static_cast<uint64_t>(off_64), buffer_length);
1676+
const size_t off = static_cast<size_t>(off_64);
16751677

16761678
CHECK(args[3]->IsInt32());
16771679
const size_t len = static_cast<size_t>(args[3].As<Int32>()->Value());

test/parallel/test-fs-util-validateoffsetlengthwrite.js

-16
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,6 @@ const { kMaxLength } = require('buffer');
2222
);
2323
}
2424

25-
// RangeError when byteLength > kMaxLength, and length > kMaxLength - offset .
26-
{
27-
const offset = kMaxLength;
28-
const length = 100;
29-
const byteLength = kMaxLength + 1;
30-
common.expectsError(
31-
() => validateOffsetLengthWrite(offset, length, byteLength),
32-
{
33-
code: 'ERR_OUT_OF_RANGE',
34-
type: RangeError,
35-
message: 'The value of "length" is out of range. ' +
36-
`It must be <= ${kMaxLength - offset}. Received ${length}`
37-
}
38-
);
39-
}
40-
4125
// RangeError when byteLength < kMaxLength, and length > byteLength - offset .
4226
{
4327
const offset = kMaxLength - 150;

test/parallel/test-fs-write-buffer.js

+24
Original file line numberDiff line numberDiff line change
@@ -148,3 +148,27 @@ tmpdir.refresh();
148148
fs.write(fd, Uint8Array.from(expected), cb);
149149
}));
150150
}
151+
152+
// fs.write with invalid offset type
153+
{
154+
const filename = path.join(tmpdir.path, 'write7.txt');
155+
fs.open(filename, 'w', 0o644, common.mustCall((err, fd) => {
156+
assert.ifError(err);
157+
158+
assert.throws(() => {
159+
fs.write(fd,
160+
Buffer.from('abcd'),
161+
NaN,
162+
expected.length,
163+
0,
164+
common.mustNotCall());
165+
}, {
166+
code: 'ERR_OUT_OF_RANGE',
167+
name: 'RangeError',
168+
message: 'The value of "offset" is out of range. ' +
169+
'It must be an integer. Received NaN'
170+
});
171+
172+
fs.closeSync(fd);
173+
}));
174+
}

0 commit comments

Comments
 (0)