Skip to content

Commit 99722f6

Browse files
authored
fix: improve ArrayBuffer brand check in ensureBuffer (#429)
`instanceof` is notoriously unreliable in JS, because it can be fooled by prototype manipulation and breaks down entirely for cross-realm brand checks. Using `Object.prototype.toString` is generally a better choice for this. This also adds `SharedArrayBuffer` as an alternative, as both should be treated the same under most circumstances.
1 parent f60c404 commit 99722f6

File tree

2 files changed

+35
-2
lines changed

2 files changed

+35
-2
lines changed

src/ensure_buffer.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@ export function ensureBuffer(potentialBuffer: Buffer | ArrayBufferView | ArrayBu
1818
return Buffer.from(potentialBuffer.buffer);
1919
}
2020

21-
if (potentialBuffer instanceof ArrayBuffer) {
21+
if (
22+
['[object ArrayBuffer]', '[object SharedArrayBuffer]'].includes(
23+
Object.prototype.toString.call(potentialBuffer)
24+
)
25+
) {
2226
return Buffer.from(potentialBuffer);
2327
}
2428

test/node/ensure_buffer_test.js

+30-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* global SharedArrayBuffer */
12
'use strict';
23

34
const { Buffer } = require('buffer');
@@ -19,7 +20,7 @@ describe('ensureBuffer tests', function () {
1920
expect(bufferOut).to.equal(bufferIn);
2021
});
2122

22-
it('should wrap a UInt8Array with a buffer', function () {
23+
it('should wrap a Uint8Array with a buffer', function () {
2324
const arrayIn = Uint8Array.from([1, 2, 3]);
2425
let bufferOut;
2526

@@ -31,6 +32,34 @@ describe('ensureBuffer tests', function () {
3132
expect(bufferOut.buffer).to.equal(arrayIn.buffer);
3233
});
3334

35+
it('should wrap a ArrayBuffer with a buffer', function () {
36+
const arrayBufferIn = Uint8Array.from([1, 2, 3]).buffer;
37+
let bufferOut;
38+
39+
expect(function () {
40+
bufferOut = ensureBuffer(arrayBufferIn);
41+
}).to.not.throw(Error);
42+
43+
expect(bufferOut).to.be.an.instanceOf(Buffer);
44+
expect(bufferOut.buffer).to.equal(arrayBufferIn);
45+
});
46+
47+
it('should wrap a SharedArrayBuffer with a buffer', function () {
48+
if (typeof SharedArrayBuffer === 'undefined') {
49+
this.skip();
50+
return;
51+
}
52+
const arrayBufferIn = new SharedArrayBuffer(3);
53+
let bufferOut;
54+
55+
expect(function () {
56+
bufferOut = ensureBuffer(arrayBufferIn);
57+
}).to.not.throw(Error);
58+
59+
expect(bufferOut).to.be.an.instanceOf(Buffer);
60+
expect(bufferOut.buffer).to.equal(arrayBufferIn);
61+
});
62+
3463
[0, 12, -1, '', 'foo', null, undefined, ['list'], {}, /x/].forEach(function (item) {
3564
it(`should throw if input is ${typeof item}: ${item}`, function () {
3665
expect(function () {

0 commit comments

Comments
 (0)