Skip to content

Commit b05ef97

Browse files
addaleaxMylesBorins
authored andcommitted
buffer: zero-fill buffer allocated with invalid content
Zero-fill when `Buffer.alloc()` receives invalid fill data. A solution like #17427 which switches to throwing makes sense, but is likely a breaking change. This suggestion leaves the behaviour of `buffer.fill()` untouched, since any change to it would be a breaking change, and lets `Buffer.alloc()` check whether any filling took place or not. PR-URL: #17428 Backport-PR-URL: #17467 Refs: #17427 Refs: #17423 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Anatoli Papirovski <apapirovski@mac.com> Reviewed-By: Ali Ijaz Sheikh <ofrobots@google.com> Reviewed-By: Tobias Nießen <tniessen@tnie.de> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Michaël Zasso <targos@protonmail.com>
1 parent db09f24 commit b05ef97

File tree

5 files changed

+44
-13
lines changed

5 files changed

+44
-13
lines changed

doc/api/buffer.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,11 @@ console.log(buf2.toString());
510510
### Class Method: Buffer.alloc(size[, fill[, encoding]])
511511
<!-- YAML
512512
added: v5.10.0
513+
changes:
514+
- version: REPLACEME
515+
pr-url: https://github.com/nodejs/node/pull/17428
516+
description: Specifying an invalid string for `fill` now results in a
517+
zero-filled buffer.
513518
-->
514519

515520
* `size` {integer} The desired length of the new `Buffer`.
@@ -1253,7 +1258,7 @@ Example: Fill a `Buffer` with a two-byte character
12531258
console.log(Buffer.allocUnsafe(3).fill('\u0222'));
12541259
```
12551260

1256-
If `value` is contains invalid characters, it is truncated; if no valid
1261+
If `value` contains invalid characters, it is truncated; if no valid
12571262
fill data remains, no filling is performed:
12581263

12591264
```js

lib/buffer.js

+15-10
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,9 @@ Buffer.alloc = function(size, fill, encoding) {
238238
// be interpreted as a start offset.
239239
if (typeof encoding !== 'string')
240240
encoding = undefined;
241-
return createUnsafeBuffer(size).fill(fill, encoding);
241+
const ret = createUnsafeBuffer(size);
242+
if (fill_(ret, fill, encoding) > 0)
243+
return ret;
242244
}
243245
return new FastBuffer(size);
244246
};
@@ -796,15 +798,20 @@ Buffer.prototype.includes = function includes(val, byteOffset, encoding) {
796798
// buffer.fill(buffer[, offset[, end]])
797799
// buffer.fill(string[, offset[, end]][, encoding])
798800
Buffer.prototype.fill = function fill(val, start, end, encoding) {
801+
fill_(this, val, start, end, encoding);
802+
return this;
803+
};
804+
805+
function fill_(buf, val, start, end, encoding) {
799806
// Handle string cases:
800807
if (typeof val === 'string') {
801808
if (typeof start === 'string') {
802809
encoding = start;
803810
start = 0;
804-
end = this.length;
811+
end = buf.length;
805812
} else if (typeof end === 'string') {
806813
encoding = end;
807-
end = this.length;
814+
end = buf.length;
808815
}
809816

810817
if (encoding !== undefined && typeof encoding !== 'string') {
@@ -832,19 +839,17 @@ Buffer.prototype.fill = function fill(val, start, end, encoding) {
832839
}
833840

834841
// Invalid ranges are not set to a default, so can range check early.
835-
if (start < 0 || end > this.length)
842+
if (start < 0 || end > buf.length)
836843
throw new RangeError('Out of range index');
837844

838845
if (end <= start)
839-
return this;
846+
return 0;
840847

841848
start = start >>> 0;
842-
end = end === undefined ? this.length : end >>> 0;
849+
end = end === undefined ? buf.length : end >>> 0;
843850

844-
binding.fill(this, val, start, end, encoding);
845-
846-
return this;
847-
};
851+
return binding.fill(buf, val, start, end, encoding);
852+
}
848853

849854

850855
Buffer.prototype.write = function(string, offset, length, encoding) {

src/node_buffer.cc

+6-2
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,8 @@ void Fill(const FunctionCallbackInfo<Value>& args) {
591591
THROW_AND_RETURN_IF_OOB(start <= end);
592592
THROW_AND_RETURN_IF_OOB(fill_length + start <= ts_obj_length);
593593

594+
args.GetReturnValue().Set(static_cast<double>(fill_length));
595+
594596
// First check if Buffer has been passed.
595597
if (Buffer::HasInstance(args[1])) {
596598
SPREAD_BUFFER_ARG(args[1], fill_obj);
@@ -612,8 +614,10 @@ void Fill(const FunctionCallbackInfo<Value>& args) {
612614
enc == UTF8 ? str_obj->Utf8Length() :
613615
enc == UCS2 ? str_obj->Length() * sizeof(uint16_t) : str_obj->Length();
614616

615-
if (str_length == 0)
617+
if (str_length == 0) {
618+
args.GetReturnValue().Set(0);
616619
return;
620+
}
617621

618622
// Can't use StringBytes::Write() in all cases. For example if attempting
619623
// to write a two byte character into a one byte Buffer.
@@ -643,7 +647,7 @@ void Fill(const FunctionCallbackInfo<Value>& args) {
643647
// TODO(trevnorris): Should this throw? Because of the string length was
644648
// greater than 0 but couldn't be written then the string was invalid.
645649
if (str_length == 0)
646-
return;
650+
return args.GetReturnValue().Set(0);
647651
}
648652

649653
start_fill:

test/parallel/test-buffer-alloc.js

+11
Original file line numberDiff line numberDiff line change
@@ -993,3 +993,14 @@ assert.strictEqual(Buffer.prototype.toLocaleString, Buffer.prototype.toString);
993993
const buf = Buffer.from('test');
994994
assert.strictEqual(buf.toLocaleString(), buf.toString());
995995
}
996+
997+
{
998+
// Ref: https://github.com/nodejs/node/issues/17423
999+
const buf = Buffer.alloc(0x1000, 'This is not correctly encoded', 'hex');
1000+
assert(buf.every((byte) => byte === 0), `Buffer was not zeroed out: ${buf}`);
1001+
}
1002+
1003+
{
1004+
const buf = Buffer.alloc(0x1000, 'c', 'hex');
1005+
assert(buf.every((byte) => byte === 0), `Buffer was not zeroed out: ${buf}`);
1006+
}

test/parallel/test-buffer-fill.js

+6
Original file line numberDiff line numberDiff line change
@@ -439,3 +439,9 @@ assert.strictEqual(
439439
assert.strictEqual(
440440
Buffer.allocUnsafeSlow(16).fill('Љ', 'utf8').toString('utf8'),
441441
'Љ'.repeat(8));
442+
443+
{
444+
const buf = Buffer.from('a'.repeat(1000));
445+
buf.fill('This is not correctly encoded', 'hex');
446+
assert.strictEqual(buf.toString(), 'a'.repeat(1000));
447+
}

0 commit comments

Comments
 (0)