diff --git a/index.js b/index.js index bdea6048..8ede5db9 100644 --- a/index.js +++ b/index.js @@ -1107,8 +1107,8 @@ function utf16leSlice (buf, start, end) { Buffer.prototype.slice = function slice (start, end) { const len = this.length - start = ~~start - end = end === undefined ? len : ~~end + start = Math.trunc(start) + end = end === undefined ? len : Math.trunc(end) if (start < 0) { start += len diff --git a/test/slice.js b/test/slice.js index 035c9aae..4e357163 100644 --- a/test/slice.js +++ b/test/slice.js @@ -1,6 +1,65 @@ const B = require('../').Buffer const test = require('tape') +test('slice clamps offsets outside the signed 32-bit range', function (t) { + const buf = B.from('abcdef') + const offsets = [0x80000000, 0x100000000, 0x100000001, Number.MAX_SAFE_INTEGER, Infinity] + + offsets.forEach(function (offset) { + t.equal(buf.slice(offset).toString(), '', 'start ' + offset) + t.equal(buf.slice(1, offset).toString(), 'bcdef', 'end ' + offset) + t.equal(buf.slice(-offset).toString(), 'abcdef', 'start ' + -offset) + t.equal(buf.slice(0, -offset).toString(), '', 'end ' + -offset) + }) + + t.end() +}) + +test('slice preserves offset coercion and truncates toward zero', function (t) { + const buf = B.from('abcdef') + const cases = [ + [undefined, 'abcdef', 'abcdef'], + [null, 'abcdef', ''], + [false, 'abcdef', ''], + [true, 'bcdef', 'a'], + ['2.9', 'cdef', 'ab'], + ['-2.9', 'ef', 'abcd'], + ['not a number', 'abcdef', ''], + [NaN, 'abcdef', ''], + [0.9, 'abcdef', ''], + [-0.9, 'abcdef', ''], + [3.9, 'def', 'abc'], + [-3.9, 'def', 'abc'], + ['4294967296', '', 'abcdef'], + ['-4294967296', 'abcdef', ''], + [{ valueOf: function () { return 0x100000000 } }, '', 'abcdef'] + ] + + cases.forEach(function (entry) { + const offset = entry[0] + t.equal(buf.slice(offset).toString(), entry[1], 'start ' + String(offset)) + t.equal(buf.slice(0, offset).toString(), entry[2], 'end ' + String(offset)) + }) + + t.end() +}) + +test('slice with a large end preserves the buffer type and shared memory', function (t) { + const buf = B.from('abcdef') + const sliced = buf.slice(1, 0x100000000).slice(1, Infinity) + + t.ok(B.isBuffer(sliced)) + t.equal(sliced.toString(), 'cdef') + t.equal(sliced.buffer, buf.buffer) + t.equal(sliced.byteOffset, buf.byteOffset + 2) + sliced[0] = '!'.charCodeAt(0) + t.equal(buf.toString(), 'ab!def') + buf[3] = '?'.charCodeAt(0) + t.equal(sliced.toString(), '!?ef') + + t.end() +}) + test('modifying buffer created by .slice() modifies original memory', function (t) { const buf1 = new B(26) for (let i = 0; i < 26; i++) {