diff options
author | 2023-01-23 21:48:52 -0300 | |
---|---|---|
committer | 2023-01-23 16:48:52 -0800 | |
commit | b3533fb3a88b33da50e58ad9594a0559af575035 (patch) | |
tree | 05c1a22ab6b967ce8ced970e4dcd783e056e50cc /test/bun.js/buffer.test.js | |
parent | 79c0b614ee04d06d9565cd52450b0de1f58fa87e (diff) | |
download | bun-b3533fb3a88b33da50e58ad9594a0559af575035.tar.gz bun-b3533fb3a88b33da50e58ad9594a0559af575035.tar.zst bun-b3533fb3a88b33da50e58ad9594a0559af575035.zip |
fix(Buffer) Fix arguments in buffer.write, fix size returned from buffer.write for utf16, fix size calc for base64, fix calc for hex byte size (#1881)
* fix buffer write when more than 2 args are passed
* fix encoding parameter
* better buffer write tests
* fix ucs2/utf8 len return
* fix base64 size in Buffer write
* fix hex encoding size
* actual fix base64
* actual fix base64
* fix segfault
* add fill parameter in Buffer.alloc
* use createUnitialized when alloc have fill parameter, use RETURN_IF_EXCEPTION when static casting
* fix utf16le, ucs2 copying in Buffer write
Diffstat (limited to 'test/bun.js/buffer.test.js')
-rw-r--r-- | test/bun.js/buffer.test.js | 104 |
1 files changed, 84 insertions, 20 deletions
diff --git a/test/bun.js/buffer.test.js b/test/bun.js/buffer.test.js index 193124b00..72cd8e10d 100644 --- a/test/bun.js/buffer.test.js +++ b/test/bun.js/buffer.test.js @@ -429,34 +429,98 @@ it("read", () => { }); it("write", () => { - let buf = Buffer.alloc(16); + + const resultMap = new Map([ + ['utf8', Buffer.from([102, 111, 111, 0, 0, 0, 0, 0, 0])], + ['ucs2', Buffer.from([102, 0, 111, 0, 111, 0, 0, 0, 0])], + ['ascii', Buffer.from([102, 111, 111, 0, 0, 0, 0, 0, 0])], + ['latin1', Buffer.from([102, 111, 111, 0, 0, 0, 0, 0, 0])], + ['binary', Buffer.from([102, 111, 111, 0, 0, 0, 0, 0, 0])], + ['utf16le', Buffer.from([102, 0, 111, 0, 111, 0, 0, 0, 0])], + ['base64', Buffer.from([102, 111, 111, 0, 0, 0, 0, 0, 0])], + ['base64url', Buffer.from([102, 111, 111, 0, 0, 0, 0, 0, 0])], + ['hex', Buffer.from([102, 111, 111, 0, 0, 0, 0, 0, 0])], + ]); + + let buf = Buffer.alloc(9); function reset() { new Uint8Array(buf.buffer).fill(0); } - expect(buf.write("hello", 8, 8)).toBe(5); - reset(); - expect(buf.write("hello!", 3, 8)).toBe(6); - reset(); + // utf8, ucs2, ascii, latin1, utf16le + const encodings = ['utf8', 'utf-8', 'ucs2', 'ucs-2', 'ascii', 'latin1', + 'binary', 'utf16le', 'utf-16le']; - expect(buf.write("Foo Bar!", 4, 4)).toBe(4); - reset(); + encodings + .reduce((es, e) => es.concat(e, e.toUpperCase()), []) + .forEach((encoding) => { + reset(); - expect(buf.write("foo", 0, 1)).toBe(1); - reset(); + const len = Buffer.byteLength('foo', encoding); + expect(buf.write('foo', 0, len, encoding)).toBe(len); - expect(buf.write("foo", 0, 2)).toBe(2); - reset(); + if (encoding.includes('-')) + encoding = encoding.replace('-', ''); - expect(buf.write("foo", 0)).toBe(3); - reset(); + expect(buf).toStrictEqual(resultMap.get(encoding.toLowerCase())); + }); - expect(buf.write("Foo Bar!", 4, 6)).toBe(6); - reset(); + // base64 + ['base64', 'BASE64', 'base64url', 'BASE64URL'].forEach((encoding) => { + reset() - expect(buf.write("Foo Bar!", 4, 7)).toBe(7); - reset(); + const len = Buffer.byteLength('Zm9v', encoding); + + expect(buf.write('Zm9v', 0, len, encoding)).toBe(len); + expect(buf).toStrictEqual(resultMap.get(encoding.toLowerCase())); + }); + + + // hex + ['hex', 'HEX'].forEach((encoding) => { + reset(); + const len = Buffer.byteLength('666f6f', encoding); + + expect(buf.write('666f6f', 0, len, encoding)).toBe(len); + expect(buf).toStrictEqual(resultMap.get(encoding.toLowerCase())); + }); + + + // UCS-2 overflow CVE-2018-12115 + for (let i = 1; i < 4; i++) { + // Allocate two Buffers sequentially off the pool. Run more than once in case + // we hit the end of the pool and don't get sequential allocations + const x = Buffer.allocUnsafe(4).fill(0); + const y = Buffer.allocUnsafe(4).fill(1); + // Should not write anything, pos 3 doesn't have enough room for a 16-bit char + expect(x.write('ыыыыыы', 3, 'ucs2')).toBe(0); + // CVE-2018-12115 experienced via buffer overrun to next block in the pool + expect(Buffer.compare(y, Buffer.alloc(4, 1))).toBe(0); + } + + // // Should not write any data when there is no space for 16-bit chars + const z = Buffer.alloc(4, 0); + expect(z.write('\u0001', 3, 'ucs2')).toBe(0); + expect(Buffer.compare(z, Buffer.alloc(4, 0))).toBe(0); + // Make sure longer strings are written up to the buffer end. + expect(z.write('abcd', 2)).toBe(2); + expect([...z]).toStrictEqual([0, 0, 0x61, 0x62]); + + //Large overrun could corrupt the process with utf8 + expect(Buffer.alloc(4).write('a'.repeat(100), 3, 'utf8')).toBe(1); + + // Large overrun could corrupt the process + expect(Buffer.alloc(4).write('ыыыыыы'.repeat(100), 3, 'utf16le')).toBe(0); + + { + // .write() does not affect the byte after the written-to slice of the Buffer. + // Refs: https://github.com/nodejs/node/issues/26422 + const buf = Buffer.alloc(8); + expect(buf.write('ыы', 1, 'utf16le')).toBe(4); + expect([...buf]).toStrictEqual([0, 0x4b, 0x04, 0x4b, 0x04, 0, 0, 0]); + + } }); it("includes", () => { @@ -679,7 +743,7 @@ it("Buffer.toString(base64)", () => { it("Buffer can be mocked", () => { function MockBuffer() { - const noop = function () {}; + const noop = function () { }; const res = Buffer.alloc(0); for (const op in Buffer.prototype) { if (typeof res[op] === "function") { @@ -766,7 +830,7 @@ it("Buffer.from (Node.js test/test-buffer-from.js)", () => { new MyBadPrimitive(), Symbol(), 5n, - (one, two, three) => {}, + (one, two, three) => { }, undefined, null, ].forEach((input) => { @@ -808,7 +872,7 @@ it("new Buffer() (Node.js test/test-buffer-new.js)", () => { // Now test protecting users from doing stupid things expect(function () { - function AB() {} + function AB() { } Object.setPrototypeOf(AB, ArrayBuffer); Object.setPrototypeOf(AB.prototype, ArrayBuffer.prototype); Buffer.from(new AB()); |