Skip to content

Commit 15bf640

Browse files
addaleaxevanlucas
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 Refs: #17427 Refs: #17423 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Anatoli Papirovski <[email protected]> Reviewed-By: Ali Ijaz Sheikh <[email protected]> Reviewed-By: Tobias Nießen <[email protected]> Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: Michaël Zasso <[email protected]>
1 parent 99fc75e commit 15bf640

File tree

5 files changed

+45
-14
lines changed

5 files changed

+45
-14
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

+16-11
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ const {
2727
compare: _compare,
2828
compareOffset,
2929
createFromString,
30-
fill: _fill,
30+
fill: bindingFill,
3131
indexOfBuffer,
3232
indexOfNumber,
3333
indexOfString,
@@ -266,7 +266,9 @@ Buffer.alloc = function alloc(size, fill, encoding) {
266266
// be interpreted as a start offset.
267267
if (typeof encoding !== 'string')
268268
encoding = undefined;
269-
return createUnsafeBuffer(size).fill(fill, encoding);
269+
const ret = createUnsafeBuffer(size);
270+
if (fill_(ret, fill, encoding) > 0)
271+
return ret;
270272
}
271273
return new FastBuffer(size);
272274
};
@@ -840,15 +842,20 @@ Buffer.prototype.includes = function includes(val, byteOffset, encoding) {
840842
// buffer.fill(buffer[, offset[, end]])
841843
// buffer.fill(string[, offset[, end]][, encoding])
842844
Buffer.prototype.fill = function fill(val, start, end, encoding) {
845+
fill_(this, val, start, end, encoding);
846+
return this;
847+
};
848+
849+
function fill_(buf, val, start, end, encoding) {
843850
// Handle string cases:
844851
if (typeof val === 'string') {
845852
if (typeof start === 'string') {
846853
encoding = start;
847854
start = 0;
848-
end = this.length;
855+
end = buf.length;
849856
} else if (typeof end === 'string') {
850857
encoding = end;
851-
end = this.length;
858+
end = buf.length;
852859
}
853860

854861
if (encoding !== undefined && typeof encoding !== 'string') {
@@ -877,19 +884,17 @@ Buffer.prototype.fill = function fill(val, start, end, encoding) {
877884
}
878885

879886
// Invalid ranges are not set to a default, so can range check early.
880-
if (start < 0 || end > this.length)
887+
if (start < 0 || end > buf.length)
881888
throw new errors.RangeError('ERR_INDEX_OUT_OF_RANGE');
882889

883890
if (end <= start)
884-
return this;
891+
return 0;
885892

886893
start = start >>> 0;
887-
end = end === undefined ? this.length : end >>> 0;
894+
end = end === undefined ? buf.length : end >>> 0;
888895

889-
_fill(this, val, start, end, encoding);
890-
891-
return this;
892-
};
896+
return bindingFill(buf, val, start, end, encoding);
897+
}
893898

894899

895900
Buffer.prototype.write = function write(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
@@ -1005,3 +1005,14 @@ assert.strictEqual(Buffer.prototype.toLocaleString, Buffer.prototype.toString);
10051005
const buf = Buffer.from('test');
10061006
assert.strictEqual(buf.toLocaleString(), buf.toString());
10071007
}
1008+
1009+
{
1010+
// Ref: https://github.com/nodejs/node/issues/17423
1011+
const buf = Buffer.alloc(0x1000, 'This is not correctly encoded', 'hex');
1012+
assert(buf.every((byte) => byte === 0), `Buffer was not zeroed out: ${buf}`);
1013+
}
1014+
1015+
{
1016+
const buf = Buffer.alloc(0x1000, 'c', 'hex');
1017+
assert(buf.every((byte) => byte === 0), `Buffer was not zeroed out: ${buf}`);
1018+
}

test/parallel/test-buffer-fill.js

+6
Original file line numberDiff line numberDiff line change
@@ -468,3 +468,9 @@ assert.strictEqual(
468468
assert.strictEqual(
469469
Buffer.allocUnsafeSlow(16).fill('Љ', 'utf8').toString('utf8'),
470470
'Љ'.repeat(8));
471+
472+
{
473+
const buf = Buffer.from('a'.repeat(1000));
474+
buf.fill('This is not correctly encoded', 'hex');
475+
assert.strictEqual(buf.toString(), 'a'.repeat(1000));
476+
}

0 commit comments

Comments
 (0)