Skip to content

Commit cd174df

Browse files
committed
buffer: throw on failed fill attempts
If fill() attempts to write a string to a buffer, but fails silently, then uninitialized memory could be leaked. This commit causes fill() to throw if the string write operation fails. Refs: #17423 PR-URL: #17427 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
1 parent 817d4ad commit cd174df

File tree

5 files changed

+52
-30
lines changed

5 files changed

+52
-30
lines changed

doc/api/buffer.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,10 @@ changes:
515515
pr-url: https://github.com/nodejs/node/pull/17428
516516
description: Specifying an invalid string for `fill` now results in a
517517
zero-filled buffer.
518+
- version: REPLACEME
519+
pr-url: https://github.com/nodejs/node/pull/17427
520+
description: Specifying an invalid string for `fill` triggers a thrown
521+
exception.
518522
-->
519523

520524
* `size` {integer} The desired length of the new `Buffer`.
@@ -1225,6 +1229,10 @@ changes:
12251229
- version: v5.7.0
12261230
pr-url: https://github.com/nodejs/node/pull/4935
12271231
description: The `encoding` parameter is supported now.
1232+
- version: REPLACEME
1233+
pr-url: https://github.com/nodejs/node/pull/17427
1234+
description: Specifying an invalid string for `value` triggers a thrown
1235+
exception.
12281236
-->
12291237

12301238
* `value` {string|Buffer|integer} The value to fill `buf` with.
@@ -1260,15 +1268,15 @@ console.log(Buffer.allocUnsafe(3).fill('\u0222'));
12601268
```
12611269

12621270
If `value` contains invalid characters, it is truncated; if no valid
1263-
fill data remains, no filling is performed:
1271+
fill data remains, an exception is thrown:
12641272

12651273
```js
12661274
const buf = Buffer.allocUnsafe(5);
12671275
// Prints: <Buffer 61 61 61 61 61>
12681276
console.log(buf.fill('a'));
12691277
// Prints: <Buffer aa aa aa aa aa>
12701278
console.log(buf.fill('aazz', 'hex'));
1271-
// Prints: <Buffer aa aa aa aa aa>
1279+
// Throws a exception.
12721280
console.log(buf.fill('zz', 'hex'));
12731281
```
12741282

lib/buffer.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -892,8 +892,12 @@ function fill_(buf, val, start, end, encoding) {
892892

893893
start = start >>> 0;
894894
end = end === undefined ? buf.length : end >>> 0;
895+
const fillLength = bindingFill(buf, val, start, end, encoding);
895896

896-
return bindingFill(buf, val, start, end, encoding);
897+
if (fillLength === -1)
898+
throw new errors.TypeError('ERR_INVALID_ARG_VALUE', 'value', val);
899+
900+
return fillLength;
897901
}
898902

899903

src/node_buffer.cc

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -643,11 +643,12 @@ void Fill(const FunctionCallbackInfo<Value>& args) {
643643
enc,
644644
nullptr);
645645
// This check is also needed in case Write() returns that no bytes could
646-
// be written.
647-
// TODO(trevnorris): Should this throw? Because of the string length was
648-
// greater than 0 but couldn't be written then the string was invalid.
646+
// be written. If no bytes could be written, then return -1 because the
647+
// string is invalid. This will trigger a throw in JavaScript. Silently
648+
// failing should be avoided because it can lead to buffers with unexpected
649+
// contents.
649650
if (str_length == 0)
650-
return args.GetReturnValue().Set(0);
651+
return args.GetReturnValue().Set(-1);
651652
}
652653

653654
start_fill:

test/parallel/test-buffer-alloc.js

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,13 +1006,16 @@ assert.strictEqual(Buffer.prototype.toLocaleString, Buffer.prototype.toString);
10061006
assert.strictEqual(buf.toLocaleString(), buf.toString());
10071007
}
10081008

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-
}
1009+
common.expectsError(() => {
1010+
Buffer.alloc(0x1000, 'This is not correctly encoded', 'hex');
1011+
}, {
1012+
code: 'ERR_INVALID_ARG_VALUE',
1013+
type: TypeError
1014+
});
10141015

1015-
{
1016-
const buf = Buffer.alloc(0x1000, 'c', 'hex');
1017-
assert(buf.every((byte) => byte === 0), `Buffer was not zeroed out: ${buf}`);
1018-
}
1016+
common.expectsError(() => {
1017+
Buffer.alloc(0x1000, 'c', 'hex');
1018+
}, {
1019+
code: 'ERR_INVALID_ARG_VALUE',
1020+
type: TypeError
1021+
});

test/parallel/test-buffer-fill.js

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -134,20 +134,23 @@ testBufs('61c8b462c8b563c8b6', 4, -1, 'hex');
134134
testBufs('61c8b462c8b563c8b6', 4, 1, 'hex');
135135
testBufs('61c8b462c8b563c8b6', 12, 1, 'hex');
136136

137-
{
137+
common.expectsError(() => {
138138
const buf = Buffer.allocUnsafe(SIZE);
139-
assert.doesNotThrow(() => {
140-
// Make sure this operation doesn't go on forever.
141-
buf.fill('yKJh', 'hex');
142-
});
143-
}
144139

145-
{
140+
buf.fill('yKJh', 'hex');
141+
}, {
142+
code: 'ERR_INVALID_ARG_VALUE',
143+
type: TypeError
144+
});
145+
146+
common.expectsError(() => {
146147
const buf = Buffer.allocUnsafe(SIZE);
147-
assert.doesNotThrow(() => {
148-
buf.fill('\u0222', 'hex');
149-
});
150-
}
148+
149+
buf.fill('\u0222', 'hex');
150+
}, {
151+
code: 'ERR_INVALID_ARG_VALUE',
152+
type: TypeError
153+
});
151154

152155
// BASE64
153156
testBufs('YWJj', 'ucs2');
@@ -469,8 +472,11 @@ assert.strictEqual(
469472
Buffer.allocUnsafeSlow(16).fill('Љ', 'utf8').toString('utf8'),
470473
'Љ'.repeat(8));
471474

472-
{
475+
common.expectsError(() => {
473476
const buf = Buffer.from('a'.repeat(1000));
477+
474478
buf.fill('This is not correctly encoded', 'hex');
475-
assert.strictEqual(buf.toString(), 'a'.repeat(1000));
476-
}
479+
}, {
480+
code: 'ERR_INVALID_ARG_VALUE',
481+
type: TypeError
482+
});

0 commit comments

Comments
 (0)