Skip to content

Commit

Permalink
buffer: fix range checking for slowToString
Browse files Browse the repository at this point in the history
If `start` is not a valid number in the range, then the default value
zero will be used. Same way, if `end` is not a valid number in the
accepted range, then, by default, the length of the buffer is assumed.

Ref: #2668

PR-URL: #2919
  • Loading branch information
thefourtheye committed Sep 22, 2015
1 parent f32a606 commit ac60740
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 12 deletions.
28 changes: 23 additions & 5 deletions lib/buffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -322,13 +322,31 @@ Object.defineProperty(Buffer.prototype, 'offset', {
function slowToString(encoding, start, end) {
var loweredCase = false;

start = start >>> 0;
end = end === undefined || end === Infinity ? this.length : end >>> 0;
if (start >= this.length || end <= 0)
return '';

/*
* if unsigned 32 bit value (>>> 0) of `start` is not the same as `start`,
* use `0` as the default value. Similarly, if the unsigned 32 bit value of
* `end` is not the same as `end`, then use the length of the buffer as the
* end value.
*
* Note that, the comparison is done with abstract equality operator (!=) to
* allow stringified numbers ('1') and Number objects (new Number(5)).
*/
if (start < 0 || start >>> 0 != parseInt(+start))
start = 0;

if (end > this.length || end >>> 0 != parseInt(+end))
end = this.length;

start >>>= 0;
end >>>= 0;

if (end <= start)
return '';

if (!encoding) encoding = 'utf8';
if (start < 0) start = 0;
if (end > this.length) end = this.length;
if (end <= start) return '';

while (true) {
switch (encoding) {
Expand Down
2 changes: 1 addition & 1 deletion src/node_internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ inline MUST_USE_RESULT bool ParseArrayIndex(v8::Local<v8::Value> arg,
return true;
}

int32_t tmp_i = arg->Int32Value();
int32_t tmp_i = arg->Uint32Value();

if (tmp_i < 0)
return false;
Expand Down
81 changes: 75 additions & 6 deletions test/parallel/test-buffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -248,14 +248,83 @@ b.copy(new Buffer(1), 1, 1, 1);
// try to copy 0 bytes from past the end of the source buffer
b.copy(new Buffer(1), 0, 2048, 2048);

// try to toString() a 0-length slice of a buffer, both within and without the
// valid buffer range
assert.equal(new Buffer('abc').toString('ascii', 0, 0), '');
assert.equal(new Buffer('abc').toString('ascii', -100, -100), '');
assert.equal(new Buffer('abc').toString('ascii', 100, 100), '');
const rangeBuffer = new Buffer('abc');

// if start >= buffer's length, empty string will be returned
assert.equal(rangeBuffer.toString('ascii', 3), '');
assert.equal(rangeBuffer.toString('ascii', +Infinity), '');
assert.equal(rangeBuffer.toString('ascii', 3.14, 3), '');
assert.equal(rangeBuffer.toString('ascii', 'Infinity', 3), '');

// if end <= 0, empty string will be returned
assert.equal(rangeBuffer.toString('ascii', 1, 0), '');
assert.equal(rangeBuffer.toString('ascii', 1, -1.2), '');
assert.equal(rangeBuffer.toString('ascii', 1, -100), '');
assert.equal(rangeBuffer.toString('ascii', 1, -Infinity), '');

// if start < 0, start will be taken as zero
assert.equal(rangeBuffer.toString('ascii', -1, 3), 'abc');
assert.equal(rangeBuffer.toString('ascii', -1.99, 3), 'abc');
assert.equal(rangeBuffer.toString('ascii', -Infinity, 3), 'abc');
assert.equal(rangeBuffer.toString('ascii', '-1', 3), 'abc');
assert.equal(rangeBuffer.toString('ascii', '-1.99', 3), 'abc');
assert.equal(rangeBuffer.toString('ascii', '-Infinity', 3), 'abc');

// if start is an invalid integer, start will be taken as zero
assert.equal(rangeBuffer.toString('ascii', 'node.js', 3), 'abc');
assert.equal(rangeBuffer.toString('ascii', {}, 3), 'abc');
assert.equal(rangeBuffer.toString('ascii', [], 3), 'abc');
assert.equal(rangeBuffer.toString('ascii', NaN, 3), 'abc');
assert.equal(rangeBuffer.toString('ascii', null, 3), 'abc');
assert.equal(rangeBuffer.toString('ascii', undefined, 3), 'abc');
assert.equal(rangeBuffer.toString('ascii', false, 3), 'abc');
assert.equal(rangeBuffer.toString('ascii', '', 3), 'abc');

// but, if start is an integer when coerced, then it will be coerced and used.
assert.equal(rangeBuffer.toString('ascii', '-1', 3), 'abc');
assert.equal(rangeBuffer.toString('ascii', '1', 3), 'bc');
assert.equal(rangeBuffer.toString('ascii', '-Infinity', 3), 'abc');
assert.equal(rangeBuffer.toString('ascii', '3', 3), '');
assert.equal(rangeBuffer.toString('ascii', Number(3), 3), '');
assert.equal(rangeBuffer.toString('ascii', '3.14', 3), '');
assert.equal(rangeBuffer.toString('ascii', '1.99', 3), 'bc');
assert.equal(rangeBuffer.toString('ascii', '-1.99', 3), 'abc');
assert.equal(rangeBuffer.toString('ascii', 1.99, 3), 'bc');
assert.equal(rangeBuffer.toString('ascii', true, 3), 'bc');

// if end > buffer's length, end will be taken as buffer's length
assert.equal(rangeBuffer.toString('ascii', 0, 5), 'abc');
assert.equal(rangeBuffer.toString('ascii', 0, 6.99), 'abc');
assert.equal(rangeBuffer.toString('ascii', 0, Infinity), 'abc');
assert.equal(rangeBuffer.toString('ascii', 0, '5'), 'abc');
assert.equal(rangeBuffer.toString('ascii', 0, '6.99'), 'abc');
assert.equal(rangeBuffer.toString('ascii', 0, 'Infinity'), 'abc');

// if end is an invalid integer, end will be taken as buffer's length
assert.equal(rangeBuffer.toString('ascii', 0, 'node.js'), 'abc');
assert.equal(rangeBuffer.toString('ascii', 0, {}), 'abc');
assert.equal(rangeBuffer.toString('ascii', 0, NaN), 'abc');
assert.equal(rangeBuffer.toString('ascii', 0, undefined), 'abc');
assert.equal(rangeBuffer.toString('ascii', 0), 'abc');
assert.equal(rangeBuffer.toString('ascii', 0, null), '');
assert.equal(rangeBuffer.toString('ascii', 0, []), '');
assert.equal(rangeBuffer.toString('ascii', 0, false), '');
assert.equal(rangeBuffer.toString('ascii', 0, ''), '');

// but, if end is an integer when coerced, then it will be coerced and used.
assert.equal(rangeBuffer.toString('ascii', 0, '-1'), '');
assert.equal(rangeBuffer.toString('ascii', 0, '1'), 'a');
assert.equal(rangeBuffer.toString('ascii', 0, '-Infinity'), '');
assert.equal(rangeBuffer.toString('ascii', 0, '3'), 'abc');
assert.equal(rangeBuffer.toString('ascii', 0, Number(3)), 'abc');
assert.equal(rangeBuffer.toString('ascii', 0, '3.14'), 'abc');
assert.equal(rangeBuffer.toString('ascii', 0, '1.99'), 'a');
assert.equal(rangeBuffer.toString('ascii', 0, '-1.99'), '');
assert.equal(rangeBuffer.toString('ascii', 0, 1.99), 'a');
assert.equal(rangeBuffer.toString('ascii', 0, true), 'a');

// try toString() with a object as a encoding
assert.equal(new Buffer('abc').toString({toString: function() {
assert.equal(rangeBuffer.toString({toString: function() {
return 'ascii';
}}), 'abc');

Expand Down

0 comments on commit ac60740

Please sign in to comment.